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