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