[MPR] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / reactos / 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 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include "precomp.h"
24
25 #include <winioctl.h>
26 #include <npapi.h>
27 #define WINE_MOUNTMGR_EXTENSIONS
28 #include <ddk/mountmgr.h>
29 #include <wine/unicode.h>
30
31 /* Data structures representing network service providers. Assumes only one
32 * thread creates them, and that they are constant for the life of the process
33 * (and therefore doesn't synchronize access).
34 * FIXME: only basic provider data and enumeration-related data are implemented
35 * so far, need to implement the rest too.
36 */
37 typedef struct _WNetProvider
38 {
39 HMODULE hLib;
40 PWSTR name;
41 PF_NPGetCaps getCaps;
42 DWORD dwSpecVersion;
43 DWORD dwNetType;
44 DWORD dwEnumScopes;
45 PF_NPOpenEnum openEnum;
46 PF_NPEnumResource enumResource;
47 PF_NPCloseEnum closeEnum;
48 PF_NPGetResourceInformation getResourceInformation;
49 } WNetProvider, *PWNetProvider;
50
51 typedef struct _WNetProviderTable
52 {
53 LPWSTR entireNetwork;
54 DWORD numAllocated;
55 DWORD numProviders;
56 WNetProvider table[1];
57 } WNetProviderTable, *PWNetProviderTable;
58
59 #define WNET_ENUMERATOR_TYPE_NULL 0
60 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
61 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
62 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
63
64 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
65 * the enumeration; it represents one of the following types:
66 * - a 'null' enumeration, one that contains no members
67 * - a global enumeration, one that's executed across all providers
68 * - a provider-specific enumeration, one that's only executed by a single
69 * provider
70 * - a context enumeration. I know this contradicts what I just said about
71 * there being no correspondence between the scope and the type, but it's
72 * necessary for the special case that a "Entire Network" entry needs to
73 * be enumerated in an enumeration of the context scope. Thus an enumeration
74 * of the context scope results in a context type enumerator, which morphs
75 * into a global enumeration (so the enumeration continues across all
76 * providers).
77 */
78 typedef struct _WNetEnumerator
79 {
80 DWORD enumType;
81 DWORD providerIndex;
82 HANDLE handle;
83 BOOL providerDone;
84 DWORD dwScope;
85 DWORD dwType;
86 DWORD dwUsage;
87 LPNETRESOURCEW lpNet;
88 } WNetEnumerator, *PWNetEnumerator;
89
90 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
91
92 /* Returns an index (into the global WNetProviderTable) of the provider with
93 * the given name, or BAD_PROVIDER_INDEX if not found.
94 */
95 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
96
97 static PWNetProviderTable providerTable;
98
99 /*
100 * Global provider table functions
101 */
102
103 static void _tryLoadProvider(PCWSTR provider)
104 {
105 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
106 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
107 'S','e','r','v','i','c','e','s','\\',0 };
108 static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
109 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
110 WCHAR serviceName[MAX_PATH];
111 HKEY hKey;
112
113 TRACE("%s\n", debugstr_w(provider));
114 snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt,
115 servicePrefix, provider);
116 serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0';
117 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
118 ERROR_SUCCESS)
119 {
120 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
121 'P','a','t','h',0 };
122 WCHAR providerPath[MAX_PATH];
123 DWORD type, size = sizeof(providerPath);
124
125 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
126 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && type == REG_SZ)
127 {
128 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
129 PWSTR name = NULL;
130
131 size = 0;
132 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
133 if (size)
134 {
135 name = HeapAlloc(GetProcessHeap(), 0, size);
136 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
137 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
138 {
139 HeapFree(GetProcessHeap(), 0, name);
140 name = NULL;
141 }
142 }
143 if (name)
144 {
145 HMODULE hLib = LoadLibraryW(providerPath);
146
147 if (hLib)
148 {
149 PF_NPGetCaps getCaps = (PF_NPGetCaps)GetProcAddress(hLib,
150 "NPGetCaps");
151
152 TRACE("loaded lib %p\n", hLib);
153 if (getCaps)
154 {
155 PWNetProvider provider =
156 &providerTable->table[providerTable->numProviders];
157
158 provider->hLib = hLib;
159 provider->name = name;
160 TRACE("name is %s\n", debugstr_w(name));
161 provider->getCaps = getCaps;
162 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
163 provider->dwNetType = getCaps(WNNC_NET_TYPE);
164 TRACE("net type is 0x%08x\n", provider->dwNetType);
165 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
166 if (provider->dwEnumScopes)
167 {
168 TRACE("supports enumeration\n");
169 provider->openEnum = (PF_NPOpenEnum)
170 GetProcAddress(hLib, "NPOpenEnum");
171 TRACE("openEnum is %p\n", provider->openEnum);
172 provider->enumResource = (PF_NPEnumResource)
173 GetProcAddress(hLib, "NPEnumResource");
174 TRACE("enumResource is %p\n",
175 provider->enumResource);
176 provider->closeEnum = (PF_NPCloseEnum)
177 GetProcAddress(hLib, "NPCloseEnum");
178 TRACE("closeEnum is %p\n", provider->closeEnum);
179 provider->getResourceInformation = (PF_NPGetResourceInformation)
180 GetProcAddress(hLib, "NPGetResourceInformation");
181 TRACE("getResourceInformation is %p\n",
182 provider->getResourceInformation);
183 if (!provider->openEnum || !provider->enumResource
184 || !provider->closeEnum)
185 {
186 provider->openEnum = NULL;
187 provider->enumResource = NULL;
188 provider->closeEnum = NULL;
189 provider->dwEnumScopes = 0;
190 WARN("Couldn't load enumeration functions\n");
191 }
192 }
193 providerTable->numProviders++;
194 }
195 else
196 {
197 WARN("Provider %s didn't export NPGetCaps\n",
198 debugstr_w(provider));
199 HeapFree(GetProcessHeap(), 0, name);
200 FreeLibrary(hLib);
201 }
202 }
203 else
204 {
205 WARN("Couldn't load library %s for provider %s\n",
206 debugstr_w(providerPath), debugstr_w(provider));
207 HeapFree(GetProcessHeap(), 0, name);
208 }
209 }
210 else
211 {
212 WARN("Couldn't get provider name for provider %s\n",
213 debugstr_w(provider));
214 }
215 }
216 else
217 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
218 RegCloseKey(hKey);
219 }
220 else
221 WARN("Couldn't open service key for provider %s\n",
222 debugstr_w(provider));
223 }
224
225 void wnetInit(HINSTANCE hInstDll)
226 {
227 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
228 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
229 'C','o','n','t','r','o','l','\\',
230 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
231 'O','r','d','e','r',0 };
232 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
233 'O','r','d','e','r',0 };
234 HKEY hKey;
235
236 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
237 == ERROR_SUCCESS)
238 {
239 DWORD size = 0;
240
241 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
242 if (size)
243 {
244 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
245
246 if (providers)
247 {
248 DWORD type;
249
250 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
251 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
252 {
253 PWSTR ptr;
254 DWORD numToAllocate;
255
256 TRACE("provider order is %s\n", debugstr_w(providers));
257 /* first count commas as a heuristic for how many to
258 * allocate space for */
259 for (ptr = providers, numToAllocate = 1; ptr; )
260 {
261 ptr = strchrW(ptr, ',');
262 if (ptr) {
263 numToAllocate++;
264 ptr++;
265 }
266 }
267 providerTable =
268 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
269 sizeof(WNetProviderTable)
270 + (numToAllocate - 1) * sizeof(WNetProvider));
271 if (providerTable)
272 {
273 PWSTR ptrPrev;
274 int entireNetworkLen;
275 LPCWSTR stringresource;
276
277 entireNetworkLen = LoadStringW(hInstDll,
278 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
279 providerTable->entireNetwork = HeapAlloc(
280 GetProcessHeap(), 0, (entireNetworkLen + 1) *
281 sizeof(WCHAR));
282 if (providerTable->entireNetwork)
283 {
284 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
285 providerTable->entireNetwork[entireNetworkLen] = 0;
286 }
287 providerTable->numAllocated = numToAllocate;
288 for (ptr = providers; ptr; )
289 {
290 ptrPrev = ptr;
291 ptr = strchrW(ptr, ',');
292 if (ptr)
293 *ptr++ = '\0';
294 _tryLoadProvider(ptrPrev);
295 }
296 }
297 }
298 HeapFree(GetProcessHeap(), 0, providers);
299 }
300 }
301 RegCloseKey(hKey);
302 }
303 }
304
305 void wnetFree(void)
306 {
307 if (providerTable)
308 {
309 DWORD i;
310
311 for (i = 0; i < providerTable->numProviders; i++)
312 {
313 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
314 FreeModule(providerTable->table[i].hLib);
315 }
316 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
317 HeapFree(GetProcessHeap(), 0, providerTable);
318 providerTable = NULL;
319 }
320 }
321
322 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
323 {
324 DWORD ret = BAD_PROVIDER_INDEX;
325
326 if (providerTable && providerTable->numProviders)
327 {
328 DWORD i;
329
330 for (i = 0; i < providerTable->numProviders &&
331 ret == BAD_PROVIDER_INDEX; i++)
332 if (!strcmpW(lpProvider, providerTable->table[i].name))
333 ret = i;
334 }
335 return ret;
336 }
337
338 /*
339 * Browsing Functions
340 */
341
342 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
343 {
344 LPNETRESOURCEW ret;
345
346 if (lpNet)
347 {
348 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
349 if (ret)
350 {
351 size_t len;
352
353 *ret = *lpNet;
354 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
355 if (lpNet->lpRemoteName)
356 {
357 len = strlenW(lpNet->lpRemoteName) + 1;
358 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
359 if (ret->lpRemoteName)
360 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
361 }
362 }
363 }
364 else
365 ret = NULL;
366 return ret;
367 }
368
369 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
370 {
371 if (lpNet)
372 {
373 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
374 HeapFree(GetProcessHeap(), 0, lpNet);
375 }
376 }
377
378 static PWNetEnumerator _createNullEnumerator(void)
379 {
380 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
381 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
382
383 if (ret)
384 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
385 return ret;
386 }
387
388 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
389 DWORD dwUsage, LPNETRESOURCEW lpNet)
390 {
391 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
392 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
393
394 if (ret)
395 {
396 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
397 ret->dwScope = dwScope;
398 ret->dwType = dwType;
399 ret->dwUsage = dwUsage;
400 ret->lpNet = _copyNetResourceForEnumW(lpNet);
401 }
402 return ret;
403 }
404
405 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
406 DWORD dwUsage, DWORD index, HANDLE handle)
407 {
408 PWNetEnumerator ret;
409
410 if (!providerTable || index >= providerTable->numProviders)
411 ret = NULL;
412 else
413 {
414 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
415 if (ret)
416 {
417 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
418 ret->providerIndex = index;
419 ret->dwScope = dwScope;
420 ret->dwType = dwType;
421 ret->dwUsage = dwUsage;
422 ret->handle = handle;
423 }
424 }
425 return ret;
426 }
427
428 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
429 DWORD dwUsage)
430 {
431 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
432 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
433
434 if (ret)
435 {
436 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
437 ret->dwScope = dwScope;
438 ret->dwType = dwType;
439 ret->dwUsage = dwUsage;
440 }
441 return ret;
442 }
443
444 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
445 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
446 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
447 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
448 * if not all members of the array could be thunked, and something else on
449 * failure.
450 */
451 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
452 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
453 {
454 DWORD i, numToThunk, totalBytes, ret;
455 LPSTR strNext;
456
457 if (!lpNetArrayIn)
458 return WN_BAD_POINTER;
459 if (!lpcCount)
460 return WN_BAD_POINTER;
461 if (*lpcCount == -1)
462 return WN_BAD_VALUE;
463 if (!lpBuffer)
464 return WN_BAD_POINTER;
465 if (!lpBufferSize)
466 return WN_BAD_POINTER;
467
468 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
469 {
470 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
471
472 totalBytes += sizeof(NETRESOURCEA);
473 if (lpNet->lpLocalName)
474 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
475 -1, NULL, 0, NULL, NULL);
476 if (lpNet->lpRemoteName)
477 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
478 -1, NULL, 0, NULL, NULL);
479 if (lpNet->lpComment)
480 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
481 -1, NULL, 0, NULL, NULL);
482 if (lpNet->lpProvider)
483 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
484 -1, NULL, 0, NULL, NULL);
485 if (totalBytes < *lpBufferSize)
486 numToThunk = i + 1;
487 }
488 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
489 for (i = 0; i < numToThunk; i++)
490 {
491 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
492 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
493
494 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
495 /* lie about string lengths, we already verified how many
496 * we have space for above
497 */
498 if (lpNetIn->lpLocalName)
499 {
500 lpNetOut->lpLocalName = strNext;
501 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
502 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
503 }
504 if (lpNetIn->lpRemoteName)
505 {
506 lpNetOut->lpRemoteName = strNext;
507 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
508 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
509 }
510 if (lpNetIn->lpComment)
511 {
512 lpNetOut->lpComment = strNext;
513 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
514 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
515 }
516 if (lpNetIn->lpProvider)
517 {
518 lpNetOut->lpProvider = strNext;
519 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
520 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
521 }
522 }
523 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
524 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
525 *lpcCount, ret);
526 return ret;
527 }
528
529 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
530 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
531 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
532 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
533 * if not all members of the array could be thunked, and something else on
534 * failure.
535 */
536 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
537 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
538 {
539 DWORD i, numToThunk, totalBytes, ret;
540 LPWSTR strNext;
541
542 if (!lpNetArrayIn)
543 return WN_BAD_POINTER;
544 if (!lpcCount)
545 return WN_BAD_POINTER;
546 if (*lpcCount == -1)
547 return WN_BAD_VALUE;
548 if (!lpBuffer)
549 return WN_BAD_POINTER;
550 if (!lpBufferSize)
551 return WN_BAD_POINTER;
552
553 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
554 {
555 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
556
557 totalBytes += sizeof(NETRESOURCEW);
558 if (lpNet->lpLocalName)
559 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
560 -1, NULL, 0) * sizeof(WCHAR);
561 if (lpNet->lpRemoteName)
562 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
563 -1, NULL, 0) * sizeof(WCHAR);
564 if (lpNet->lpComment)
565 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
566 -1, NULL, 0) * sizeof(WCHAR);
567 if (lpNet->lpProvider)
568 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
569 -1, NULL, 0) * sizeof(WCHAR);
570 if (totalBytes < *lpBufferSize)
571 numToThunk = i + 1;
572 }
573 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
574 for (i = 0; i < numToThunk; i++)
575 {
576 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
577 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
578
579 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
580 /* lie about string lengths, we already verified how many
581 * we have space for above
582 */
583 if (lpNetIn->lpLocalName)
584 {
585 lpNetOut->lpLocalName = strNext;
586 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
587 -1, lpNetOut->lpLocalName, *lpBufferSize);
588 }
589 if (lpNetIn->lpRemoteName)
590 {
591 lpNetOut->lpRemoteName = strNext;
592 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
593 -1, lpNetOut->lpRemoteName, *lpBufferSize);
594 }
595 if (lpNetIn->lpComment)
596 {
597 lpNetOut->lpComment = strNext;
598 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
599 -1, lpNetOut->lpComment, *lpBufferSize);
600 }
601 if (lpNetIn->lpProvider)
602 {
603 lpNetOut->lpProvider = strNext;
604 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
605 -1, lpNetOut->lpProvider, *lpBufferSize);
606 }
607 }
608 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
609 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
610 *lpcCount, ret);
611 return ret;
612 }
613
614 /*********************************************************************
615 * WNetOpenEnumA [MPR.@]
616 *
617 * See comments for WNetOpenEnumW.
618 */
619 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
620 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
621 {
622 DWORD ret;
623
624 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
625 dwScope, dwType, dwUsage, lpNet, lphEnum );
626
627 if (!lphEnum)
628 ret = WN_BAD_POINTER;
629 else if (!providerTable || providerTable->numProviders == 0)
630 {
631 *lphEnum = NULL;
632 ret = WN_NO_NETWORK;
633 }
634 else
635 {
636 if (lpNet)
637 {
638 LPNETRESOURCEW lpNetWide = NULL;
639 BYTE buf[1024];
640 DWORD size = sizeof(buf), count = 1;
641 BOOL allocated = FALSE;
642
643 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
644 if (ret == WN_MORE_DATA)
645 {
646 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
647 size);
648 if (lpNetWide)
649 {
650 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
651 &size);
652 allocated = TRUE;
653 }
654 else
655 ret = WN_OUT_OF_MEMORY;
656 }
657 else if (ret == WN_SUCCESS)
658 lpNetWide = (LPNETRESOURCEW)buf;
659 if (ret == WN_SUCCESS)
660 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
661 lphEnum);
662 if (allocated)
663 HeapFree(GetProcessHeap(), 0, lpNetWide);
664 }
665 else
666 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
667 }
668 if (ret)
669 SetLastError(ret);
670 TRACE("Returning %d\n", ret);
671 return ret;
672 }
673
674 /*********************************************************************
675 * WNetOpenEnumW [MPR.@]
676 *
677 * Network enumeration has way too many parameters, so I'm not positive I got
678 * them right. What I've got so far:
679 *
680 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
681 * all the network providers should be enumerated.
682 *
683 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
684 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
685 * lpProvider is set, all the network providers should be enumerated.
686 * (This means the enumeration is a list of network providers, not that the
687 * enumeration is passed on to the providers.)
688 *
689 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
690 * resource matches the "Entire Network" resource (no remote name, no
691 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
692 * enumeration is done on every network provider.
693 *
694 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
695 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
696 * only to the given network provider.
697 *
698 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
699 * no lpProvider is set, enumeration will be tried on every network provider,
700 * in the order in which they're loaded.
701 *
702 * - The LPNETRESOURCE should be disregarded for scopes besides
703 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
704 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
705 *
706 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
707 * resource in the enumerated list, as well as any machines in your
708 * workgroup. The machines in your workgroup come from doing a
709 * RESOURCE_CONTEXT enumeration of every Network Provider.
710 */
711 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
712 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
713 {
714 DWORD ret;
715
716 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
717 dwScope, dwType, dwUsage, lpNet, lphEnum );
718
719 if (!lphEnum)
720 ret = WN_BAD_POINTER;
721 else if (!providerTable || providerTable->numProviders == 0)
722 {
723 *lphEnum = NULL;
724 ret = WN_NO_NETWORK;
725 }
726 else
727 {
728 switch (dwScope)
729 {
730 case RESOURCE_GLOBALNET:
731 if (lpNet)
732 {
733 if (lpNet->lpProvider)
734 {
735 DWORD index = _findProviderIndexW(lpNet->lpProvider);
736
737 if (index != BAD_PROVIDER_INDEX)
738 {
739 if (providerTable->table[index].openEnum &&
740 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
741 {
742 HANDLE handle;
743
744 ret = providerTable->table[index].openEnum(
745 dwScope, dwType, dwUsage, lpNet, &handle);
746 if (ret == WN_SUCCESS)
747 {
748 *lphEnum = _createProviderEnumerator(
749 dwScope, dwType, dwUsage, index, handle);
750 ret = *lphEnum ? WN_SUCCESS :
751 WN_OUT_OF_MEMORY;
752 }
753 }
754 else
755 ret = WN_NOT_SUPPORTED;
756 }
757 else
758 ret = WN_BAD_PROVIDER;
759 }
760 else if (lpNet->lpRemoteName)
761 {
762 *lphEnum = _createGlobalEnumeratorW(dwScope,
763 dwType, dwUsage, lpNet);
764 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
765 }
766 else
767 {
768 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
769 providerTable->entireNetwork))
770 {
771 /* comment matches the "Entire Network", enumerate
772 * global scope of every provider
773 */
774 *lphEnum = _createGlobalEnumeratorW(dwScope,
775 dwType, dwUsage, lpNet);
776 }
777 else
778 {
779 /* this is the same as not having passed lpNet */
780 *lphEnum = _createGlobalEnumeratorW(dwScope,
781 dwType, dwUsage, NULL);
782 }
783 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
784 }
785 }
786 else
787 {
788 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
789 dwUsage, lpNet);
790 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
791 }
792 break;
793 case RESOURCE_CONTEXT:
794 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
795 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
796 break;
797 case RESOURCE_REMEMBERED:
798 case RESOURCE_CONNECTED:
799 *lphEnum = _createNullEnumerator();
800 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
801 break;
802 default:
803 WARN("unknown scope 0x%08x\n", dwScope);
804 ret = WN_BAD_VALUE;
805 }
806 }
807 if (ret)
808 SetLastError(ret);
809 TRACE("Returning %d\n", ret);
810 return ret;
811 }
812
813 /*********************************************************************
814 * WNetEnumResourceA [MPR.@]
815 */
816 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
817 LPVOID lpBuffer, LPDWORD lpBufferSize )
818 {
819 DWORD ret;
820
821 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
822
823 if (!hEnum)
824 ret = WN_BAD_POINTER;
825 else if (!lpcCount)
826 ret = WN_BAD_POINTER;
827 else if (!lpBuffer)
828 ret = WN_BAD_POINTER;
829 else if (!lpBufferSize)
830 ret = WN_BAD_POINTER;
831 else if (*lpBufferSize < sizeof(NETRESOURCEA))
832 {
833 *lpBufferSize = sizeof(NETRESOURCEA);
834 ret = WN_MORE_DATA;
835 }
836 else
837 {
838 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
839 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
840
841 if (localBuffer)
842 {
843 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
844 &localSize);
845 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
846 {
847 /* FIXME: this isn't necessarily going to work in the case of
848 * WN_MORE_DATA, because our enumerator may have moved on to
849 * the next provider. MSDN states that a large (16KB) buffer
850 * size is the appropriate usage of this function, so
851 * hopefully it won't be an issue.
852 */
853 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
854 lpBuffer, lpBufferSize);
855 *lpcCount = localCount;
856 }
857 HeapFree(GetProcessHeap(), 0, localBuffer);
858 }
859 else
860 ret = WN_OUT_OF_MEMORY;
861 }
862 if (ret)
863 SetLastError(ret);
864 TRACE("Returning %d\n", ret);
865 return ret;
866 }
867
868 static DWORD _countProviderBytesW(PWNetProvider provider)
869 {
870 DWORD ret;
871
872 if (provider)
873 {
874 ret = sizeof(NETRESOURCEW);
875 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
876 }
877 else
878 ret = 0;
879 return ret;
880 }
881
882 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
883 LPVOID lpBuffer, const DWORD *lpBufferSize)
884 {
885 DWORD ret;
886
887 if (!enumerator)
888 return WN_BAD_POINTER;
889 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
890 return WN_BAD_VALUE;
891 if (!lpcCount)
892 return WN_BAD_POINTER;
893 if (!lpBuffer)
894 return WN_BAD_POINTER;
895 if (!lpBufferSize)
896 return WN_BAD_POINTER;
897 if (*lpBufferSize < sizeof(NETRESOURCEA))
898 return WN_MORE_DATA;
899
900 if (!providerTable || enumerator->providerIndex >=
901 providerTable->numProviders)
902 ret = WN_NO_MORE_ENTRIES;
903 else
904 {
905 DWORD bytes = 0, count = 0, countLimit, i;
906 LPNETRESOURCEW resource;
907 LPWSTR strNext;
908
909 countLimit = *lpcCount == -1 ?
910 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
911 while (count < countLimit && bytes < *lpBufferSize)
912 {
913 DWORD bytesNext = _countProviderBytesW(
914 &providerTable->table[count + enumerator->providerIndex]);
915
916 if (bytes + bytesNext < *lpBufferSize)
917 {
918 bytes += bytesNext;
919 count++;
920 }
921 }
922 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
923 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
924 {
925 resource->dwScope = RESOURCE_GLOBALNET;
926 resource->dwType = RESOURCETYPE_ANY;
927 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
928 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
929 RESOURCEUSAGE_RESERVED;
930 resource->lpLocalName = NULL;
931 resource->lpRemoteName = strNext;
932 strcpyW(resource->lpRemoteName,
933 providerTable->table[i + enumerator->providerIndex].name);
934 strNext += strlenW(resource->lpRemoteName) + 1;
935 resource->lpComment = NULL;
936 resource->lpProvider = strNext;
937 strcpyW(resource->lpProvider,
938 providerTable->table[i + enumerator->providerIndex].name);
939 strNext += strlenW(resource->lpProvider) + 1;
940 }
941 enumerator->providerIndex += count;
942 *lpcCount = count;
943 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
944 }
945 TRACE("Returning %d\n", ret);
946 return ret;
947 }
948
949 /* Advances the enumerator (assumed to be a global enumerator) to the next
950 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
951 * not open a handle with the next provider.
952 * If the existing handle is NULL, may leave the enumerator unchanged, since
953 * the current provider may support the desired scope.
954 * If the existing handle is not NULL, closes it before moving on.
955 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
956 * provider, and another error on failure.
957 */
958 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
959 {
960 if (!enumerator)
961 return WN_BAD_POINTER;
962 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
963 return WN_BAD_VALUE;
964 if (!providerTable || enumerator->providerIndex >=
965 providerTable->numProviders)
966 return WN_NO_MORE_ENTRIES;
967
968 if (enumerator->providerDone)
969 {
970 DWORD dwEnum = 0;
971 enumerator->providerDone = FALSE;
972 if (enumerator->handle)
973 {
974 providerTable->table[enumerator->providerIndex].closeEnum(
975 enumerator->handle);
976 enumerator->handle = NULL;
977 enumerator->providerIndex++;
978 }
979 if (enumerator->dwScope == RESOURCE_CONNECTED)
980 dwEnum = WNNC_ENUM_LOCAL;
981 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
982 dwEnum = WNNC_ENUM_GLOBAL;
983 else if (enumerator->dwScope == RESOURCE_CONTEXT)
984 dwEnum = WNNC_ENUM_CONTEXT;
985 for (; enumerator->providerIndex < providerTable->numProviders &&
986 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
987 & dwEnum); enumerator->providerIndex++)
988 ;
989 }
990 return enumerator->providerIndex < providerTable->numProviders ?
991 WN_SUCCESS : WN_NO_MORE_ENTRIES;
992 }
993
994 /* "Passes through" call to the next provider that supports the enumeration
995 * type.
996 * FIXME: if one call to a provider's enumerator succeeds while there's still
997 * space in lpBuffer, I don't call to the next provider. The caller may not
998 * expect that it should call EnumResourceW again with a return value of
999 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1000 * may have to be moved around a bit, ick.
1001 */
1002 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1003 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1004 {
1005 DWORD ret;
1006
1007 if (!enumerator)
1008 return WN_BAD_POINTER;
1009 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1010 return WN_BAD_VALUE;
1011 if (!lpcCount)
1012 return WN_BAD_POINTER;
1013 if (!lpBuffer)
1014 return WN_BAD_POINTER;
1015 if (!lpBufferSize)
1016 return WN_BAD_POINTER;
1017 if (*lpBufferSize < sizeof(NETRESOURCEW))
1018 return WN_MORE_DATA;
1019
1020 ret = _globalEnumeratorAdvance(enumerator);
1021 if (ret == WN_SUCCESS)
1022 {
1023 ret = providerTable->table[enumerator->providerIndex].
1024 openEnum(enumerator->dwScope, enumerator->dwType,
1025 enumerator->dwUsage, enumerator->lpNet,
1026 &enumerator->handle);
1027 if (ret == WN_SUCCESS)
1028 {
1029 ret = providerTable->table[enumerator->providerIndex].
1030 enumResource(enumerator->handle, lpcCount, lpBuffer,
1031 lpBufferSize);
1032 if (ret != WN_MORE_DATA)
1033 enumerator->providerDone = TRUE;
1034 }
1035 }
1036 TRACE("Returning %d\n", ret);
1037 return ret;
1038 }
1039
1040 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1041 LPVOID lpBuffer, LPDWORD lpBufferSize)
1042 {
1043 DWORD ret;
1044
1045 if (!enumerator)
1046 return WN_BAD_POINTER;
1047 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1048 return WN_BAD_VALUE;
1049 if (!lpcCount)
1050 return WN_BAD_POINTER;
1051 if (!lpBuffer)
1052 return WN_BAD_POINTER;
1053 if (!lpBufferSize)
1054 return WN_BAD_POINTER;
1055 if (*lpBufferSize < sizeof(NETRESOURCEW))
1056 return WN_MORE_DATA;
1057 if (!providerTable)
1058 return WN_NO_NETWORK;
1059
1060 switch (enumerator->dwScope)
1061 {
1062 case RESOURCE_GLOBALNET:
1063 if (enumerator->lpNet)
1064 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1065 lpBuffer, lpBufferSize);
1066 else
1067 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1068 lpBufferSize);
1069 break;
1070 case RESOURCE_CONTEXT:
1071 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1072 lpBufferSize);
1073 break;
1074 default:
1075 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1076 ret = WN_NO_MORE_ENTRIES;
1077 }
1078 TRACE("Returning %d\n", ret);
1079 return ret;
1080 }
1081
1082 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1083 LPVOID lpBuffer, LPDWORD lpBufferSize)
1084 {
1085 if (!enumerator)
1086 return WN_BAD_POINTER;
1087 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1088 return WN_BAD_VALUE;
1089 if (!enumerator->handle)
1090 return WN_BAD_VALUE;
1091 if (!lpcCount)
1092 return WN_BAD_POINTER;
1093 if (!lpBuffer)
1094 return WN_BAD_POINTER;
1095 if (!lpBufferSize)
1096 return WN_BAD_POINTER;
1097 if (!providerTable)
1098 return WN_NO_NETWORK;
1099 if (enumerator->providerIndex >= providerTable->numProviders)
1100 return WN_NO_MORE_ENTRIES;
1101 if (!providerTable->table[enumerator->providerIndex].enumResource)
1102 return WN_BAD_VALUE;
1103 return providerTable->table[enumerator->providerIndex].enumResource(
1104 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1105 }
1106
1107 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1108 LPVOID lpBuffer, LPDWORD lpBufferSize)
1109 {
1110 DWORD ret;
1111 size_t cchEntireNetworkLen, bytesNeeded;
1112
1113 if (!enumerator)
1114 return WN_BAD_POINTER;
1115 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1116 return WN_BAD_VALUE;
1117 if (!lpcCount)
1118 return WN_BAD_POINTER;
1119 if (!lpBuffer)
1120 return WN_BAD_POINTER;
1121 if (!lpBufferSize)
1122 return WN_BAD_POINTER;
1123 if (!providerTable)
1124 return WN_NO_NETWORK;
1125
1126 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1127 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1128 if (*lpBufferSize < bytesNeeded)
1129 {
1130 *lpBufferSize = bytesNeeded;
1131 ret = WN_MORE_DATA;
1132 }
1133 else
1134 {
1135 LPNETRESOURCEW lpNet = lpBuffer;
1136
1137 lpNet->dwScope = RESOURCE_GLOBALNET;
1138 lpNet->dwType = enumerator->dwType;
1139 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1140 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1141 lpNet->lpLocalName = NULL;
1142 lpNet->lpRemoteName = NULL;
1143 lpNet->lpProvider = NULL;
1144 /* odd, but correct: put comment at end of buffer, so it won't get
1145 * overwritten by subsequent calls to a provider's enumResource
1146 */
1147 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1148 (cchEntireNetworkLen * sizeof(WCHAR)));
1149 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1150 ret = WN_SUCCESS;
1151 }
1152 if (ret == WN_SUCCESS)
1153 {
1154 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1155
1156 /* "Entire Network" entry enumerated--morph this into a global
1157 * enumerator. enumerator->lpNet continues to be NULL, since it has
1158 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1159 */
1160 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1161 ret = _enumerateGlobalW(enumerator, lpcCount,
1162 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1163 if (ret == WN_SUCCESS)
1164 {
1165 /* reflect the fact that we already enumerated "Entire Network" */
1166 (*lpcCount)++;
1167 *lpBufferSize = bufferSize + bytesNeeded;
1168 }
1169 else
1170 {
1171 /* the provider enumeration failed, but we already succeeded in
1172 * enumerating "Entire Network"--leave type as global to allow a
1173 * retry, but indicate success with a count of one.
1174 */
1175 ret = WN_SUCCESS;
1176 *lpcCount = 1;
1177 *lpBufferSize = bytesNeeded;
1178 }
1179 }
1180 TRACE("Returning %d\n", ret);
1181 return ret;
1182 }
1183
1184 /*********************************************************************
1185 * WNetEnumResourceW [MPR.@]
1186 */
1187 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1188 LPVOID lpBuffer, LPDWORD lpBufferSize )
1189 {
1190 DWORD ret;
1191
1192 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1193
1194 if (!hEnum)
1195 ret = WN_BAD_POINTER;
1196 else if (!lpcCount)
1197 ret = WN_BAD_POINTER;
1198 else if (!lpBuffer)
1199 ret = WN_BAD_POINTER;
1200 else if (!lpBufferSize)
1201 ret = WN_BAD_POINTER;
1202 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1203 {
1204 *lpBufferSize = sizeof(NETRESOURCEW);
1205 ret = WN_MORE_DATA;
1206 }
1207 else
1208 {
1209 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1210
1211 switch (enumerator->enumType)
1212 {
1213 case WNET_ENUMERATOR_TYPE_NULL:
1214 ret = WN_NO_MORE_ENTRIES;
1215 break;
1216 case WNET_ENUMERATOR_TYPE_GLOBAL:
1217 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1218 lpBufferSize);
1219 break;
1220 case WNET_ENUMERATOR_TYPE_PROVIDER:
1221 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1222 lpBufferSize);
1223 break;
1224 case WNET_ENUMERATOR_TYPE_CONTEXT:
1225 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1226 lpBufferSize);
1227 break;
1228 default:
1229 WARN("bogus enumerator type!\n");
1230 ret = WN_NO_NETWORK;
1231 }
1232 }
1233 if (ret)
1234 SetLastError(ret);
1235 TRACE("Returning %d\n", ret);
1236 return ret;
1237 }
1238
1239 /*********************************************************************
1240 * WNetCloseEnum [MPR.@]
1241 */
1242 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1243 {
1244 DWORD ret;
1245
1246 TRACE( "(%p)\n", hEnum );
1247
1248 if (hEnum)
1249 {
1250 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1251
1252 switch (enumerator->enumType)
1253 {
1254 case WNET_ENUMERATOR_TYPE_NULL:
1255 ret = WN_SUCCESS;
1256 break;
1257 case WNET_ENUMERATOR_TYPE_GLOBAL:
1258 if (enumerator->lpNet)
1259 _freeEnumNetResource(enumerator->lpNet);
1260 if (enumerator->handle)
1261 providerTable->table[enumerator->providerIndex].
1262 closeEnum(enumerator->handle);
1263 ret = WN_SUCCESS;
1264 break;
1265 case WNET_ENUMERATOR_TYPE_PROVIDER:
1266 if (enumerator->handle)
1267 providerTable->table[enumerator->providerIndex].
1268 closeEnum(enumerator->handle);
1269 ret = WN_SUCCESS;
1270 break;
1271 default:
1272 WARN("bogus enumerator type!\n");
1273 ret = WN_BAD_HANDLE;
1274 }
1275 HeapFree(GetProcessHeap(), 0, hEnum);
1276 }
1277 else
1278 ret = WN_BAD_HANDLE;
1279 if (ret)
1280 SetLastError(ret);
1281 TRACE("Returning %d\n", ret);
1282 return ret;
1283 }
1284
1285 /*********************************************************************
1286 * WNetGetResourceInformationA [MPR.@]
1287 *
1288 * See WNetGetResourceInformationW
1289 */
1290 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1291 LPVOID lpBuffer, LPDWORD cbBuffer,
1292 LPSTR *lplpSystem )
1293 {
1294 DWORD ret;
1295
1296 TRACE( "(%p, %p, %p, %p)\n",
1297 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1298
1299 if (!providerTable || providerTable->numProviders == 0)
1300 ret = WN_NO_NETWORK;
1301 else if (lpNetResource)
1302 {
1303 LPNETRESOURCEW lpNetResourceW = NULL;
1304 DWORD size = 1024, count = 1;
1305 DWORD len;
1306
1307 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1308 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1309 if (ret == WN_MORE_DATA)
1310 {
1311 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1312 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1313 if (lpNetResourceW)
1314 ret = _thunkNetResourceArrayAToW(lpNetResource,
1315 &count, lpNetResourceW, &size);
1316 else
1317 ret = WN_OUT_OF_MEMORY;
1318 }
1319 if (ret == WN_SUCCESS)
1320 {
1321 LPWSTR lpSystemW = NULL;
1322 LPVOID lpBufferW;
1323 size = 1024;
1324 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1325 if (lpBufferW)
1326 {
1327 ret = WNetGetResourceInformationW(lpNetResourceW,
1328 lpBufferW, &size, &lpSystemW);
1329 if (ret == WN_MORE_DATA)
1330 {
1331 HeapFree(GetProcessHeap(), 0, lpBufferW);
1332 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1333 if (lpBufferW)
1334 ret = WNetGetResourceInformationW(lpNetResourceW,
1335 lpBufferW, &size, &lpSystemW);
1336 else
1337 ret = WN_OUT_OF_MEMORY;
1338 }
1339 if (ret == WN_SUCCESS)
1340 {
1341 ret = _thunkNetResourceArrayWToA(lpBufferW,
1342 &count, lpBuffer, cbBuffer);
1343 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1344 lpNetResourceW = lpBufferW;
1345 size = sizeof(NETRESOURCEA);
1346 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1347 -1, NULL, 0, NULL, NULL);
1348 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1349 -1, NULL, 0, NULL, NULL);
1350
1351 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1352 -1, NULL, 0, NULL, NULL);
1353 if ((len) && ( size + len < *cbBuffer))
1354 {
1355 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1356 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1357 *lplpSystem, len, NULL, NULL);
1358 ret = WN_SUCCESS;
1359 }
1360 else
1361 ret = WN_MORE_DATA;
1362 }
1363 else
1364 ret = WN_OUT_OF_MEMORY;
1365 HeapFree(GetProcessHeap(), 0, lpBufferW);
1366 }
1367 else
1368 ret = WN_OUT_OF_MEMORY;
1369 HeapFree(GetProcessHeap(), 0, lpSystemW);
1370 }
1371 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1372 }
1373 else
1374 ret = WN_NO_NETWORK;
1375
1376 if (ret)
1377 SetLastError(ret);
1378 TRACE("Returning %d\n", ret);
1379 return ret;
1380 }
1381
1382 /*********************************************************************
1383 * WNetGetResourceInformationW [MPR.@]
1384 *
1385 * WNetGetResourceInformationW function identifies the network provider
1386 * that owns the resource and gets information about the type of the resource.
1387 *
1388 * PARAMS:
1389 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1390 * defines a network resource.
1391 * lpBuffer [ O] the pointer to buffer, containing result. It
1392 * contains NETRESOURCEW structure and strings to
1393 * which the members of the NETRESOURCEW structure
1394 * point.
1395 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1396 * in bytes.
1397 * lplpSystem [ O] the pointer to string in the output buffer,
1398 * containing the part of the resource name without
1399 * names of the server and share.
1400 *
1401 * RETURNS:
1402 * NO_ERROR if the function succeeds. System error code if the function fails.
1403 */
1404
1405 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1406 LPVOID lpBuffer, LPDWORD cbBuffer,
1407 LPWSTR *lplpSystem )
1408 {
1409 DWORD ret = WN_NO_NETWORK;
1410 DWORD index;
1411
1412 TRACE( "(%p, %p, %p, %p)\n",
1413 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1414
1415 if (!(lpBuffer))
1416 ret = WN_OUT_OF_MEMORY;
1417 else if (providerTable != NULL)
1418 {
1419 /* FIXME: For function value of a variable is indifferent, it does
1420 * search of all providers in a network.
1421 */
1422 for (index = 0; index < providerTable->numProviders; index++)
1423 {
1424 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1425 WNNC_DLG_GETRESOURCEINFORMATION)
1426 {
1427 if (providerTable->table[index].getResourceInformation)
1428 ret = providerTable->table[index].getResourceInformation(
1429 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1430 else
1431 ret = WN_NO_NETWORK;
1432 if (ret == WN_SUCCESS)
1433 break;
1434 }
1435 }
1436 }
1437 if (ret)
1438 SetLastError(ret);
1439 return ret;
1440 }
1441
1442 /*********************************************************************
1443 * WNetGetResourceParentA [MPR.@]
1444 */
1445 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1446 LPVOID lpBuffer, LPDWORD lpBufferSize )
1447 {
1448 FIXME( "(%p, %p, %p): stub\n",
1449 lpNetResource, lpBuffer, lpBufferSize );
1450
1451 SetLastError(WN_NO_NETWORK);
1452 return WN_NO_NETWORK;
1453 }
1454
1455 /*********************************************************************
1456 * WNetGetResourceParentW [MPR.@]
1457 */
1458 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1459 LPVOID lpBuffer, LPDWORD lpBufferSize )
1460 {
1461 FIXME( "(%p, %p, %p): stub\n",
1462 lpNetResource, lpBuffer, lpBufferSize );
1463
1464 SetLastError(WN_NO_NETWORK);
1465 return WN_NO_NETWORK;
1466 }
1467
1468
1469
1470 /*
1471 * Connection Functions
1472 */
1473
1474 /*********************************************************************
1475 * WNetAddConnectionA [MPR.@]
1476 */
1477 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1478 LPCSTR lpLocalName )
1479 {
1480 FIXME( "(%s, %p, %s): stub\n",
1481 debugstr_a(lpRemoteName), lpPassword, debugstr_a(lpLocalName) );
1482
1483 SetLastError(WN_NO_NETWORK);
1484 return WN_NO_NETWORK;
1485 }
1486
1487 /*********************************************************************
1488 * WNetAddConnectionW [MPR.@]
1489 */
1490 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1491 LPCWSTR lpLocalName )
1492 {
1493 FIXME( "(%s, %p, %s): stub\n",
1494 debugstr_w(lpRemoteName), lpPassword, debugstr_w(lpLocalName) );
1495
1496 SetLastError(WN_NO_NETWORK);
1497 return WN_NO_NETWORK;
1498 }
1499
1500 /*********************************************************************
1501 * WNetAddConnection2A [MPR.@]
1502 */
1503 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1504 LPCSTR lpPassword, LPCSTR lpUserID,
1505 DWORD dwFlags )
1506 {
1507 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1508 lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1509
1510 SetLastError(WN_NO_NETWORK);
1511 return WN_NO_NETWORK;
1512 }
1513
1514 /*********************************************************************
1515 * WNetAddConnection2W [MPR.@]
1516 */
1517 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1518 LPCWSTR lpPassword, LPCWSTR lpUserID,
1519 DWORD dwFlags )
1520 {
1521 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1522 lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1523
1524 SetLastError(WN_NO_NETWORK);
1525 return WN_NO_NETWORK;
1526 }
1527
1528 /*********************************************************************
1529 * WNetAddConnection3A [MPR.@]
1530 */
1531 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1532 LPCSTR lpPassword, LPCSTR lpUserID,
1533 DWORD dwFlags )
1534 {
1535 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1536 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1537
1538 SetLastError(WN_NO_NETWORK);
1539 return WN_NO_NETWORK;
1540 }
1541
1542 /*********************************************************************
1543 * WNetAddConnection3W [MPR.@]
1544 */
1545 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1546 LPCWSTR lpPassword, LPCWSTR lpUserID,
1547 DWORD dwFlags )
1548 {
1549 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1550 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1551
1552 SetLastError(WN_NO_NETWORK);
1553 return WN_NO_NETWORK;
1554 }
1555
1556 /*****************************************************************
1557 * WNetUseConnectionA [MPR.@]
1558 */
1559 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1560 LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
1561 LPSTR lpAccessName, LPDWORD lpBufferSize,
1562 LPDWORD lpResult )
1563 {
1564 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1565 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags,
1566 debugstr_a(lpAccessName), lpBufferSize, lpResult );
1567
1568 SetLastError(WN_NO_NETWORK);
1569 return WN_NO_NETWORK;
1570 }
1571
1572 /*****************************************************************
1573 * WNetUseConnectionW [MPR.@]
1574 */
1575 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1576 LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags,
1577 LPWSTR lpAccessName, LPDWORD lpBufferSize,
1578 LPDWORD lpResult )
1579 {
1580 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1581 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags,
1582 debugstr_w(lpAccessName), lpBufferSize, lpResult );
1583
1584 SetLastError(WN_NO_NETWORK);
1585 return WN_NO_NETWORK;
1586 }
1587
1588 /*********************************************************************
1589 * WNetCancelConnectionA [MPR.@]
1590 */
1591 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1592 {
1593 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1594
1595 return WN_SUCCESS;
1596 }
1597
1598 /*********************************************************************
1599 * WNetCancelConnectionW [MPR.@]
1600 */
1601 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1602 {
1603 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1604
1605 return WN_SUCCESS;
1606 }
1607
1608 /*********************************************************************
1609 * WNetCancelConnection2A [MPR.@]
1610 */
1611 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1612 {
1613 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1614
1615 return WN_SUCCESS;
1616 }
1617
1618 /*********************************************************************
1619 * WNetCancelConnection2W [MPR.@]
1620 */
1621 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1622 {
1623 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1624
1625 return WN_SUCCESS;
1626 }
1627
1628 /*****************************************************************
1629 * WNetRestoreConnectionA [MPR.@]
1630 */
1631 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
1632 {
1633 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1634
1635 SetLastError(WN_NO_NETWORK);
1636 return WN_NO_NETWORK;
1637 }
1638
1639 /*****************************************************************
1640 * WNetRestoreConnectionW [MPR.@]
1641 */
1642 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
1643 {
1644 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1645
1646 SetLastError(WN_NO_NETWORK);
1647 return WN_NO_NETWORK;
1648 }
1649
1650 /**************************************************************************
1651 * WNetGetConnectionA [MPR.@]
1652 *
1653 * RETURNS
1654 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1655 * - WN_NOT_CONNECTED drive is a local drive
1656 * - WN_MORE_DATA buffer isn't big enough
1657 * - WN_SUCCESS success (net path in buffer)
1658 *
1659 * FIXME: need to test return values under different errors
1660 */
1661 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1662 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1663 {
1664 DWORD ret;
1665
1666 if (!lpLocalName)
1667 ret = WN_BAD_POINTER;
1668 else if (!lpBufferSize)
1669 ret = WN_BAD_POINTER;
1670 else if (!lpRemoteName && *lpBufferSize)
1671 ret = WN_BAD_POINTER;
1672 else
1673 {
1674 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1675
1676 if (len)
1677 {
1678 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1679
1680 if (wideLocalName)
1681 {
1682 WCHAR wideRemoteStatic[MAX_PATH];
1683 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1684
1685 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1686
1687 /* try once without memory allocation */
1688 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1689 &wideRemoteSize);
1690 if (ret == WN_SUCCESS)
1691 {
1692 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1693 -1, NULL, 0, NULL, NULL);
1694
1695 if (len <= *lpBufferSize)
1696 {
1697 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1698 lpRemoteName, *lpBufferSize, NULL, NULL);
1699 ret = WN_SUCCESS;
1700 }
1701 else
1702 {
1703 *lpBufferSize = len;
1704 ret = WN_MORE_DATA;
1705 }
1706 }
1707 else if (ret == WN_MORE_DATA)
1708 {
1709 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1710 wideRemoteSize * sizeof(WCHAR));
1711
1712 if (wideRemote)
1713 {
1714 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1715 &wideRemoteSize);
1716 if (ret == WN_SUCCESS)
1717 {
1718 if (len <= *lpBufferSize)
1719 {
1720 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1721 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1722 ret = WN_SUCCESS;
1723 }
1724 else
1725 {
1726 *lpBufferSize = len;
1727 ret = WN_MORE_DATA;
1728 }
1729 }
1730 HeapFree(GetProcessHeap(), 0, wideRemote);
1731 }
1732 else
1733 ret = WN_OUT_OF_MEMORY;
1734 }
1735 HeapFree(GetProcessHeap(), 0, wideLocalName);
1736 }
1737 else
1738 ret = WN_OUT_OF_MEMORY;
1739 }
1740 else
1741 ret = WN_BAD_LOCALNAME;
1742 }
1743 if (ret)
1744 SetLastError(ret);
1745 TRACE("Returning %d\n", ret);
1746 return ret;
1747 }
1748
1749 /* find the network connection for a given drive; helper for WNetGetConnection */
1750 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
1751 {
1752 char buffer[1024];
1753 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
1754 HANDLE mgr;
1755 DWORD ret = WN_NOT_CONNECTED;
1756 DWORD bytes_returned;
1757
1758 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
1759 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1760 0, 0 )) == INVALID_HANDLE_VALUE)
1761 {
1762 ERR( "failed to open mount manager err %u\n", GetLastError() );
1763 return ret;
1764 }
1765 memset( data, 0, sizeof(*data) );
1766 data->letter = letter;
1767 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
1768 data, sizeof(buffer), &bytes_returned, NULL ))
1769 {
1770 char *p, *mount_point = buffer + data->mount_point_offset;
1771 DWORD len;
1772
1773 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
1774 {
1775 mount_point += 2;
1776 mount_point[0] = '\\';
1777 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
1778
1779 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
1780 if (len > *size)
1781 {
1782 *size = len;
1783 ret = WN_MORE_DATA;
1784 }
1785 else
1786 {
1787 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
1788 ret = WN_SUCCESS;
1789 }
1790 }
1791 }
1792 CloseHandle( mgr );
1793 return ret;
1794 }
1795
1796 /**************************************************************************
1797 * WNetGetConnectionW [MPR.@]
1798 *
1799 * FIXME: need to test return values under different errors
1800 */
1801 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
1802 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
1803 {
1804 DWORD ret;
1805
1806 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
1807 lpBufferSize);
1808
1809 if (!lpLocalName)
1810 ret = WN_BAD_POINTER;
1811 else if (!lpBufferSize)
1812 ret = WN_BAD_POINTER;
1813 else if (!lpRemoteName && *lpBufferSize)
1814 ret = WN_BAD_POINTER;
1815 else if (!lpLocalName[0])
1816 ret = WN_BAD_LOCALNAME;
1817 else
1818 {
1819 if (lpLocalName[1] == ':')
1820 {
1821 switch(GetDriveTypeW(lpLocalName))
1822 {
1823 case DRIVE_REMOTE:
1824 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
1825 break;
1826 case DRIVE_REMOVABLE:
1827 case DRIVE_FIXED:
1828 case DRIVE_CDROM:
1829 TRACE("file is local\n");
1830 ret = WN_NOT_CONNECTED;
1831 break;
1832 default:
1833 ret = WN_BAD_LOCALNAME;
1834 }
1835 }
1836 else
1837 ret = WN_BAD_LOCALNAME;
1838 }
1839 if (ret)
1840 SetLastError(ret);
1841 TRACE("Returning %d\n", ret);
1842 return ret;
1843 }
1844
1845 /**************************************************************************
1846 * WNetSetConnectionA [MPR.@]
1847 */
1848 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
1849 LPVOID pvValue )
1850 {
1851 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
1852
1853 SetLastError(WN_NO_NETWORK);
1854 return WN_NO_NETWORK;
1855 }
1856
1857 /**************************************************************************
1858 * WNetSetConnectionW [MPR.@]
1859 */
1860 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
1861 LPVOID pvValue )
1862 {
1863 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
1864
1865 SetLastError(WN_NO_NETWORK);
1866 return WN_NO_NETWORK;
1867 }
1868
1869 /*****************************************************************
1870 * WNetGetUniversalNameA [MPR.@]
1871 */
1872 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
1873 LPVOID lpBuffer, LPDWORD lpBufferSize )
1874 {
1875 DWORD err, size;
1876
1877 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1878 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1879
1880 switch (dwInfoLevel)
1881 {
1882 case UNIVERSAL_NAME_INFO_LEVEL:
1883 {
1884 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
1885
1886 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
1887 {
1888 err = ERROR_NOT_CONNECTED;
1889 break;
1890 }
1891
1892 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
1893 if (*lpBufferSize < size)
1894 {
1895 err = WN_MORE_DATA;
1896 break;
1897 }
1898 info->lpUniversalName = (char *)info + sizeof(*info);
1899 lstrcpyA(info->lpUniversalName, lpLocalPath);
1900 err = WN_NO_ERROR;
1901 break;
1902 }
1903 case REMOTE_NAME_INFO_LEVEL:
1904 err = WN_NO_NETWORK;
1905 break;
1906
1907 default:
1908 err = WN_BAD_VALUE;
1909 break;
1910 }
1911
1912 SetLastError(err);
1913 return err;
1914 }
1915
1916 /*****************************************************************
1917 * WNetGetUniversalNameW [MPR.@]
1918 */
1919 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
1920 LPVOID lpBuffer, LPDWORD lpBufferSize )
1921 {
1922 DWORD err, size;
1923
1924 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1925 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1926
1927 switch (dwInfoLevel)
1928 {
1929 case UNIVERSAL_NAME_INFO_LEVEL:
1930 {
1931 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
1932
1933 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
1934 {
1935 err = ERROR_NOT_CONNECTED;
1936 break;
1937 }
1938
1939 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
1940 if (*lpBufferSize < size)
1941 {
1942 err = WN_MORE_DATA;
1943 break;
1944 }
1945 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
1946 lstrcpyW(info->lpUniversalName, lpLocalPath);
1947 err = WN_NO_ERROR;
1948 break;
1949 }
1950 case REMOTE_NAME_INFO_LEVEL:
1951 err = WN_NOT_CONNECTED;
1952 break;
1953
1954 default:
1955 err = WN_BAD_VALUE;
1956 break;
1957 }
1958
1959 if (err != WN_NO_ERROR) SetLastError(err);
1960 return err;
1961 }
1962
1963
1964
1965 /*
1966 * Other Functions
1967 */
1968
1969 /**************************************************************************
1970 * WNetGetUserA [MPR.@]
1971 *
1972 * FIXME: we should not return ourselves, but the owner of the drive lpName
1973 */
1974 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
1975 {
1976 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
1977 return GetLastError();
1978 }
1979
1980 /*****************************************************************
1981 * WNetGetUserW [MPR.@]
1982 *
1983 * FIXME: we should not return ourselves, but the owner of the drive lpName
1984 */
1985 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
1986 {
1987 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
1988 return GetLastError();
1989 }
1990
1991 /*********************************************************************
1992 * WNetConnectionDialog [MPR.@]
1993 */
1994 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
1995 {
1996 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
1997
1998 SetLastError(WN_NO_NETWORK);
1999 return WN_NO_NETWORK;
2000 }
2001
2002 /*********************************************************************
2003 * WNetConnectionDialog1A [MPR.@]
2004 */
2005 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2006 {
2007 FIXME( "(%p): stub\n", lpConnDlgStruct );
2008
2009 SetLastError(WN_NO_NETWORK);
2010 return WN_NO_NETWORK;
2011 }
2012
2013 /*********************************************************************
2014 * WNetConnectionDialog1W [MPR.@]
2015 */
2016 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2017 {
2018 FIXME( "(%p): stub\n", lpConnDlgStruct );
2019
2020 SetLastError(WN_NO_NETWORK);
2021 return WN_NO_NETWORK;
2022 }
2023
2024 /*********************************************************************
2025 * WNetDisconnectDialog [MPR.@]
2026 */
2027 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2028 {
2029 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2030
2031 SetLastError(WN_NO_NETWORK);
2032 return WN_NO_NETWORK;
2033 }
2034
2035 /*********************************************************************
2036 * WNetDisconnectDialog1A [MPR.@]
2037 */
2038 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2039 {
2040 FIXME( "(%p): stub\n", lpConnDlgStruct );
2041
2042 SetLastError(WN_NO_NETWORK);
2043 return WN_NO_NETWORK;
2044 }
2045
2046 /*********************************************************************
2047 * WNetDisconnectDialog1W [MPR.@]
2048 */
2049 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2050 {
2051 FIXME( "(%p): stub\n", lpConnDlgStruct );
2052
2053 SetLastError(WN_NO_NETWORK);
2054 return WN_NO_NETWORK;
2055 }
2056
2057 /*********************************************************************
2058 * WNetGetLastErrorA [MPR.@]
2059 */
2060 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2061 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2062 LPSTR lpNameBuf, DWORD nNameBufSize )
2063 {
2064 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2065 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2066
2067 SetLastError(WN_NO_NETWORK);
2068 return WN_NO_NETWORK;
2069 }
2070
2071 /*********************************************************************
2072 * WNetGetLastErrorW [MPR.@]
2073 */
2074 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2075 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2076 LPWSTR lpNameBuf, DWORD nNameBufSize )
2077 {
2078 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2079 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2080
2081 SetLastError(WN_NO_NETWORK);
2082 return WN_NO_NETWORK;
2083 }
2084
2085 /*********************************************************************
2086 * WNetGetNetworkInformationA [MPR.@]
2087 */
2088 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2089 LPNETINFOSTRUCT lpNetInfoStruct )
2090 {
2091 DWORD ret;
2092
2093 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2094
2095 if (!lpProvider)
2096 ret = WN_BAD_POINTER;
2097 else
2098 {
2099 int len;
2100
2101 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2102 if (len)
2103 {
2104 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2105
2106 if (wideProvider)
2107 {
2108 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2109 len);
2110 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2111 HeapFree(GetProcessHeap(), 0, wideProvider);
2112 }
2113 else
2114 ret = WN_OUT_OF_MEMORY;
2115 }
2116 else
2117 ret = GetLastError();
2118 }
2119 if (ret)
2120 SetLastError(ret);
2121 TRACE("Returning %d\n", ret);
2122 return ret;
2123 }
2124
2125 /*********************************************************************
2126 * WNetGetNetworkInformationW [MPR.@]
2127 */
2128 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2129 LPNETINFOSTRUCT lpNetInfoStruct )
2130 {
2131 DWORD ret;
2132
2133 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2134
2135 if (!lpProvider)
2136 ret = WN_BAD_POINTER;
2137 else if (!lpNetInfoStruct)
2138 ret = WN_BAD_POINTER;
2139 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2140 ret = WN_BAD_VALUE;
2141 else
2142 {
2143 if (providerTable && providerTable->numProviders)
2144 {
2145 DWORD providerIndex = _findProviderIndexW(lpProvider);
2146
2147 if (providerIndex != BAD_PROVIDER_INDEX)
2148 {
2149 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2150 lpNetInfoStruct->dwProviderVersion =
2151 providerTable->table[providerIndex].dwSpecVersion;
2152 lpNetInfoStruct->dwStatus = NO_ERROR;
2153 lpNetInfoStruct->dwCharacteristics = 0;
2154 lpNetInfoStruct->dwHandle = 0;
2155 lpNetInfoStruct->wNetType =
2156 HIWORD(providerTable->table[providerIndex].dwNetType);
2157 lpNetInfoStruct->dwPrinters = -1;
2158 lpNetInfoStruct->dwDrives = -1;
2159 ret = WN_SUCCESS;
2160 }
2161 else
2162 ret = WN_BAD_PROVIDER;
2163 }
2164 else
2165 ret = WN_NO_NETWORK;
2166 }
2167 if (ret)
2168 SetLastError(ret);
2169 TRACE("Returning %d\n", ret);
2170 return ret;
2171 }
2172
2173 /*****************************************************************
2174 * WNetGetProviderNameA [MPR.@]
2175 */
2176 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2177 LPSTR lpProvider, LPDWORD lpBufferSize )
2178 {
2179 DWORD ret;
2180
2181 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2182 lpBufferSize);
2183
2184 if (!lpProvider)
2185 ret = WN_BAD_POINTER;
2186 else if (!lpBufferSize)
2187 ret = WN_BAD_POINTER;
2188 else
2189 {
2190 if (providerTable)
2191 {
2192 DWORD i;
2193
2194 ret = WN_NO_NETWORK;
2195 for (i = 0; i < providerTable->numProviders &&
2196 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2197 i++)
2198 ;
2199 if (i < providerTable->numProviders)
2200 {
2201 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2202 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2203
2204 if (*lpBufferSize < sizeNeeded)
2205 {
2206 *lpBufferSize = sizeNeeded;
2207 ret = WN_MORE_DATA;
2208 }
2209 else
2210 {
2211 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2212 -1, lpProvider, *lpBufferSize, NULL, NULL);
2213 ret = WN_SUCCESS;
2214 /* FIXME: is *lpBufferSize set to the number of characters
2215 * copied? */
2216 }
2217 }
2218 }
2219 else
2220 ret = WN_NO_NETWORK;
2221 }
2222 if (ret)
2223 SetLastError(ret);
2224 TRACE("Returning %d\n", ret);
2225 return ret;
2226 }
2227
2228 /*****************************************************************
2229 * WNetGetProviderNameW [MPR.@]
2230 */
2231 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2232 LPWSTR lpProvider, LPDWORD lpBufferSize )
2233 {
2234 DWORD ret;
2235
2236 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2237 lpBufferSize);
2238
2239 if (!lpProvider)
2240 ret = WN_BAD_POINTER;
2241 else if (!lpBufferSize)
2242 ret = WN_BAD_POINTER;
2243 else
2244 {
2245 if (providerTable)
2246 {
2247 DWORD i;
2248
2249 ret = WN_NO_NETWORK;
2250 for (i = 0; i < providerTable->numProviders &&
2251 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2252 i++)
2253 ;
2254 if (i < providerTable->numProviders)
2255 {
2256 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2257
2258 if (*lpBufferSize < sizeNeeded)
2259 {
2260 *lpBufferSize = sizeNeeded;
2261 ret = WN_MORE_DATA;
2262 }
2263 else
2264 {
2265 strcpyW(lpProvider, providerTable->table[i].name);
2266 ret = WN_SUCCESS;
2267 /* FIXME: is *lpBufferSize set to the number of characters
2268 * copied? */
2269 }
2270 }
2271 }
2272 else
2273 ret = WN_NO_NETWORK;
2274 }
2275 if (ret)
2276 SetLastError(ret);
2277 TRACE("Returning %d\n", ret);
2278 return ret;
2279 }