[MPR] Import Wine commit: 93fb279f4f3e150eee329b02ca5fb0251d8a239d
[reactos.git] / dll / win32 / mpr / wnet.c
1 /*
2 * MPR WNet functions
3 *
4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
7 * Copyright 2016 Pierre Schweitzer
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnls.h"
28 #include "winioctl.h"
29 #include "winnetwk.h"
30 #include "npapi.h"
31 #include "winreg.h"
32 #include "winuser.h"
33 #define WINE_MOUNTMGR_EXTENSIONS
34 #include "ddk/mountmgr.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "mprres.h"
38 #include "wnetpriv.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(mpr);
41
42 /* Data structures representing network service providers. Assumes only one
43 * thread creates them, and that they are constant for the life of the process
44 * (and therefore doesn't synchronize access).
45 * FIXME: only basic provider data and enumeration-related data are implemented
46 * so far, need to implement the rest too.
47 */
48 typedef struct _WNetProvider
49 {
50 HMODULE hLib;
51 PWSTR name;
52 PF_NPGetCaps getCaps;
53 DWORD dwSpecVersion;
54 DWORD dwNetType;
55 DWORD dwEnumScopes;
56 PF_NPOpenEnum openEnum;
57 PF_NPEnumResource enumResource;
58 PF_NPCloseEnum closeEnum;
59 PF_NPGetResourceInformation getResourceInformation;
60 PF_NPAddConnection addConnection;
61 PF_NPAddConnection3 addConnection3;
62 PF_NPCancelConnection cancelConnection;
63 #ifdef __REACTOS__
64 PF_NPGetConnection getConnection;
65 #endif
66 } WNetProvider, *PWNetProvider;
67
68 typedef struct _WNetProviderTable
69 {
70 LPWSTR entireNetwork;
71 DWORD numAllocated;
72 DWORD numProviders;
73 WNetProvider table[1];
74 } WNetProviderTable, *PWNetProviderTable;
75
76 #define WNET_ENUMERATOR_TYPE_NULL 0
77 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
78 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
79 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
80 #define WNET_ENUMERATOR_TYPE_CONNECTED 4
81
82 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
83 * the enumeration; it represents one of the following types:
84 * - a 'null' enumeration, one that contains no members
85 * - a global enumeration, one that's executed across all providers
86 * - a provider-specific enumeration, one that's only executed by a single
87 * provider
88 * - a context enumeration. I know this contradicts what I just said about
89 * there being no correspondence between the scope and the type, but it's
90 * necessary for the special case that a "Entire Network" entry needs to
91 * be enumerated in an enumeration of the context scope. Thus an enumeration
92 * of the context scope results in a context type enumerator, which morphs
93 * into a global enumeration (so the enumeration continues across all
94 * providers).
95 */
96 typedef struct _WNetEnumerator
97 {
98 DWORD enumType;
99 DWORD providerIndex;
100 HANDLE handle;
101 BOOL providerDone;
102 DWORD dwScope;
103 DWORD dwType;
104 DWORD dwUsage;
105 union
106 {
107 NETRESOURCEW* net;
108 HANDLE* handles;
109 } specific;
110 } WNetEnumerator, *PWNetEnumerator;
111
112 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
113
114 /* Returns an index (into the global WNetProviderTable) of the provider with
115 * the given name, or BAD_PROVIDER_INDEX if not found.
116 */
117 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
118
119 static PWNetProviderTable providerTable;
120
121 /*
122 * Global provider table functions
123 */
124
125 static void _tryLoadProvider(PCWSTR provider)
126 {
127 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
128 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
129 'S','e','r','v','i','c','e','s','\\',0 };
130 static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
131 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
132 WCHAR serviceName[MAX_PATH];
133 HKEY hKey;
134
135 TRACE("%s\n", debugstr_w(provider));
136 snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt,
137 servicePrefix, provider);
138 serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0';
139 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
140 ERROR_SUCCESS)
141 {
142 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
143 'P','a','t','h',0 };
144 WCHAR providerPath[MAX_PATH];
145 DWORD type, size = sizeof(providerPath);
146
147 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
148 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && (type == REG_SZ || type == REG_EXPAND_SZ))
149 {
150 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
151 PWSTR name = NULL;
152
153 if (type == REG_EXPAND_SZ)
154 {
155 WCHAR path[MAX_PATH];
156 if (ExpandEnvironmentStringsW(providerPath, path, MAX_PATH)) lstrcpyW( providerPath, path );
157 }
158
159 size = 0;
160 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
161 if (size)
162 {
163 name = HeapAlloc(GetProcessHeap(), 0, size);
164 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
165 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
166 {
167 HeapFree(GetProcessHeap(), 0, name);
168 name = NULL;
169 }
170 }
171 if (name)
172 {
173 HMODULE hLib = LoadLibraryW(providerPath);
174
175 if (hLib)
176 {
177 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
178
179 PF_NPGetCaps getCaps = MPR_GETPROC(NPGetCaps);
180
181 TRACE("loaded lib %p\n", hLib);
182 if (getCaps)
183 {
184 DWORD connectCap;
185 PWNetProvider provider =
186 &providerTable->table[providerTable->numProviders];
187
188 provider->hLib = hLib;
189 provider->name = name;
190 TRACE("name is %s\n", debugstr_w(name));
191 provider->getCaps = getCaps;
192 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
193 provider->dwNetType = getCaps(WNNC_NET_TYPE);
194 TRACE("net type is 0x%08x\n", provider->dwNetType);
195 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
196 if (provider->dwEnumScopes)
197 {
198 TRACE("supports enumeration\n");
199 provider->openEnum = MPR_GETPROC(NPOpenEnum);
200 TRACE("NPOpenEnum %p\n", provider->openEnum);
201 provider->enumResource = MPR_GETPROC(NPEnumResource);
202 TRACE("NPEnumResource %p\n", provider->enumResource);
203 provider->closeEnum = MPR_GETPROC(NPCloseEnum);
204 TRACE("NPCloseEnum %p\n", provider->closeEnum);
205 provider->getResourceInformation = MPR_GETPROC(NPGetResourceInformation);
206 TRACE("NPGetResourceInformation %p\n", provider->getResourceInformation);
207 if (!provider->openEnum ||
208 !provider->enumResource ||
209 !provider->closeEnum)
210 {
211 provider->openEnum = NULL;
212 provider->enumResource = NULL;
213 provider->closeEnum = NULL;
214 provider->dwEnumScopes = 0;
215 WARN("Couldn't load enumeration functions\n");
216 }
217 }
218 connectCap = getCaps(WNNC_CONNECTION);
219 if (connectCap & WNNC_CON_ADDCONNECTION)
220 provider->addConnection = MPR_GETPROC(NPAddConnection);
221 if (connectCap & WNNC_CON_ADDCONNECTION3)
222 provider->addConnection3 = MPR_GETPROC(NPAddConnection3);
223 if (connectCap & WNNC_CON_CANCELCONNECTION)
224 provider->cancelConnection = MPR_GETPROC(NPCancelConnection);
225 #ifdef __REACTOS__
226 if (connectCap & WNNC_CON_GETCONNECTIONS)
227 provider->getConnection = MPR_GETPROC(NPGetConnection);
228 #endif
229 TRACE("NPAddConnection %p\n", provider->addConnection);
230 TRACE("NPAddConnection3 %p\n", provider->addConnection3);
231 TRACE("NPCancelConnection %p\n", provider->cancelConnection);
232 providerTable->numProviders++;
233 }
234 else
235 {
236 WARN("Provider %s didn't export NPGetCaps\n",
237 debugstr_w(provider));
238 HeapFree(GetProcessHeap(), 0, name);
239 FreeLibrary(hLib);
240 }
241
242 #undef MPR_GETPROC
243 }
244 else
245 {
246 WARN("Couldn't load library %s for provider %s\n",
247 debugstr_w(providerPath), debugstr_w(provider));
248 HeapFree(GetProcessHeap(), 0, name);
249 }
250 }
251 else
252 {
253 WARN("Couldn't get provider name for provider %s\n",
254 debugstr_w(provider));
255 }
256 }
257 else
258 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
259 RegCloseKey(hKey);
260 }
261 else
262 WARN("Couldn't open service key for provider %s\n",
263 debugstr_w(provider));
264 }
265
266 #ifdef __REACTOS__
267 static void _restoreSavedConnection(HKEY connection, WCHAR * local)
268 {
269 NETRESOURCEW net;
270 DWORD type, prov, index, size;
271
272 net.lpProvider = NULL;
273 net.lpRemoteName = NULL;
274 net.lpLocalName = NULL;
275
276 TRACE("Restoring: %S\n", local);
277
278 size = sizeof(DWORD);
279 if (RegQueryValueExW(connection, L"ConnectionType", NULL, &type, (BYTE *)&net.dwType, &size) != ERROR_SUCCESS)
280 return;
281
282 if (type != REG_DWORD || size != sizeof(DWORD))
283 return;
284
285 if (RegQueryValueExW(connection, L"ProviderName", NULL, &type, NULL, &size) != ERROR_SUCCESS)
286 return;
287
288 if (type != REG_SZ)
289 return;
290
291 net.lpProvider = HeapAlloc(GetProcessHeap(), 0, size);
292 if (!net.lpProvider)
293 return;
294
295 if (RegQueryValueExW(connection, L"ProviderName", NULL, NULL, (BYTE *)net.lpProvider, &size) != ERROR_SUCCESS)
296 goto cleanup;
297
298 size = sizeof(DWORD);
299 if (RegQueryValueExW(connection, L"ProviderType", NULL, &type, (BYTE *)&prov, &size) != ERROR_SUCCESS)
300 goto cleanup;
301
302 if (type != REG_DWORD || size != sizeof(DWORD))
303 goto cleanup;
304
305 index = _findProviderIndexW(net.lpProvider);
306 if (index == BAD_PROVIDER_INDEX)
307 goto cleanup;
308
309 if (providerTable->table[index].dwNetType != prov)
310 goto cleanup;
311
312 if (RegQueryValueExW(connection, L"RemotePath", NULL, &type, NULL, &size) != ERROR_SUCCESS)
313 goto cleanup;
314
315 if (type != REG_SZ)
316 goto cleanup;
317
318 net.lpRemoteName = HeapAlloc(GetProcessHeap(), 0, size);
319 if (!net.lpRemoteName)
320 goto cleanup;
321
322 if (RegQueryValueExW(connection, L"RemotePath", NULL, NULL, (BYTE *)net.lpRemoteName, &size) != ERROR_SUCCESS)
323 goto cleanup;
324
325 size = strlenW(local);
326 net.lpLocalName = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR) + 2 * sizeof(WCHAR));
327 if (!net.lpLocalName)
328 goto cleanup;
329
330 strcpyW(net.lpLocalName, local);
331 net.lpLocalName[size] = ':';
332 net.lpLocalName[size + 1] = 0;
333
334 TRACE("Attempting connection\n");
335
336 WNetAddConnection2W(&net, NULL, NULL, 0);
337
338 cleanup:
339 HeapFree(GetProcessHeap(), 0, net.lpProvider);
340 HeapFree(GetProcessHeap(), 0, net.lpRemoteName);
341 HeapFree(GetProcessHeap(), 0, net.lpLocalName);
342 }
343 #endif
344
345 void wnetInit(HINSTANCE hInstDll)
346 {
347 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
348 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
349 'C','o','n','t','r','o','l','\\',
350 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
351 'O','r','d','e','r',0 };
352 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
353 'O','r','d','e','r',0 };
354 HKEY hKey;
355
356 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
357 == ERROR_SUCCESS)
358 {
359 DWORD size = 0;
360
361 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
362 if (size)
363 {
364 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
365
366 if (providers)
367 {
368 DWORD type;
369
370 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
371 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
372 {
373 PWSTR ptr;
374 DWORD numToAllocate;
375
376 TRACE("provider order is %s\n", debugstr_w(providers));
377 /* first count commas as a heuristic for how many to
378 * allocate space for */
379 for (ptr = providers, numToAllocate = 1; ptr; )
380 {
381 ptr = strchrW(ptr, ',');
382 if (ptr) {
383 numToAllocate++;
384 ptr++;
385 }
386 }
387 providerTable =
388 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
389 sizeof(WNetProviderTable)
390 + (numToAllocate - 1) * sizeof(WNetProvider));
391 if (providerTable)
392 {
393 PWSTR ptrPrev;
394 int entireNetworkLen;
395 LPCWSTR stringresource;
396
397 entireNetworkLen = LoadStringW(hInstDll,
398 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
399 providerTable->entireNetwork = HeapAlloc(
400 GetProcessHeap(), 0, (entireNetworkLen + 1) *
401 sizeof(WCHAR));
402 if (providerTable->entireNetwork)
403 {
404 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
405 providerTable->entireNetwork[entireNetworkLen] = 0;
406 }
407 providerTable->numAllocated = numToAllocate;
408 for (ptr = providers; ptr; )
409 {
410 ptrPrev = ptr;
411 ptr = strchrW(ptr, ',');
412 if (ptr)
413 *ptr++ = '\0';
414 _tryLoadProvider(ptrPrev);
415 }
416 }
417 }
418 HeapFree(GetProcessHeap(), 0, providers);
419 }
420 }
421 RegCloseKey(hKey);
422 }
423
424 #ifdef __REACTOS__
425 if (providerTable)
426 {
427 HKEY user_profile;
428
429 if (RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
430 {
431 HKEY network;
432 WCHAR subkey[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
433
434 if (RegOpenKeyExW(user_profile, subkey, 0, KEY_READ, &network) == ERROR_SUCCESS)
435 {
436 DWORD size, max;
437
438 TRACE("Enumerating remembered connections\n");
439
440 if (RegQueryInfoKey(network, NULL, NULL, NULL, &max, &size, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
441 {
442 WCHAR *local;
443
444 TRACE("There are %lu connections\n", max);
445
446 local = HeapAlloc(GetProcessHeap(), 0, (size + 1) * sizeof(WCHAR));
447 if (local)
448 {
449 DWORD index;
450
451 for (index = 0; index < max; ++index)
452 {
453 DWORD len = size + 1;
454 HKEY connection;
455
456 TRACE("Trying connection %lu\n", index);
457
458 if (RegEnumKeyExW(network, index, local, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
459 continue;
460
461 TRACE("It is %S\n", local);
462
463 if (RegOpenKeyExW(network, local, 0, KEY_READ, &connection) != ERROR_SUCCESS)
464 continue;
465
466 _restoreSavedConnection(connection, local);
467 RegCloseKey(connection);
468 }
469
470 HeapFree(GetProcessHeap(), 0, local);
471 }
472 }
473
474 RegCloseKey(network);
475 }
476
477 RegCloseKey(user_profile);
478 }
479 }
480 #endif
481 }
482
483 void wnetFree(void)
484 {
485 if (providerTable)
486 {
487 DWORD i;
488
489 for (i = 0; i < providerTable->numProviders; i++)
490 {
491 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
492 FreeModule(providerTable->table[i].hLib);
493 }
494 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
495 HeapFree(GetProcessHeap(), 0, providerTable);
496 providerTable = NULL;
497 }
498 }
499
500 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
501 {
502 DWORD ret = BAD_PROVIDER_INDEX;
503
504 if (providerTable && providerTable->numProviders)
505 {
506 DWORD i;
507
508 for (i = 0; i < providerTable->numProviders &&
509 ret == BAD_PROVIDER_INDEX; i++)
510 if (!strcmpW(lpProvider, providerTable->table[i].name))
511 ret = i;
512 }
513 return ret;
514 }
515
516 /*
517 * Browsing Functions
518 */
519
520 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
521 {
522 LPNETRESOURCEW ret;
523
524 if (lpNet)
525 {
526 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
527 if (ret)
528 {
529 size_t len;
530
531 *ret = *lpNet;
532 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
533 if (lpNet->lpRemoteName)
534 {
535 len = strlenW(lpNet->lpRemoteName) + 1;
536 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
537 if (ret->lpRemoteName)
538 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
539 }
540 }
541 }
542 else
543 ret = NULL;
544 return ret;
545 }
546
547 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
548 {
549 if (lpNet)
550 {
551 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
552 HeapFree(GetProcessHeap(), 0, lpNet);
553 }
554 }
555
556 static PWNetEnumerator _createNullEnumerator(void)
557 {
558 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
559 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
560
561 if (ret)
562 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
563 return ret;
564 }
565
566 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
567 DWORD dwUsage, LPNETRESOURCEW lpNet)
568 {
569 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
570 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
571
572 if (ret)
573 {
574 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
575 ret->dwScope = dwScope;
576 ret->dwType = dwType;
577 ret->dwUsage = dwUsage;
578 ret->specific.net = _copyNetResourceForEnumW(lpNet);
579 }
580 return ret;
581 }
582
583 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
584 DWORD dwUsage, DWORD index, HANDLE handle)
585 {
586 PWNetEnumerator ret;
587
588 if (!providerTable || index >= providerTable->numProviders)
589 ret = NULL;
590 else
591 {
592 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
593 if (ret)
594 {
595 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
596 ret->providerIndex = index;
597 ret->dwScope = dwScope;
598 ret->dwType = dwType;
599 ret->dwUsage = dwUsage;
600 ret->handle = handle;
601 }
602 }
603 return ret;
604 }
605
606 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
607 DWORD dwUsage)
608 {
609 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
610 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
611
612 if (ret)
613 {
614 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
615 ret->dwScope = dwScope;
616 ret->dwType = dwType;
617 ret->dwUsage = dwUsage;
618 }
619 return ret;
620 }
621
622 static PWNetEnumerator _createConnectedEnumerator(DWORD dwScope, DWORD dwType,
623 DWORD dwUsage)
624 {
625 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
626 if (ret)
627 {
628 ret->enumType = WNET_ENUMERATOR_TYPE_CONNECTED;
629 ret->dwScope = dwScope;
630 ret->dwType = dwType;
631 ret->dwUsage = dwUsage;
632 ret->specific.handles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HANDLE) * providerTable->numProviders);
633 if (!ret->specific.handles)
634 {
635 HeapFree(GetProcessHeap(), 0, ret);
636 ret = NULL;
637 }
638 }
639 return ret;
640 }
641
642 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
643 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
644 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
645 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
646 * if not all members of the array could be thunked, and something else on
647 * failure.
648 */
649 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
650 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
651 {
652 DWORD i, numToThunk, totalBytes, ret;
653 LPSTR strNext;
654
655 if (!lpNetArrayIn)
656 return WN_BAD_POINTER;
657 if (!lpcCount)
658 return WN_BAD_POINTER;
659 if (*lpcCount == -1)
660 return WN_BAD_VALUE;
661 if (!lpBuffer)
662 return WN_BAD_POINTER;
663 if (!lpBufferSize)
664 return WN_BAD_POINTER;
665
666 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
667 {
668 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
669
670 totalBytes += sizeof(NETRESOURCEA);
671 if (lpNet->lpLocalName)
672 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
673 -1, NULL, 0, NULL, NULL);
674 if (lpNet->lpRemoteName)
675 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
676 -1, NULL, 0, NULL, NULL);
677 if (lpNet->lpComment)
678 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
679 -1, NULL, 0, NULL, NULL);
680 if (lpNet->lpProvider)
681 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
682 -1, NULL, 0, NULL, NULL);
683 if (totalBytes < *lpBufferSize)
684 numToThunk = i + 1;
685 }
686 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
687 for (i = 0; i < numToThunk; i++)
688 {
689 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
690 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
691
692 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
693 /* lie about string lengths, we already verified how many
694 * we have space for above
695 */
696 if (lpNetIn->lpLocalName)
697 {
698 lpNetOut->lpLocalName = strNext;
699 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
700 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
701 }
702 if (lpNetIn->lpRemoteName)
703 {
704 lpNetOut->lpRemoteName = strNext;
705 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
706 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
707 }
708 if (lpNetIn->lpComment)
709 {
710 lpNetOut->lpComment = strNext;
711 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
712 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
713 }
714 if (lpNetIn->lpProvider)
715 {
716 lpNetOut->lpProvider = strNext;
717 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
718 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
719 }
720 }
721 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
722 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
723 *lpcCount, ret);
724 return ret;
725 }
726
727 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
728 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
729 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
730 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
731 * if not all members of the array could be thunked, and something else on
732 * failure.
733 */
734 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
735 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
736 {
737 DWORD i, numToThunk, totalBytes, ret;
738 LPWSTR strNext;
739
740 if (!lpNetArrayIn)
741 return WN_BAD_POINTER;
742 if (!lpcCount)
743 return WN_BAD_POINTER;
744 if (*lpcCount == -1)
745 return WN_BAD_VALUE;
746 if (!lpBuffer)
747 return WN_BAD_POINTER;
748 if (!lpBufferSize)
749 return WN_BAD_POINTER;
750
751 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
752 {
753 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
754
755 totalBytes += sizeof(NETRESOURCEW);
756 if (lpNet->lpLocalName)
757 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
758 -1, NULL, 0) * sizeof(WCHAR);
759 if (lpNet->lpRemoteName)
760 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
761 -1, NULL, 0) * sizeof(WCHAR);
762 if (lpNet->lpComment)
763 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
764 -1, NULL, 0) * sizeof(WCHAR);
765 if (lpNet->lpProvider)
766 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
767 -1, NULL, 0) * sizeof(WCHAR);
768 if (totalBytes < *lpBufferSize)
769 numToThunk = i + 1;
770 }
771 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
772 for (i = 0; i < numToThunk; i++)
773 {
774 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
775 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
776
777 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
778 /* lie about string lengths, we already verified how many
779 * we have space for above
780 */
781 if (lpNetIn->lpLocalName)
782 {
783 lpNetOut->lpLocalName = strNext;
784 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
785 -1, lpNetOut->lpLocalName, *lpBufferSize);
786 }
787 if (lpNetIn->lpRemoteName)
788 {
789 lpNetOut->lpRemoteName = strNext;
790 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
791 -1, lpNetOut->lpRemoteName, *lpBufferSize);
792 }
793 if (lpNetIn->lpComment)
794 {
795 lpNetOut->lpComment = strNext;
796 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
797 -1, lpNetOut->lpComment, *lpBufferSize);
798 }
799 if (lpNetIn->lpProvider)
800 {
801 lpNetOut->lpProvider = strNext;
802 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
803 -1, lpNetOut->lpProvider, *lpBufferSize);
804 }
805 }
806 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
807 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
808 *lpcCount, ret);
809 return ret;
810 }
811
812 /*********************************************************************
813 * WNetOpenEnumA [MPR.@]
814 *
815 * See comments for WNetOpenEnumW.
816 */
817 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
818 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
819 {
820 DWORD ret;
821
822 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
823 dwScope, dwType, dwUsage, lpNet, lphEnum );
824
825 if (!lphEnum)
826 ret = WN_BAD_POINTER;
827 else if (!providerTable || providerTable->numProviders == 0)
828 {
829 *lphEnum = NULL;
830 ret = WN_NO_NETWORK;
831 }
832 else
833 {
834 if (lpNet)
835 {
836 LPNETRESOURCEW lpNetWide = NULL;
837 BYTE buf[1024];
838 DWORD size = sizeof(buf), count = 1;
839 BOOL allocated = FALSE;
840
841 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
842 if (ret == WN_MORE_DATA)
843 {
844 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
845 size);
846 if (lpNetWide)
847 {
848 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
849 &size);
850 allocated = TRUE;
851 }
852 else
853 ret = WN_OUT_OF_MEMORY;
854 }
855 else if (ret == WN_SUCCESS)
856 lpNetWide = (LPNETRESOURCEW)buf;
857 if (ret == WN_SUCCESS)
858 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
859 lphEnum);
860 if (allocated)
861 HeapFree(GetProcessHeap(), 0, lpNetWide);
862 }
863 else
864 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
865 }
866 if (ret)
867 SetLastError(ret);
868 TRACE("Returning %d\n", ret);
869 return ret;
870 }
871
872 /*********************************************************************
873 * WNetOpenEnumW [MPR.@]
874 *
875 * Network enumeration has way too many parameters, so I'm not positive I got
876 * them right. What I've got so far:
877 *
878 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
879 * all the network providers should be enumerated.
880 *
881 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
882 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
883 * lpProvider is set, all the network providers should be enumerated.
884 * (This means the enumeration is a list of network providers, not that the
885 * enumeration is passed on to the providers.)
886 *
887 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
888 * resource matches the "Entire Network" resource (no remote name, no
889 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
890 * enumeration is done on every network provider.
891 *
892 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
893 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
894 * only to the given network provider.
895 *
896 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
897 * no lpProvider is set, enumeration will be tried on every network provider,
898 * in the order in which they're loaded.
899 *
900 * - The LPNETRESOURCE should be disregarded for scopes besides
901 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
902 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
903 *
904 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
905 * resource in the enumerated list, as well as any machines in your
906 * workgroup. The machines in your workgroup come from doing a
907 * RESOURCE_CONTEXT enumeration of every Network Provider.
908 */
909 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
910 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
911 {
912 DWORD ret;
913
914 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
915 dwScope, dwType, dwUsage, lpNet, lphEnum );
916
917 if (!lphEnum)
918 ret = WN_BAD_POINTER;
919 else if (!providerTable || providerTable->numProviders == 0)
920 {
921 *lphEnum = NULL;
922 ret = WN_NO_NETWORK;
923 }
924 else
925 {
926 switch (dwScope)
927 {
928 case RESOURCE_GLOBALNET:
929 if (lpNet)
930 {
931 if (lpNet->lpProvider)
932 {
933 DWORD index = _findProviderIndexW(lpNet->lpProvider);
934
935 if (index != BAD_PROVIDER_INDEX)
936 {
937 if (providerTable->table[index].openEnum &&
938 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
939 {
940 HANDLE handle;
941 PWSTR RemoteName = lpNet->lpRemoteName;
942
943 if ((lpNet->dwUsage & RESOURCEUSAGE_CONTAINER) &&
944 RemoteName && !strcmpW(RemoteName, lpNet->lpProvider))
945 lpNet->lpRemoteName = NULL;
946
947 ret = providerTable->table[index].openEnum(
948 dwScope, dwType, dwUsage, lpNet, &handle);
949 if (ret == WN_SUCCESS)
950 {
951 *lphEnum = _createProviderEnumerator(
952 dwScope, dwType, dwUsage, index, handle);
953 ret = *lphEnum ? WN_SUCCESS :
954 WN_OUT_OF_MEMORY;
955 }
956
957 lpNet->lpRemoteName = RemoteName;
958 }
959 else
960 ret = WN_NOT_SUPPORTED;
961 }
962 else
963 ret = WN_BAD_PROVIDER;
964 }
965 else if (lpNet->lpRemoteName)
966 {
967 *lphEnum = _createGlobalEnumeratorW(dwScope,
968 dwType, dwUsage, lpNet);
969 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
970 }
971 else
972 {
973 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
974 providerTable->entireNetwork))
975 {
976 /* comment matches the "Entire Network", enumerate
977 * global scope of every provider
978 */
979 *lphEnum = _createGlobalEnumeratorW(dwScope,
980 dwType, dwUsage, lpNet);
981 }
982 else
983 {
984 /* this is the same as not having passed lpNet */
985 *lphEnum = _createGlobalEnumeratorW(dwScope,
986 dwType, dwUsage, NULL);
987 }
988 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
989 }
990 }
991 else
992 {
993 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
994 dwUsage, lpNet);
995 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
996 }
997 break;
998 case RESOURCE_CONTEXT:
999 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
1000 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
1001 break;
1002 case RESOURCE_CONNECTED:
1003 *lphEnum = _createConnectedEnumerator(dwScope, dwType, dwUsage);
1004 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
1005 break;
1006 case RESOURCE_REMEMBERED:
1007 *lphEnum = _createNullEnumerator();
1008 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
1009 break;
1010 default:
1011 WARN("unknown scope 0x%08x\n", dwScope);
1012 ret = WN_BAD_VALUE;
1013 }
1014 }
1015 if (ret)
1016 SetLastError(ret);
1017 TRACE("Returning %d\n", ret);
1018 return ret;
1019 }
1020
1021 /*********************************************************************
1022 * WNetEnumResourceA [MPR.@]
1023 */
1024 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
1025 LPVOID lpBuffer, LPDWORD lpBufferSize )
1026 {
1027 DWORD ret;
1028
1029 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1030
1031 if (!hEnum)
1032 ret = WN_BAD_POINTER;
1033 else if (!lpcCount)
1034 ret = WN_BAD_POINTER;
1035 else if (!lpBuffer)
1036 ret = WN_BAD_POINTER;
1037 else if (!lpBufferSize)
1038 ret = WN_BAD_POINTER;
1039 else if (*lpBufferSize < sizeof(NETRESOURCEA))
1040 {
1041 *lpBufferSize = sizeof(NETRESOURCEA);
1042 ret = WN_MORE_DATA;
1043 }
1044 else
1045 {
1046 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
1047 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
1048
1049 if (localBuffer)
1050 {
1051 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
1052 &localSize);
1053 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
1054 {
1055 /* FIXME: this isn't necessarily going to work in the case of
1056 * WN_MORE_DATA, because our enumerator may have moved on to
1057 * the next provider. MSDN states that a large (16KB) buffer
1058 * size is the appropriate usage of this function, so
1059 * hopefully it won't be an issue.
1060 */
1061 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
1062 lpBuffer, lpBufferSize);
1063 *lpcCount = localCount;
1064 }
1065 HeapFree(GetProcessHeap(), 0, localBuffer);
1066 }
1067 else
1068 ret = WN_OUT_OF_MEMORY;
1069 }
1070 if (ret)
1071 SetLastError(ret);
1072 TRACE("Returning %d\n", ret);
1073 return ret;
1074 }
1075
1076 static DWORD _countProviderBytesW(PWNetProvider provider)
1077 {
1078 DWORD ret;
1079
1080 if (provider)
1081 {
1082 ret = sizeof(NETRESOURCEW);
1083 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
1084 }
1085 else
1086 ret = 0;
1087 return ret;
1088 }
1089
1090 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1091 LPVOID lpBuffer, const DWORD *lpBufferSize)
1092 {
1093 DWORD ret;
1094
1095 if (!enumerator)
1096 return WN_BAD_POINTER;
1097 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1098 return WN_BAD_VALUE;
1099 if (!lpcCount)
1100 return WN_BAD_POINTER;
1101 if (!lpBuffer)
1102 return WN_BAD_POINTER;
1103 if (!lpBufferSize)
1104 return WN_BAD_POINTER;
1105 if (*lpBufferSize < sizeof(NETRESOURCEA))
1106 return WN_MORE_DATA;
1107
1108 if (!providerTable || enumerator->providerIndex >=
1109 providerTable->numProviders)
1110 ret = WN_NO_MORE_ENTRIES;
1111 else
1112 {
1113 DWORD bytes = 0, count = 0, countLimit, i;
1114 LPNETRESOURCEW resource;
1115 LPWSTR strNext;
1116
1117 countLimit = *lpcCount == -1 ?
1118 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
1119 while (count < countLimit && bytes < *lpBufferSize)
1120 {
1121 DWORD bytesNext = _countProviderBytesW(
1122 &providerTable->table[count + enumerator->providerIndex]);
1123
1124 if (bytes + bytesNext < *lpBufferSize)
1125 {
1126 bytes += bytesNext;
1127 count++;
1128 }
1129 }
1130 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
1131 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
1132 {
1133 resource->dwScope = RESOURCE_GLOBALNET;
1134 resource->dwType = RESOURCETYPE_ANY;
1135 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
1136 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
1137 RESOURCEUSAGE_RESERVED;
1138 resource->lpLocalName = NULL;
1139 resource->lpRemoteName = strNext;
1140 strcpyW(resource->lpRemoteName,
1141 providerTable->table[i + enumerator->providerIndex].name);
1142 strNext += strlenW(resource->lpRemoteName) + 1;
1143 resource->lpComment = NULL;
1144 resource->lpProvider = strNext;
1145 strcpyW(resource->lpProvider,
1146 providerTable->table[i + enumerator->providerIndex].name);
1147 strNext += strlenW(resource->lpProvider) + 1;
1148 }
1149 enumerator->providerIndex += count;
1150 *lpcCount = count;
1151 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
1152 }
1153 TRACE("Returning %d\n", ret);
1154 return ret;
1155 }
1156
1157 /* Advances the enumerator (assumed to be a global enumerator) to the next
1158 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1159 * not open a handle with the next provider.
1160 * If the existing handle is NULL, may leave the enumerator unchanged, since
1161 * the current provider may support the desired scope.
1162 * If the existing handle is not NULL, closes it before moving on.
1163 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1164 * provider, and another error on failure.
1165 */
1166 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
1167 {
1168 if (!enumerator)
1169 return WN_BAD_POINTER;
1170 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1171 return WN_BAD_VALUE;
1172 if (!providerTable || enumerator->providerIndex >=
1173 providerTable->numProviders)
1174 return WN_NO_MORE_ENTRIES;
1175
1176 if (enumerator->providerDone)
1177 {
1178 DWORD dwEnum = 0;
1179 enumerator->providerDone = FALSE;
1180 if (enumerator->handle)
1181 {
1182 providerTable->table[enumerator->providerIndex].closeEnum(
1183 enumerator->handle);
1184 enumerator->handle = NULL;
1185 enumerator->providerIndex++;
1186 }
1187 if (enumerator->dwScope == RESOURCE_CONNECTED)
1188 dwEnum = WNNC_ENUM_LOCAL;
1189 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
1190 dwEnum = WNNC_ENUM_GLOBAL;
1191 else if (enumerator->dwScope == RESOURCE_CONTEXT)
1192 dwEnum = WNNC_ENUM_CONTEXT;
1193 for (; enumerator->providerIndex < providerTable->numProviders &&
1194 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
1195 & dwEnum); enumerator->providerIndex++)
1196 ;
1197 }
1198 return enumerator->providerIndex < providerTable->numProviders ?
1199 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1200 }
1201
1202 /* "Passes through" call to the next provider that supports the enumeration
1203 * type.
1204 * FIXME: if one call to a provider's enumerator succeeds while there's still
1205 * space in lpBuffer, I don't call to the next provider. The caller may not
1206 * expect that it should call EnumResourceW again with a return value of
1207 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1208 * may have to be moved around a bit, ick.
1209 */
1210 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1211 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1212 {
1213 DWORD ret;
1214
1215 if (!enumerator)
1216 return WN_BAD_POINTER;
1217 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1218 return WN_BAD_VALUE;
1219 if (!lpcCount)
1220 return WN_BAD_POINTER;
1221 if (!lpBuffer)
1222 return WN_BAD_POINTER;
1223 if (!lpBufferSize)
1224 return WN_BAD_POINTER;
1225 if (*lpBufferSize < sizeof(NETRESOURCEW))
1226 return WN_MORE_DATA;
1227
1228 ret = _globalEnumeratorAdvance(enumerator);
1229 if (ret == WN_SUCCESS)
1230 {
1231 ret = providerTable->table[enumerator->providerIndex].
1232 openEnum(enumerator->dwScope, enumerator->dwType,
1233 enumerator->dwUsage, enumerator->specific.net,
1234 &enumerator->handle);
1235 if (ret == WN_SUCCESS)
1236 {
1237 ret = providerTable->table[enumerator->providerIndex].
1238 enumResource(enumerator->handle, lpcCount, lpBuffer,
1239 lpBufferSize);
1240 if (ret != WN_MORE_DATA)
1241 enumerator->providerDone = TRUE;
1242 }
1243 }
1244 TRACE("Returning %d\n", ret);
1245 return ret;
1246 }
1247
1248 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1249 LPVOID lpBuffer, LPDWORD lpBufferSize)
1250 {
1251 DWORD ret;
1252
1253 if (!enumerator)
1254 return WN_BAD_POINTER;
1255 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1256 return WN_BAD_VALUE;
1257 if (!lpcCount)
1258 return WN_BAD_POINTER;
1259 if (!lpBuffer)
1260 return WN_BAD_POINTER;
1261 if (!lpBufferSize)
1262 return WN_BAD_POINTER;
1263 if (*lpBufferSize < sizeof(NETRESOURCEW))
1264 return WN_MORE_DATA;
1265 if (!providerTable)
1266 return WN_NO_NETWORK;
1267
1268 switch (enumerator->dwScope)
1269 {
1270 case RESOURCE_GLOBALNET:
1271 if (enumerator->specific.net)
1272 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1273 lpBuffer, lpBufferSize);
1274 else
1275 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1276 lpBufferSize);
1277 break;
1278 case RESOURCE_CONTEXT:
1279 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1280 lpBufferSize);
1281 break;
1282 default:
1283 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1284 ret = WN_NO_MORE_ENTRIES;
1285 }
1286 TRACE("Returning %d\n", ret);
1287 return ret;
1288 }
1289
1290 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1291 LPVOID lpBuffer, LPDWORD lpBufferSize)
1292 {
1293 if (!enumerator)
1294 return WN_BAD_POINTER;
1295 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1296 return WN_BAD_VALUE;
1297 if (!enumerator->handle)
1298 return WN_BAD_VALUE;
1299 if (!lpcCount)
1300 return WN_BAD_POINTER;
1301 if (!lpBuffer)
1302 return WN_BAD_POINTER;
1303 if (!lpBufferSize)
1304 return WN_BAD_POINTER;
1305 if (!providerTable)
1306 return WN_NO_NETWORK;
1307 if (enumerator->providerIndex >= providerTable->numProviders)
1308 return WN_NO_MORE_ENTRIES;
1309 if (!providerTable->table[enumerator->providerIndex].enumResource)
1310 return WN_BAD_VALUE;
1311 return providerTable->table[enumerator->providerIndex].enumResource(
1312 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1313 }
1314
1315 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1316 LPVOID lpBuffer, LPDWORD lpBufferSize)
1317 {
1318 DWORD ret;
1319 size_t cchEntireNetworkLen, bytesNeeded;
1320
1321 if (!enumerator)
1322 return WN_BAD_POINTER;
1323 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1324 return WN_BAD_VALUE;
1325 if (!lpcCount)
1326 return WN_BAD_POINTER;
1327 if (!lpBuffer)
1328 return WN_BAD_POINTER;
1329 if (!lpBufferSize)
1330 return WN_BAD_POINTER;
1331 if (!providerTable)
1332 return WN_NO_NETWORK;
1333
1334 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1335 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1336 if (*lpBufferSize < bytesNeeded)
1337 {
1338 *lpBufferSize = bytesNeeded;
1339 ret = WN_MORE_DATA;
1340 }
1341 else
1342 {
1343 LPNETRESOURCEW lpNet = lpBuffer;
1344
1345 lpNet->dwScope = RESOURCE_GLOBALNET;
1346 lpNet->dwType = enumerator->dwType;
1347 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1348 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1349 lpNet->lpLocalName = NULL;
1350 lpNet->lpRemoteName = NULL;
1351 lpNet->lpProvider = NULL;
1352 /* odd, but correct: put comment at end of buffer, so it won't get
1353 * overwritten by subsequent calls to a provider's enumResource
1354 */
1355 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1356 (cchEntireNetworkLen * sizeof(WCHAR)));
1357 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1358 ret = WN_SUCCESS;
1359 }
1360 if (ret == WN_SUCCESS)
1361 {
1362 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1363
1364 /* "Entire Network" entry enumerated--morph this into a global
1365 * enumerator. enumerator->lpNet continues to be NULL, since it has
1366 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1367 */
1368 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1369 ret = _enumerateGlobalW(enumerator, lpcCount,
1370 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1371 if (ret == WN_SUCCESS)
1372 {
1373 /* reflect the fact that we already enumerated "Entire Network" */
1374 (*lpcCount)++;
1375 *lpBufferSize = bufferSize + bytesNeeded;
1376 }
1377 else
1378 {
1379 /* the provider enumeration failed, but we already succeeded in
1380 * enumerating "Entire Network"--leave type as global to allow a
1381 * retry, but indicate success with a count of one.
1382 */
1383 ret = WN_SUCCESS;
1384 *lpcCount = 1;
1385 *lpBufferSize = bytesNeeded;
1386 }
1387 }
1388 TRACE("Returning %d\n", ret);
1389 return ret;
1390 }
1391
1392 static DWORD _copyStringToEnumW(const WCHAR *source, DWORD* left, void** end)
1393 {
1394 DWORD len;
1395 WCHAR* local = *end;
1396
1397 len = strlenW(source) + 1;
1398 len *= sizeof(WCHAR);
1399 if (*left < len)
1400 return WN_MORE_DATA;
1401
1402 local -= (len / sizeof(WCHAR));
1403 memcpy(local, source, len);
1404 *left -= len;
1405 *end = local;
1406
1407 return WN_SUCCESS;
1408 }
1409
1410 static DWORD _enumerateConnectedW(PWNetEnumerator enumerator, DWORD* user_count,
1411 void* user_buffer, DWORD* user_size)
1412 {
1413 DWORD ret, index, count, total_count, size, i, left;
1414 void* end;
1415 NETRESOURCEW* curr, * buffer;
1416 HANDLE* handles;
1417
1418 if (!enumerator)
1419 return WN_BAD_POINTER;
1420 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONNECTED)
1421 return WN_BAD_VALUE;
1422 if (!user_count || !user_buffer || !user_size)
1423 return WN_BAD_POINTER;
1424 if (!providerTable)
1425 return WN_NO_NETWORK;
1426
1427 handles = enumerator->specific.handles;
1428 left = *user_size;
1429 size = *user_size;
1430 buffer = HeapAlloc(GetProcessHeap(), 0, *user_size);
1431 if (!buffer)
1432 return WN_NO_NETWORK;
1433
1434 curr = user_buffer;
1435 end = (char *)user_buffer + size;
1436 count = *user_count;
1437 total_count = 0;
1438
1439 ret = WN_NO_MORE_ENTRIES;
1440 for (index = 0; index < providerTable->numProviders; index++)
1441 {
1442 if (providerTable->table[index].dwEnumScopes)
1443 {
1444 if (handles[index] == 0)
1445 {
1446 ret = providerTable->table[index].openEnum(enumerator->dwScope,
1447 enumerator->dwType,
1448 enumerator->dwUsage,
1449 NULL, &handles[index]);
1450 if (ret != WN_SUCCESS)
1451 continue;
1452 }
1453
1454 ret = providerTable->table[index].enumResource(handles[index],
1455 &count, buffer,
1456 &size);
1457 total_count += count;
1458 if (ret == WN_MORE_DATA)
1459 break;
1460
1461 if (ret == WN_SUCCESS)
1462 {
1463 for (i = 0; i < count; ++i)
1464 {
1465 if (left < sizeof(NETRESOURCEW))
1466 {
1467 ret = WN_MORE_DATA;
1468 break;
1469 }
1470
1471 memcpy(curr, &buffer[i], sizeof(NETRESOURCEW));
1472 left -= sizeof(NETRESOURCEW);
1473
1474 ret = _copyStringToEnumW(buffer[i].lpLocalName, &left, &end);
1475 if (ret == WN_MORE_DATA)
1476 break;
1477 curr->lpLocalName = end;
1478
1479 ret = _copyStringToEnumW(buffer[i].lpRemoteName, &left, &end);
1480 if (ret == WN_MORE_DATA)
1481 break;
1482 curr->lpRemoteName = end;
1483
1484 ret = _copyStringToEnumW(buffer[i].lpProvider, &left, &end);
1485 if (ret == WN_MORE_DATA)
1486 break;
1487 curr->lpProvider = end;
1488
1489 ++curr;
1490 }
1491
1492 size = left;
1493 }
1494
1495 if (*user_count != -1)
1496 count = *user_count - total_count;
1497 else
1498 count = *user_count;
1499 }
1500 }
1501
1502 if (total_count == 0)
1503 ret = WN_NO_MORE_ENTRIES;
1504
1505 *user_count = total_count;
1506 if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
1507 ret = WN_SUCCESS;
1508
1509 HeapFree(GetProcessHeap(), 0, buffer);
1510
1511 TRACE("Returning %d\n", ret);
1512 return ret;
1513 }
1514
1515 /*********************************************************************
1516 * WNetEnumResourceW [MPR.@]
1517 */
1518 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1519 LPVOID lpBuffer, LPDWORD lpBufferSize )
1520 {
1521 DWORD ret;
1522
1523 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1524
1525 if (!hEnum)
1526 ret = WN_BAD_POINTER;
1527 else if (!lpcCount)
1528 ret = WN_BAD_POINTER;
1529 else if (!lpBuffer)
1530 ret = WN_BAD_POINTER;
1531 else if (!lpBufferSize)
1532 ret = WN_BAD_POINTER;
1533 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1534 {
1535 *lpBufferSize = sizeof(NETRESOURCEW);
1536 ret = WN_MORE_DATA;
1537 }
1538 else
1539 {
1540 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1541
1542 switch (enumerator->enumType)
1543 {
1544 case WNET_ENUMERATOR_TYPE_NULL:
1545 ret = WN_NO_MORE_ENTRIES;
1546 break;
1547 case WNET_ENUMERATOR_TYPE_GLOBAL:
1548 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1549 lpBufferSize);
1550 break;
1551 case WNET_ENUMERATOR_TYPE_PROVIDER:
1552 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1553 lpBufferSize);
1554 break;
1555 case WNET_ENUMERATOR_TYPE_CONTEXT:
1556 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1557 lpBufferSize);
1558 break;
1559 case WNET_ENUMERATOR_TYPE_CONNECTED:
1560 ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer,
1561 lpBufferSize);
1562 break;
1563 default:
1564 WARN("bogus enumerator type!\n");
1565 ret = WN_NO_NETWORK;
1566 }
1567 }
1568 if (ret)
1569 SetLastError(ret);
1570 TRACE("Returning %d\n", ret);
1571 return ret;
1572 }
1573
1574 /*********************************************************************
1575 * WNetCloseEnum [MPR.@]
1576 */
1577 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1578 {
1579 DWORD ret, index;
1580 HANDLE *handles;
1581
1582 TRACE( "(%p)\n", hEnum );
1583
1584 if (hEnum)
1585 {
1586 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1587
1588 switch (enumerator->enumType)
1589 {
1590 case WNET_ENUMERATOR_TYPE_NULL:
1591 ret = WN_SUCCESS;
1592 break;
1593 case WNET_ENUMERATOR_TYPE_GLOBAL:
1594 if (enumerator->specific.net)
1595 _freeEnumNetResource(enumerator->specific.net);
1596 if (enumerator->handle)
1597 providerTable->table[enumerator->providerIndex].
1598 closeEnum(enumerator->handle);
1599 ret = WN_SUCCESS;
1600 break;
1601 case WNET_ENUMERATOR_TYPE_PROVIDER:
1602 if (enumerator->handle)
1603 providerTable->table[enumerator->providerIndex].
1604 closeEnum(enumerator->handle);
1605 ret = WN_SUCCESS;
1606 break;
1607 case WNET_ENUMERATOR_TYPE_CONNECTED:
1608 handles = enumerator->specific.handles;
1609 for (index = 0; index < providerTable->numProviders; index++)
1610 {
1611 if (providerTable->table[index].dwEnumScopes && handles[index])
1612 providerTable->table[index].closeEnum(handles[index]);
1613 }
1614 HeapFree(GetProcessHeap(), 0, handles);
1615 ret = WN_SUCCESS;
1616 break;
1617 default:
1618 WARN("bogus enumerator type!\n");
1619 ret = WN_BAD_HANDLE;
1620 }
1621 HeapFree(GetProcessHeap(), 0, hEnum);
1622 }
1623 else
1624 ret = WN_BAD_HANDLE;
1625 if (ret)
1626 SetLastError(ret);
1627 TRACE("Returning %d\n", ret);
1628 return ret;
1629 }
1630
1631 /*********************************************************************
1632 * WNetGetResourceInformationA [MPR.@]
1633 *
1634 * See WNetGetResourceInformationW
1635 */
1636 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1637 LPVOID lpBuffer, LPDWORD cbBuffer,
1638 LPSTR *lplpSystem )
1639 {
1640 DWORD ret;
1641
1642 TRACE( "(%p, %p, %p, %p)\n",
1643 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1644
1645 if (!providerTable || providerTable->numProviders == 0)
1646 ret = WN_NO_NETWORK;
1647 else if (lpNetResource)
1648 {
1649 LPNETRESOURCEW lpNetResourceW = NULL;
1650 DWORD size = 1024, count = 1;
1651 DWORD len;
1652
1653 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1654 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1655 if (ret == WN_MORE_DATA)
1656 {
1657 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1658 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1659 if (lpNetResourceW)
1660 ret = _thunkNetResourceArrayAToW(lpNetResource,
1661 &count, lpNetResourceW, &size);
1662 else
1663 ret = WN_OUT_OF_MEMORY;
1664 }
1665 if (ret == WN_SUCCESS)
1666 {
1667 LPWSTR lpSystemW = NULL;
1668 LPVOID lpBufferW;
1669 size = 1024;
1670 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1671 if (lpBufferW)
1672 {
1673 ret = WNetGetResourceInformationW(lpNetResourceW,
1674 lpBufferW, &size, &lpSystemW);
1675 if (ret == WN_MORE_DATA)
1676 {
1677 HeapFree(GetProcessHeap(), 0, lpBufferW);
1678 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1679 if (lpBufferW)
1680 ret = WNetGetResourceInformationW(lpNetResourceW,
1681 lpBufferW, &size, &lpSystemW);
1682 else
1683 ret = WN_OUT_OF_MEMORY;
1684 }
1685 if (ret == WN_SUCCESS)
1686 {
1687 ret = _thunkNetResourceArrayWToA(lpBufferW,
1688 &count, lpBuffer, cbBuffer);
1689 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1690 lpNetResourceW = lpBufferW;
1691 size = sizeof(NETRESOURCEA);
1692 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1693 -1, NULL, 0, NULL, NULL);
1694 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1695 -1, NULL, 0, NULL, NULL);
1696
1697 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1698 -1, NULL, 0, NULL, NULL);
1699 if ((len) && ( size + len < *cbBuffer))
1700 {
1701 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1702 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1703 *lplpSystem, len, NULL, NULL);
1704 ret = WN_SUCCESS;
1705 }
1706 else
1707 ret = WN_MORE_DATA;
1708 }
1709 else
1710 ret = WN_OUT_OF_MEMORY;
1711 HeapFree(GetProcessHeap(), 0, lpBufferW);
1712 }
1713 else
1714 ret = WN_OUT_OF_MEMORY;
1715 HeapFree(GetProcessHeap(), 0, lpSystemW);
1716 }
1717 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1718 }
1719 else
1720 ret = WN_NO_NETWORK;
1721
1722 if (ret)
1723 SetLastError(ret);
1724 TRACE("Returning %d\n", ret);
1725 return ret;
1726 }
1727
1728 /*********************************************************************
1729 * WNetGetResourceInformationW [MPR.@]
1730 *
1731 * WNetGetResourceInformationW function identifies the network provider
1732 * that owns the resource and gets information about the type of the resource.
1733 *
1734 * PARAMS:
1735 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1736 * defines a network resource.
1737 * lpBuffer [ O] the pointer to buffer, containing result. It
1738 * contains NETRESOURCEW structure and strings to
1739 * which the members of the NETRESOURCEW structure
1740 * point.
1741 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1742 * in bytes.
1743 * lplpSystem [ O] the pointer to string in the output buffer,
1744 * containing the part of the resource name without
1745 * names of the server and share.
1746 *
1747 * RETURNS:
1748 * NO_ERROR if the function succeeds. System error code if the function fails.
1749 */
1750
1751 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1752 LPVOID lpBuffer, LPDWORD cbBuffer,
1753 LPWSTR *lplpSystem )
1754 {
1755 DWORD ret = WN_NO_NETWORK;
1756 DWORD index;
1757
1758 TRACE( "(%p, %p, %p, %p)\n",
1759 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1760
1761 if (!(lpBuffer))
1762 ret = WN_OUT_OF_MEMORY;
1763 else if (providerTable != NULL)
1764 {
1765 /* FIXME: For function value of a variable is indifferent, it does
1766 * search of all providers in a network.
1767 */
1768 for (index = 0; index < providerTable->numProviders; index++)
1769 {
1770 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1771 WNNC_DLG_GETRESOURCEINFORMATION)
1772 {
1773 if (providerTable->table[index].getResourceInformation)
1774 ret = providerTable->table[index].getResourceInformation(
1775 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1776 else
1777 ret = WN_NO_NETWORK;
1778 if (ret == WN_SUCCESS)
1779 break;
1780 }
1781 }
1782 }
1783 if (ret)
1784 SetLastError(ret);
1785 return ret;
1786 }
1787
1788 /*********************************************************************
1789 * WNetGetResourceParentA [MPR.@]
1790 */
1791 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1792 LPVOID lpBuffer, LPDWORD lpBufferSize )
1793 {
1794 FIXME( "(%p, %p, %p): stub\n",
1795 lpNetResource, lpBuffer, lpBufferSize );
1796
1797 SetLastError(WN_NO_NETWORK);
1798 return WN_NO_NETWORK;
1799 }
1800
1801 /*********************************************************************
1802 * WNetGetResourceParentW [MPR.@]
1803 */
1804 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1805 LPVOID lpBuffer, LPDWORD lpBufferSize )
1806 {
1807 FIXME( "(%p, %p, %p): stub\n",
1808 lpNetResource, lpBuffer, lpBufferSize );
1809
1810 SetLastError(WN_NO_NETWORK);
1811 return WN_NO_NETWORK;
1812 }
1813
1814
1815
1816 /*
1817 * Connection Functions
1818 */
1819
1820 /*********************************************************************
1821 * WNetAddConnectionA [MPR.@]
1822 */
1823 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1824 LPCSTR lpLocalName )
1825 {
1826 NETRESOURCEA resourcesA;
1827
1828 memset(&resourcesA, 0, sizeof(resourcesA));
1829 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1830 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1831 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1832 }
1833
1834 /*********************************************************************
1835 * WNetAddConnectionW [MPR.@]
1836 */
1837 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1838 LPCWSTR lpLocalName )
1839 {
1840 NETRESOURCEW resourcesW;
1841
1842 memset(&resourcesW, 0, sizeof(resourcesW));
1843 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1844 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1845 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1846 }
1847
1848 /*********************************************************************
1849 * WNetAddConnection2A [MPR.@]
1850 */
1851 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1852 LPCSTR lpPassword, LPCSTR lpUserID,
1853 DWORD dwFlags )
1854 {
1855 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1856 NULL, 0, NULL);
1857 }
1858
1859 /*********************************************************************
1860 * WNetAddConnection2W [MPR.@]
1861 */
1862 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1863 LPCWSTR lpPassword, LPCWSTR lpUserID,
1864 DWORD dwFlags )
1865 {
1866 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1867 NULL, 0, NULL);
1868 }
1869
1870 /*********************************************************************
1871 * WNetAddConnection3A [MPR.@]
1872 */
1873 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1874 LPCSTR lpPassword, LPCSTR lpUserID,
1875 DWORD dwFlags )
1876 {
1877 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1878 dwFlags, NULL, 0, NULL);
1879 }
1880
1881 /*********************************************************************
1882 * WNetAddConnection3W [MPR.@]
1883 */
1884 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1885 LPCWSTR lpPassword, LPCWSTR lpUserID,
1886 DWORD dwFlags )
1887 {
1888 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1889 dwFlags, NULL, 0, NULL);
1890 }
1891
1892 struct use_connection_context
1893 {
1894 HWND hwndOwner;
1895 NETRESOURCEW *resource;
1896 NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */
1897 WCHAR *password;
1898 WCHAR *userid;
1899 DWORD flags;
1900 void *accessname;
1901 DWORD *buffer_size;
1902 DWORD *result;
1903 DWORD (*pre_set_accessname)(struct use_connection_context*, WCHAR *);
1904 void (*set_accessname)(struct use_connection_context*, WCHAR *);
1905 };
1906
1907 static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1908 {
1909 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1910 {
1911 DWORD len;
1912
1913 if (local_name)
1914 len = strlenW(local_name);
1915 else
1916 len = strlenW(ctxt->resource->lpRemoteName);
1917
1918 if (++len > *ctxt->buffer_size)
1919 {
1920 *ctxt->buffer_size = len;
1921 return ERROR_MORE_DATA;
1922 }
1923 }
1924 else
1925 ctxt->accessname = NULL;
1926
1927 return ERROR_SUCCESS;
1928 }
1929
1930 static void use_connection_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1931 {
1932 WCHAR *accessname = ctxt->accessname;
1933 if (local_name)
1934 {
1935 strcpyW(accessname, local_name);
1936 if (ctxt->result)
1937 *ctxt->result = CONNECT_LOCALDRIVE;
1938 }
1939 else
1940 strcpyW(accessname, ctxt->resource->lpRemoteName);
1941 }
1942
1943 static DWORD wnet_use_provider( struct use_connection_context *ctxt, NETRESOURCEW * netres, WNetProvider *provider, BOOLEAN redirect )
1944 {
1945 DWORD caps, ret;
1946
1947 caps = provider->getCaps(WNNC_CONNECTION);
1948 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1949 return ERROR_BAD_PROVIDER;
1950
1951 ret = WN_ACCESS_DENIED;
1952 do
1953 {
1954 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1955 ret = provider->addConnection3(ctxt->hwndOwner, netres, ctxt->password, ctxt->userid, ctxt->flags);
1956 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1957 ret = provider->addConnection(netres, ctxt->password, ctxt->userid);
1958
1959 if (ret == WN_ALREADY_CONNECTED && redirect)
1960 netres->lpLocalName[0] -= 1;
1961 } while (redirect && ret == WN_ALREADY_CONNECTED && netres->lpLocalName[0] >= 'C');
1962
1963 if (ret == WN_SUCCESS && ctxt->accessname)
1964 ctxt->set_accessname(ctxt, netres->lpLocalName);
1965
1966 return ret;
1967 }
1968
1969 static DWORD wnet_use_connection( struct use_connection_context *ctxt )
1970 {
1971 WNetProvider *provider;
1972 DWORD index, ret = WN_NO_NETWORK;
1973 BOOL redirect = FALSE;
1974 WCHAR letter[3] = {'Z', ':', 0};
1975 NETRESOURCEW netres;
1976
1977 if (!providerTable || providerTable->numProviders == 0)
1978 return WN_NO_NETWORK;
1979
1980 if (!ctxt->resource)
1981 return ERROR_INVALID_PARAMETER;
1982 netres = *ctxt->resource;
1983
1984 if (!netres.lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
1985 {
1986 if (netres.dwType != RESOURCETYPE_DISK && netres.dwType != RESOURCETYPE_PRINT)
1987 return ERROR_BAD_DEV_TYPE;
1988
1989 if (netres.dwType == RESOURCETYPE_PRINT)
1990 {
1991 FIXME("Local device selection is not implemented for printers.\n");
1992 return WN_NO_NETWORK;
1993 }
1994
1995 redirect = TRUE;
1996 netres.lpLocalName = letter;
1997 }
1998
1999 if (ctxt->flags & CONNECT_INTERACTIVE)
2000 return ERROR_BAD_NET_NAME;
2001
2002 if ((ret = ctxt->pre_set_accessname(ctxt, netres.lpLocalName)))
2003 return ret;
2004
2005 if (netres.lpProvider)
2006 {
2007 index = _findProviderIndexW(netres.lpProvider);
2008 if (index == BAD_PROVIDER_INDEX)
2009 return ERROR_BAD_PROVIDER;
2010
2011 provider = &providerTable->table[index];
2012 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
2013 }
2014 else
2015 {
2016 for (index = 0; index < providerTable->numProviders; index++)
2017 {
2018 provider = &providerTable->table[index];
2019 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
2020 if (ret == WN_SUCCESS || ret == WN_ALREADY_CONNECTED)
2021 break;
2022 }
2023 }
2024
2025 #ifdef __REACTOS__
2026 if (ret == WN_SUCCESS && ctxt->flags & CONNECT_UPDATE_PROFILE)
2027 {
2028 HKEY user_profile;
2029
2030 if (netres.dwType == RESOURCETYPE_PRINT)
2031 {
2032 FIXME("Persistent connection are not supported for printers\n");
2033 return ret;
2034 }
2035
2036 if (RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
2037 {
2038 HKEY network;
2039 WCHAR subkey[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres.lpLocalName[0], 0};
2040
2041 if (RegCreateKeyExW(user_profile, subkey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &network, NULL) == ERROR_SUCCESS)
2042 {
2043 DWORD dword_arg = RESOURCETYPE_DISK;
2044 DWORD len = (strlenW(provider->name) + 1) * sizeof(WCHAR);
2045
2046 RegSetValueExW(network, L"ConnectionType", 0, REG_DWORD, (const BYTE *)&dword_arg, sizeof(DWORD));
2047 RegSetValueExW(network, L"ProviderName", 0, REG_SZ, (const BYTE *)provider->name, len);
2048 dword_arg = provider->dwNetType;
2049 RegSetValueExW(network, L"ProviderType", 0, REG_DWORD, (const BYTE *)&dword_arg, sizeof(DWORD));
2050 len = (strlenW(netres.lpRemoteName) + 1) * sizeof(WCHAR);
2051 RegSetValueExW(network, L"RemotePath", 0, REG_SZ, (const BYTE *)netres.lpRemoteName, len);
2052 len = 0;
2053 RegSetValueExW(network, L"UserName", 0, REG_SZ, (const BYTE *)netres.lpRemoteName, len);
2054 RegCloseKey(network);
2055 }
2056
2057 RegCloseKey(user_profile);
2058 }
2059 }
2060 #endif
2061
2062 return ret;
2063 }
2064
2065 /*****************************************************************
2066 * WNetUseConnectionW [MPR.@]
2067 */
2068 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
2069 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
2070 {
2071 struct use_connection_context ctxt;
2072
2073 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
2074 hwndOwner, resource, password, debugstr_w(userid), flags,
2075 accessname, buffer_size, result );
2076
2077 ctxt.hwndOwner = hwndOwner;
2078 ctxt.resource = resource;
2079 ctxt.resourceA = NULL;
2080 ctxt.password = (WCHAR*)password;
2081 ctxt.userid = (WCHAR*)userid;
2082 ctxt.flags = flags;
2083 ctxt.accessname = accessname;
2084 ctxt.buffer_size = buffer_size;
2085 ctxt.result = result;
2086 ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
2087 ctxt.set_accessname = use_connection_set_accessnameW;
2088
2089 return wnet_use_connection(&ctxt);
2090 }
2091
2092 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
2093 {
2094 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
2095 {
2096 DWORD len;
2097
2098 if (local_name)
2099 len = WideCharToMultiByte(CP_ACP, 0, local_name, -1, NULL, 0, NULL, NULL) - 1;
2100 else
2101 len = strlen(ctxt->resourceA->lpRemoteName);
2102
2103 if (++len > *ctxt->buffer_size)
2104 {
2105 *ctxt->buffer_size = len;
2106 return ERROR_MORE_DATA;
2107 }
2108 }
2109 else
2110 ctxt->accessname = NULL;
2111
2112 return ERROR_SUCCESS;
2113 }
2114
2115 static void use_connection_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
2116 {
2117 char *accessname = ctxt->accessname;
2118 if (local_name)
2119 {
2120 WideCharToMultiByte(CP_ACP, 0, local_name, -1, accessname, *ctxt->buffer_size, NULL, NULL);
2121 if (ctxt->result)
2122 *ctxt->result = CONNECT_LOCALDRIVE;
2123 }
2124 else
2125 strcpy(accessname, ctxt->resourceA->lpRemoteName);
2126 }
2127
2128 static LPWSTR strdupAtoW( LPCSTR str )
2129 {
2130 LPWSTR ret;
2131 INT len;
2132
2133 if (!str) return NULL;
2134 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
2135 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2136 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
2137 return ret;
2138 }
2139
2140 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
2141 {
2142 resourceW->dwScope = resourceA->dwScope;
2143 resourceW->dwType = resourceA->dwType;
2144 resourceW->dwDisplayType = resourceA->dwDisplayType;
2145 resourceW->dwUsage = resourceA->dwUsage;
2146 resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
2147 resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
2148 resourceW->lpComment = strdupAtoW(resourceA->lpComment);
2149 resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
2150 }
2151
2152 static void free_netresourceW( NETRESOURCEW *resource )
2153 {
2154 HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
2155 HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
2156 HeapFree(GetProcessHeap(), 0, resource->lpComment);
2157 HeapFree(GetProcessHeap(), 0, resource->lpProvider);
2158 }
2159
2160 /*****************************************************************
2161 * WNetUseConnectionA [MPR.@]
2162 */
2163 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
2164 LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
2165 DWORD *buffer_size, DWORD *result )
2166 {
2167 struct use_connection_context ctxt;
2168 NETRESOURCEW resourceW;
2169 DWORD ret;
2170
2171 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
2172 accessname, buffer_size, result );
2173
2174 netresource_a_to_w(resource, &resourceW);
2175
2176 ctxt.hwndOwner = hwndOwner;
2177 ctxt.resource = &resourceW;
2178 ctxt.resourceA = resource;
2179 ctxt.password = strdupAtoW(password);
2180 ctxt.userid = strdupAtoW(userid);
2181 ctxt.flags = flags;
2182 ctxt.accessname = accessname;
2183 ctxt.buffer_size = buffer_size;
2184 ctxt.result = result;
2185 ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
2186 ctxt.set_accessname = use_connection_set_accessnameA;
2187
2188 ret = wnet_use_connection(&ctxt);
2189
2190 free_netresourceW(&resourceW);
2191 HeapFree(GetProcessHeap(), 0, ctxt.password);
2192 HeapFree(GetProcessHeap(), 0, ctxt.userid);
2193
2194 return ret;
2195 }
2196
2197 /*********************************************************************
2198 * WNetCancelConnectionA [MPR.@]
2199 */
2200 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
2201 {
2202 return WNetCancelConnection2A(lpName, 0, fForce);
2203 }
2204
2205 /*********************************************************************
2206 * WNetCancelConnectionW [MPR.@]
2207 */
2208 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
2209 {
2210 return WNetCancelConnection2W(lpName, 0, fForce);
2211 }
2212
2213 /*********************************************************************
2214 * WNetCancelConnection2A [MPR.@]
2215 */
2216 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
2217 {
2218 DWORD ret;
2219 WCHAR * name = strdupAtoW(lpName);
2220 if (!name)
2221 return ERROR_NOT_CONNECTED;
2222
2223 ret = WNetCancelConnection2W(name, dwFlags, fForce);
2224 HeapFree(GetProcessHeap(), 0, name);
2225
2226 return ret;
2227 }
2228
2229 /*********************************************************************
2230 * WNetCancelConnection2W [MPR.@]
2231 */
2232 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
2233 {
2234 DWORD ret = WN_NO_NETWORK;
2235 DWORD index;
2236
2237 if (providerTable != NULL)
2238 {
2239 for (index = 0; index < providerTable->numProviders; index++)
2240 {
2241 if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2242 WNNC_CON_CANCELCONNECTION)
2243 {
2244 if (providerTable->table[index].cancelConnection)
2245 ret = providerTable->table[index].cancelConnection((LPWSTR)lpName, fForce);
2246 else
2247 ret = WN_NO_NETWORK;
2248 if (ret == WN_SUCCESS || ret == WN_OPEN_FILES)
2249 break;
2250 }
2251 }
2252 }
2253 #ifdef __REACTOS__
2254
2255 if (dwFlags & CONNECT_UPDATE_PROFILE)
2256 {
2257 HKEY user_profile;
2258 WCHAR *coma = strchrW(lpName, ':');
2259
2260 if (coma && RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
2261 {
2262 WCHAR *subkey;
2263 DWORD len;
2264
2265 len = (ULONG_PTR)coma - (ULONG_PTR)lpName + sizeof(L"Network\\");
2266 subkey = HeapAlloc(GetProcessHeap(), 0, len);
2267 if (subkey)
2268 {
2269 strcpyW(subkey, L"Network\\");
2270 memcpy(subkey + (sizeof(L"Network\\") / sizeof(WCHAR)) - 1, lpName, (ULONG_PTR)coma - (ULONG_PTR)lpName);
2271 subkey[len / sizeof(WCHAR) - 1] = 0;
2272
2273 TRACE("Removing: %S\n", subkey);
2274
2275 RegDeleteKeyW(user_profile, subkey);
2276 HeapFree(GetProcessHeap(), 0, subkey);
2277 }
2278
2279 RegCloseKey(user_profile);
2280 }
2281 }
2282
2283 #endif
2284 return ret;
2285 }
2286
2287 /*****************************************************************
2288 * WNetRestoreConnectionA [MPR.@]
2289 */
2290 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
2291 {
2292 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
2293
2294 SetLastError(WN_NO_NETWORK);
2295 return WN_NO_NETWORK;
2296 }
2297
2298 /*****************************************************************
2299 * WNetRestoreConnectionW [MPR.@]
2300 */
2301 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
2302 {
2303 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
2304
2305 SetLastError(WN_NO_NETWORK);
2306 return WN_NO_NETWORK;
2307 }
2308
2309 /**************************************************************************
2310 * WNetGetConnectionA [MPR.@]
2311 *
2312 * RETURNS
2313 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2314 * - WN_NOT_CONNECTED drive is a local drive
2315 * - WN_MORE_DATA buffer isn't big enough
2316 * - WN_SUCCESS success (net path in buffer)
2317 *
2318 * FIXME: need to test return values under different errors
2319 */
2320 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
2321 LPSTR lpRemoteName, LPDWORD lpBufferSize )
2322 {
2323 DWORD ret;
2324
2325 if (!lpLocalName)
2326 ret = WN_BAD_POINTER;
2327 else if (!lpBufferSize)
2328 ret = WN_BAD_POINTER;
2329 else if (!lpRemoteName && *lpBufferSize)
2330 ret = WN_BAD_POINTER;
2331 else
2332 {
2333 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
2334
2335 if (len)
2336 {
2337 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2338
2339 if (wideLocalName)
2340 {
2341 WCHAR wideRemoteStatic[MAX_PATH];
2342 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
2343
2344 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
2345
2346 /* try once without memory allocation */
2347 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
2348 &wideRemoteSize);
2349 if (ret == WN_SUCCESS)
2350 {
2351 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2352 -1, NULL, 0, NULL, NULL);
2353
2354 if (len <= *lpBufferSize)
2355 {
2356 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
2357 lpRemoteName, *lpBufferSize, NULL, NULL);
2358 ret = WN_SUCCESS;
2359 }
2360 else
2361 {
2362 *lpBufferSize = len;
2363 ret = WN_MORE_DATA;
2364 }
2365 }
2366 else if (ret == WN_MORE_DATA)
2367 {
2368 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
2369 wideRemoteSize * sizeof(WCHAR));
2370
2371 if (wideRemote)
2372 {
2373 ret = WNetGetConnectionW(wideLocalName, wideRemote,
2374 &wideRemoteSize);
2375 if (ret == WN_SUCCESS)
2376 {
2377 if (len <= *lpBufferSize)
2378 {
2379 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2380 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
2381 ret = WN_SUCCESS;
2382 }
2383 else
2384 {
2385 *lpBufferSize = len;
2386 ret = WN_MORE_DATA;
2387 }
2388 }
2389 HeapFree(GetProcessHeap(), 0, wideRemote);
2390 }
2391 else
2392 ret = WN_OUT_OF_MEMORY;
2393 }
2394 HeapFree(GetProcessHeap(), 0, wideLocalName);
2395 }
2396 else
2397 ret = WN_OUT_OF_MEMORY;
2398 }
2399 else
2400 ret = WN_BAD_LOCALNAME;
2401 }
2402 if (ret)
2403 SetLastError(ret);
2404 TRACE("Returning %d\n", ret);
2405 return ret;
2406 }
2407
2408 /* find the network connection for a given drive; helper for WNetGetConnection */
2409 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
2410 {
2411 #ifndef __REACTOS__
2412 char buffer[1024];
2413 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
2414 HANDLE mgr;
2415 DWORD ret = WN_NOT_CONNECTED;
2416 DWORD bytes_returned;
2417
2418 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
2419 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
2420 0, 0 )) == INVALID_HANDLE_VALUE)
2421 {
2422 ERR( "failed to open mount manager err %u\n", GetLastError() );
2423 return ret;
2424 }
2425 memset( data, 0, sizeof(*data) );
2426 data->letter = letter;
2427 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
2428 data, sizeof(buffer), &bytes_returned, NULL ))
2429 {
2430 char *p, *mount_point = buffer + data->mount_point_offset;
2431 DWORD len;
2432
2433 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
2434 {
2435 mount_point += 2;
2436 mount_point[0] = '\\';
2437 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
2438
2439 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
2440 if (len > *size)
2441 {
2442 *size = len;
2443 ret = WN_MORE_DATA;
2444 }
2445 else
2446 {
2447 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
2448 ret = WN_SUCCESS;
2449 }
2450 }
2451 }
2452 CloseHandle( mgr );
2453 return ret;
2454 #else
2455 DWORD ret = WN_NO_NETWORK;
2456 DWORD index;
2457 WCHAR local[3] = {letter, ':', 0};
2458
2459 if (providerTable != NULL)
2460 {
2461 for (index = 0; index < providerTable->numProviders; index++)
2462 {
2463 if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2464 WNNC_CON_GETCONNECTIONS)
2465 {
2466 if (providerTable->table[index].getConnection)
2467 ret = providerTable->table[index].getConnection(
2468 local, remote, size);
2469 else
2470 ret = WN_NO_NETWORK;
2471 if (ret == WN_SUCCESS || ret == WN_MORE_DATA)
2472 break;
2473 }
2474 }
2475 }
2476 if (ret)
2477 SetLastError(ret);
2478 return ret;
2479 #endif
2480 }
2481
2482 /**************************************************************************
2483 * WNetGetConnectionW [MPR.@]
2484 *
2485 * FIXME: need to test return values under different errors
2486 */
2487 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
2488 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
2489 {
2490 DWORD ret;
2491
2492 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
2493 lpBufferSize);
2494
2495 if (!lpLocalName)
2496 ret = WN_BAD_POINTER;
2497 else if (!lpBufferSize)
2498 ret = WN_BAD_POINTER;
2499 else if (!lpRemoteName && *lpBufferSize)
2500 ret = WN_BAD_POINTER;
2501 else if (!lpLocalName[0])
2502 ret = WN_BAD_LOCALNAME;
2503 else
2504 {
2505 if (lpLocalName[1] == ':')
2506 {
2507 switch(GetDriveTypeW(lpLocalName))
2508 {
2509 case DRIVE_REMOTE:
2510 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
2511 break;
2512 case DRIVE_REMOVABLE:
2513 case DRIVE_FIXED:
2514 case DRIVE_CDROM:
2515 TRACE("file is local\n");
2516 ret = WN_NOT_CONNECTED;
2517 break;
2518 default:
2519 ret = WN_BAD_LOCALNAME;
2520 }
2521 }
2522 else
2523 ret = WN_BAD_LOCALNAME;
2524 }
2525 if (ret)
2526 SetLastError(ret);
2527 TRACE("Returning %d\n", ret);
2528 return ret;
2529 }
2530
2531 /**************************************************************************
2532 * WNetSetConnectionA [MPR.@]
2533 */
2534 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
2535 LPVOID pvValue )
2536 {
2537 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
2538
2539 SetLastError(WN_NO_NETWORK);
2540 return WN_NO_NETWORK;
2541 }
2542
2543 /**************************************************************************
2544 * WNetSetConnectionW [MPR.@]
2545 */
2546 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2547 LPVOID pvValue )
2548 {
2549 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2550
2551 SetLastError(WN_NO_NETWORK);
2552 return WN_NO_NETWORK;
2553 }
2554
2555 /*****************************************************************
2556 * WNetGetUniversalNameA [MPR.@]
2557 */
2558 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2559 LPVOID lpBuffer, LPDWORD lpBufferSize )
2560 {
2561 DWORD err, size;
2562
2563 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2564 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2565
2566 switch (dwInfoLevel)
2567 {
2568 case UNIVERSAL_NAME_INFO_LEVEL:
2569 {
2570 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2571
2572 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2573 {
2574 err = ERROR_NOT_CONNECTED;
2575 break;
2576 }
2577
2578 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2579 if (*lpBufferSize < size)
2580 {
2581 err = WN_MORE_DATA;
2582 break;
2583 }
2584 info->lpUniversalName = (char *)info + sizeof(*info);
2585 lstrcpyA(info->lpUniversalName, lpLocalPath);
2586 err = WN_NO_ERROR;
2587 break;
2588 }
2589 case REMOTE_NAME_INFO_LEVEL:
2590 err = WN_NOT_CONNECTED;
2591 break;
2592
2593 default:
2594 err = WN_BAD_VALUE;
2595 break;
2596 }
2597
2598 SetLastError(err);
2599 return err;
2600 }
2601
2602 /*****************************************************************
2603 * WNetGetUniversalNameW [MPR.@]
2604 */
2605 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2606 LPVOID lpBuffer, LPDWORD lpBufferSize )
2607 {
2608 DWORD err, size;
2609
2610 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2611 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2612
2613 switch (dwInfoLevel)
2614 {
2615 case UNIVERSAL_NAME_INFO_LEVEL:
2616 {
2617 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2618
2619 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2620 {
2621 err = ERROR_NOT_CONNECTED;
2622 break;
2623 }
2624
2625 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2626 if (*lpBufferSize < size)
2627 {
2628 err = WN_MORE_DATA;
2629 break;
2630 }
2631 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2632 lstrcpyW(info->lpUniversalName, lpLocalPath);
2633 err = WN_NO_ERROR;
2634 break;
2635 }
2636 case REMOTE_NAME_INFO_LEVEL:
2637 err = WN_NO_NETWORK;
2638 break;
2639
2640 default:
2641 err = WN_BAD_VALUE;
2642 break;
2643 }
2644
2645 if (err != WN_NO_ERROR) SetLastError(err);
2646 return err;
2647 }
2648
2649 /*****************************************************************
2650 * WNetClearConnections [MPR.@]
2651 */
2652 DWORD WINAPI WNetClearConnections ( HWND owner )
2653 {
2654 HANDLE connected;
2655 PWSTR connection;
2656 DWORD ret, size, count;
2657 NETRESOURCEW * resources, * iter;
2658
2659 ret = WNetOpenEnumW(RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL, &connected);
2660 if (ret != WN_SUCCESS)
2661 {
2662 if (ret != WN_NO_NETWORK)
2663 {
2664 return ret;
2665 }
2666
2667 /* Means no provider, then, clearing is OK */
2668 return WN_SUCCESS;
2669 }
2670
2671 size = 0x1000;
2672 resources = HeapAlloc(GetProcessHeap(), 0, size);
2673 if (!resources)
2674 {
2675 WNetCloseEnum(connected);
2676 return WN_OUT_OF_MEMORY;
2677 }
2678
2679 for (;;)
2680 {
2681 size = 0x1000;
2682 count = -1;
2683
2684 memset(resources, 0, size);
2685 ret = WNetEnumResourceW(connected, &count, resources, &size);
2686 if (ret == WN_SUCCESS || ret == WN_MORE_DATA)
2687 {
2688 for (iter = resources; count; count--, iter++)
2689 {
2690 if (iter->lpLocalName && iter->lpLocalName[0])
2691 connection = iter->lpLocalName;
2692 else
2693 connection = iter->lpRemoteName;
2694
2695 WNetCancelConnection2W(connection, 0, TRUE);
2696 }
2697 }
2698 else
2699 break;
2700 }
2701
2702 HeapFree(GetProcessHeap(), 0, resources);
2703 WNetCloseEnum(connected);
2704
2705 return ret;
2706 }
2707
2708
2709 /*
2710 * Other Functions
2711 */
2712
2713 /**************************************************************************
2714 * WNetGetUserA [MPR.@]
2715 *
2716 * FIXME: we should not return ourselves, but the owner of the drive lpName
2717 */
2718 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2719 {
2720 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2721 return GetLastError();
2722 }
2723
2724 /*****************************************************************
2725 * WNetGetUserW [MPR.@]
2726 *
2727 * FIXME: we should not return ourselves, but the owner of the drive lpName
2728 */
2729 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2730 {
2731 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2732 return GetLastError();
2733 }
2734
2735 /*********************************************************************
2736 * WNetConnectionDialog [MPR.@]
2737 */
2738 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2739 {
2740 CONNECTDLGSTRUCTW conn_dlg;
2741 NETRESOURCEW net_res;
2742
2743 ZeroMemory(&conn_dlg, sizeof(conn_dlg));
2744 ZeroMemory(&net_res, sizeof(net_res));
2745
2746 conn_dlg.cbStructure = sizeof(conn_dlg);
2747 conn_dlg.lpConnRes = &net_res;
2748 conn_dlg.hwndOwner = hwnd;
2749 net_res.dwType = dwType;
2750
2751 return WNetConnectionDialog1W(&conn_dlg);
2752 }
2753
2754 /*********************************************************************
2755 * WNetConnectionDialog1A [MPR.@]
2756 */
2757 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2758 {
2759 FIXME( "(%p): stub\n", lpConnDlgStruct );
2760
2761 SetLastError(WN_NO_NETWORK);
2762 return WN_NO_NETWORK;
2763 }
2764
2765 /*********************************************************************
2766 * WNetConnectionDialog1W [MPR.@]
2767 */
2768 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2769 {
2770 FIXME( "(%p): stub\n", lpConnDlgStruct );
2771
2772 SetLastError(WN_NO_NETWORK);
2773 return WN_NO_NETWORK;
2774 }
2775
2776 /*********************************************************************
2777 * WNetDisconnectDialog [MPR.@]
2778 */
2779 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2780 {
2781 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2782
2783 SetLastError(WN_NO_NETWORK);
2784 return WN_NO_NETWORK;
2785 }
2786
2787 /*********************************************************************
2788 * WNetDisconnectDialog1A [MPR.@]
2789 */
2790 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2791 {
2792 FIXME( "(%p): stub\n", lpConnDlgStruct );
2793
2794 SetLastError(WN_NO_NETWORK);
2795 return WN_NO_NETWORK;
2796 }
2797
2798 /*********************************************************************
2799 * WNetDisconnectDialog1W [MPR.@]
2800 */
2801 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2802 {
2803 FIXME( "(%p): stub\n", lpConnDlgStruct );
2804
2805 SetLastError(WN_NO_NETWORK);
2806 return WN_NO_NETWORK;
2807 }
2808
2809 /*********************************************************************
2810 * WNetGetLastErrorA [MPR.@]
2811 */
2812 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2813 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2814 LPSTR lpNameBuf, DWORD nNameBufSize )
2815 {
2816 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2817 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2818
2819 SetLastError(WN_NO_NETWORK);
2820 return WN_NO_NETWORK;
2821 }
2822
2823 /*********************************************************************
2824 * WNetGetLastErrorW [MPR.@]
2825 */
2826 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2827 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2828 LPWSTR lpNameBuf, DWORD nNameBufSize )
2829 {
2830 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2831 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2832
2833 SetLastError(WN_NO_NETWORK);
2834 return WN_NO_NETWORK;
2835 }
2836
2837 /*********************************************************************
2838 * WNetGetNetworkInformationA [MPR.@]
2839 */
2840 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2841 LPNETINFOSTRUCT lpNetInfoStruct )
2842 {
2843 DWORD ret;
2844
2845 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2846
2847 if (!lpProvider)
2848 ret = WN_BAD_POINTER;
2849 else
2850 {
2851 int len;
2852
2853 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2854 if (len)
2855 {
2856 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2857
2858 if (wideProvider)
2859 {
2860 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2861 len);
2862 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2863 HeapFree(GetProcessHeap(), 0, wideProvider);
2864 }
2865 else
2866 ret = WN_OUT_OF_MEMORY;
2867 }
2868 else
2869 ret = GetLastError();
2870 }
2871 if (ret)
2872 SetLastError(ret);
2873 TRACE("Returning %d\n", ret);
2874 return ret;
2875 }
2876
2877 /*********************************************************************
2878 * WNetGetNetworkInformationW [MPR.@]
2879 */
2880 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2881 LPNETINFOSTRUCT lpNetInfoStruct )
2882 {
2883 DWORD ret;
2884
2885 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2886
2887 if (!lpProvider)
2888 ret = WN_BAD_POINTER;
2889 else if (!lpNetInfoStruct)
2890 ret = WN_BAD_POINTER;
2891 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2892 ret = WN_BAD_VALUE;
2893 else
2894 {
2895 if (providerTable && providerTable->numProviders)
2896 {
2897 DWORD providerIndex = _findProviderIndexW(lpProvider);
2898
2899 if (providerIndex != BAD_PROVIDER_INDEX)
2900 {
2901 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2902 lpNetInfoStruct->dwProviderVersion =
2903 providerTable->table[providerIndex].dwSpecVersion;
2904 lpNetInfoStruct->dwStatus = NO_ERROR;
2905 lpNetInfoStruct->dwCharacteristics = 0;
2906 lpNetInfoStruct->dwHandle = 0;
2907 lpNetInfoStruct->wNetType =
2908 HIWORD(providerTable->table[providerIndex].dwNetType);
2909 lpNetInfoStruct->dwPrinters = -1;
2910 lpNetInfoStruct->dwDrives = -1;
2911 ret = WN_SUCCESS;
2912 }
2913 else
2914 ret = WN_BAD_PROVIDER;
2915 }
2916 else
2917 ret = WN_NO_NETWORK;
2918 }
2919 if (ret)
2920 SetLastError(ret);
2921 TRACE("Returning %d\n", ret);
2922 return ret;
2923 }
2924
2925 /*****************************************************************
2926 * WNetGetProviderNameA [MPR.@]
2927 */
2928 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2929 LPSTR lpProvider, LPDWORD lpBufferSize )
2930 {
2931 DWORD ret;
2932
2933 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2934 lpBufferSize);
2935
2936 if (!lpProvider)
2937 ret = WN_BAD_POINTER;
2938 else if (!lpBufferSize)
2939 ret = WN_BAD_POINTER;
2940 else
2941 {
2942 if (providerTable)
2943 {
2944 DWORD i;
2945
2946 ret = WN_NO_NETWORK;
2947 for (i = 0; i < providerTable->numProviders &&
2948 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2949 i++)
2950 ;
2951 if (i < providerTable->numProviders)
2952 {
2953 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2954 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2955
2956 if (*lpBufferSize < sizeNeeded)
2957 {
2958 *lpBufferSize = sizeNeeded;
2959 ret = WN_MORE_DATA;
2960 }
2961 else
2962 {
2963 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2964 -1, lpProvider, *lpBufferSize, NULL, NULL);
2965 ret = WN_SUCCESS;
2966 /* FIXME: is *lpBufferSize set to the number of characters
2967 * copied? */
2968 }
2969 }
2970 }
2971 else
2972 ret = WN_NO_NETWORK;
2973 }
2974 if (ret)
2975 SetLastError(ret);
2976 TRACE("Returning %d\n", ret);
2977 return ret;
2978 }
2979
2980 /*****************************************************************
2981 * WNetGetProviderNameW [MPR.@]
2982 */
2983 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2984 LPWSTR lpProvider, LPDWORD lpBufferSize )
2985 {
2986 DWORD ret;
2987
2988 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2989 lpBufferSize);
2990
2991 if (!lpProvider)
2992 ret = WN_BAD_POINTER;
2993 else if (!lpBufferSize)
2994 ret = WN_BAD_POINTER;
2995 else
2996 {
2997 if (providerTable)
2998 {
2999 DWORD i;
3000
3001 ret = WN_NO_NETWORK;
3002 for (i = 0; i < providerTable->numProviders &&
3003 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
3004 i++)
3005 ;
3006 if (i < providerTable->numProviders)
3007 {
3008 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
3009
3010 if (*lpBufferSize < sizeNeeded)
3011 {
3012 *lpBufferSize = sizeNeeded;
3013 ret = WN_MORE_DATA;
3014 }
3015 else
3016 {
3017 strcpyW(lpProvider, providerTable->table[i].name);
3018 ret = WN_SUCCESS;
3019 /* FIXME: is *lpBufferSize set to the number of characters
3020 * copied? */
3021 }
3022 }
3023 }
3024 else
3025 ret = WN_NO_NETWORK;
3026 }
3027 if (ret)
3028 SetLastError(ret);
3029 TRACE("Returning %d\n", ret);
3030 return ret;
3031 }