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