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