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