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