[MPR]
[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 NETRESOURCEA resourcesA;
1481
1482 memset(&resourcesA, 0, sizeof(resourcesA));
1483 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1484 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1485 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1486 }
1487
1488 /*********************************************************************
1489 * WNetAddConnectionW [MPR.@]
1490 */
1491 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1492 LPCWSTR lpLocalName )
1493 {
1494 NETRESOURCEW resourcesW;
1495
1496 memset(&resourcesW, 0, sizeof(resourcesW));
1497 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1498 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1499 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1500 }
1501
1502 /*********************************************************************
1503 * WNetAddConnection2A [MPR.@]
1504 */
1505 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1506 LPCSTR lpPassword, LPCSTR lpUserID,
1507 DWORD dwFlags )
1508 {
1509 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1510 NULL, 0, NULL);
1511 }
1512
1513 /*********************************************************************
1514 * WNetAddConnection2W [MPR.@]
1515 */
1516 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1517 LPCWSTR lpPassword, LPCWSTR lpUserID,
1518 DWORD dwFlags )
1519 {
1520 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1521 NULL, 0, NULL);
1522 }
1523
1524 /*********************************************************************
1525 * WNetAddConnection3A [MPR.@]
1526 */
1527 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1528 LPCSTR lpPassword, LPCSTR lpUserID,
1529 DWORD dwFlags )
1530 {
1531 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1532 dwFlags, NULL, 0, NULL);
1533 }
1534
1535 /*********************************************************************
1536 * WNetAddConnection3W [MPR.@]
1537 */
1538 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1539 LPCWSTR lpPassword, LPCWSTR lpUserID,
1540 DWORD dwFlags )
1541 {
1542 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1543 dwFlags, NULL, 0, NULL);
1544 }
1545
1546 /*****************************************************************
1547 * WNetUseConnectionA [MPR.@]
1548 */
1549 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1550 LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
1551 LPSTR lpAccessName, LPDWORD lpBufferSize,
1552 LPDWORD lpResult )
1553 {
1554 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1555 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags,
1556 debugstr_a(lpAccessName), lpBufferSize, lpResult );
1557
1558 SetLastError(WN_NO_NETWORK);
1559 return WN_NO_NETWORK;
1560 }
1561
1562 /*****************************************************************
1563 * WNetUseConnectionW [MPR.@]
1564 */
1565 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1566 LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags,
1567 LPWSTR lpAccessName, LPDWORD lpBufferSize,
1568 LPDWORD lpResult )
1569 {
1570 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1571 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags,
1572 debugstr_w(lpAccessName), lpBufferSize, lpResult );
1573
1574 SetLastError(WN_NO_NETWORK);
1575 return WN_NO_NETWORK;
1576 }
1577
1578 /*********************************************************************
1579 * WNetCancelConnectionA [MPR.@]
1580 */
1581 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1582 {
1583 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1584
1585 return WN_SUCCESS;
1586 }
1587
1588 /*********************************************************************
1589 * WNetCancelConnectionW [MPR.@]
1590 */
1591 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1592 {
1593 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1594
1595 return WN_SUCCESS;
1596 }
1597
1598 /*********************************************************************
1599 * WNetCancelConnection2A [MPR.@]
1600 */
1601 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1602 {
1603 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1604
1605 return WN_SUCCESS;
1606 }
1607
1608 /*********************************************************************
1609 * WNetCancelConnection2W [MPR.@]
1610 */
1611 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1612 {
1613 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1614
1615 return WN_SUCCESS;
1616 }
1617
1618 /*****************************************************************
1619 * WNetRestoreConnectionA [MPR.@]
1620 */
1621 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
1622 {
1623 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1624
1625 SetLastError(WN_NO_NETWORK);
1626 return WN_NO_NETWORK;
1627 }
1628
1629 /*****************************************************************
1630 * WNetRestoreConnectionW [MPR.@]
1631 */
1632 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
1633 {
1634 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1635
1636 SetLastError(WN_NO_NETWORK);
1637 return WN_NO_NETWORK;
1638 }
1639
1640 /**************************************************************************
1641 * WNetGetConnectionA [MPR.@]
1642 *
1643 * RETURNS
1644 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1645 * - WN_NOT_CONNECTED drive is a local drive
1646 * - WN_MORE_DATA buffer isn't big enough
1647 * - WN_SUCCESS success (net path in buffer)
1648 *
1649 * FIXME: need to test return values under different errors
1650 */
1651 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1652 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1653 {
1654 DWORD ret;
1655
1656 if (!lpLocalName)
1657 ret = WN_BAD_POINTER;
1658 else if (!lpBufferSize)
1659 ret = WN_BAD_POINTER;
1660 else if (!lpRemoteName && *lpBufferSize)
1661 ret = WN_BAD_POINTER;
1662 else
1663 {
1664 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1665
1666 if (len)
1667 {
1668 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1669
1670 if (wideLocalName)
1671 {
1672 WCHAR wideRemoteStatic[MAX_PATH];
1673 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1674
1675 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1676
1677 /* try once without memory allocation */
1678 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1679 &wideRemoteSize);
1680 if (ret == WN_SUCCESS)
1681 {
1682 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1683 -1, NULL, 0, NULL, NULL);
1684
1685 if (len <= *lpBufferSize)
1686 {
1687 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1688 lpRemoteName, *lpBufferSize, NULL, NULL);
1689 ret = WN_SUCCESS;
1690 }
1691 else
1692 {
1693 *lpBufferSize = len;
1694 ret = WN_MORE_DATA;
1695 }
1696 }
1697 else if (ret == WN_MORE_DATA)
1698 {
1699 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1700 wideRemoteSize * sizeof(WCHAR));
1701
1702 if (wideRemote)
1703 {
1704 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1705 &wideRemoteSize);
1706 if (ret == WN_SUCCESS)
1707 {
1708 if (len <= *lpBufferSize)
1709 {
1710 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1711 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1712 ret = WN_SUCCESS;
1713 }
1714 else
1715 {
1716 *lpBufferSize = len;
1717 ret = WN_MORE_DATA;
1718 }
1719 }
1720 HeapFree(GetProcessHeap(), 0, wideRemote);
1721 }
1722 else
1723 ret = WN_OUT_OF_MEMORY;
1724 }
1725 HeapFree(GetProcessHeap(), 0, wideLocalName);
1726 }
1727 else
1728 ret = WN_OUT_OF_MEMORY;
1729 }
1730 else
1731 ret = WN_BAD_LOCALNAME;
1732 }
1733 if (ret)
1734 SetLastError(ret);
1735 TRACE("Returning %d\n", ret);
1736 return ret;
1737 }
1738
1739 /* find the network connection for a given drive; helper for WNetGetConnection */
1740 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
1741 {
1742 char buffer[1024];
1743 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
1744 HANDLE mgr;
1745 DWORD ret = WN_NOT_CONNECTED;
1746 DWORD bytes_returned;
1747
1748 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
1749 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1750 0, 0 )) == INVALID_HANDLE_VALUE)
1751 {
1752 ERR( "failed to open mount manager err %u\n", GetLastError() );
1753 return ret;
1754 }
1755 memset( data, 0, sizeof(*data) );
1756 data->letter = letter;
1757 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
1758 data, sizeof(buffer), &bytes_returned, NULL ))
1759 {
1760 char *p, *mount_point = buffer + data->mount_point_offset;
1761 DWORD len;
1762
1763 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
1764 {
1765 mount_point += 2;
1766 mount_point[0] = '\\';
1767 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
1768
1769 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
1770 if (len > *size)
1771 {
1772 *size = len;
1773 ret = WN_MORE_DATA;
1774 }
1775 else
1776 {
1777 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
1778 ret = WN_SUCCESS;
1779 }
1780 }
1781 }
1782 CloseHandle( mgr );
1783 return ret;
1784 }
1785
1786 /**************************************************************************
1787 * WNetGetConnectionW [MPR.@]
1788 *
1789 * FIXME: need to test return values under different errors
1790 */
1791 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
1792 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
1793 {
1794 DWORD ret;
1795
1796 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
1797 lpBufferSize);
1798
1799 if (!lpLocalName)
1800 ret = WN_BAD_POINTER;
1801 else if (!lpBufferSize)
1802 ret = WN_BAD_POINTER;
1803 else if (!lpRemoteName && *lpBufferSize)
1804 ret = WN_BAD_POINTER;
1805 else if (!lpLocalName[0])
1806 ret = WN_BAD_LOCALNAME;
1807 else
1808 {
1809 if (lpLocalName[1] == ':')
1810 {
1811 switch(GetDriveTypeW(lpLocalName))
1812 {
1813 case DRIVE_REMOTE:
1814 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
1815 break;
1816 case DRIVE_REMOVABLE:
1817 case DRIVE_FIXED:
1818 case DRIVE_CDROM:
1819 TRACE("file is local\n");
1820 ret = WN_NOT_CONNECTED;
1821 break;
1822 default:
1823 ret = WN_BAD_LOCALNAME;
1824 }
1825 }
1826 else
1827 ret = WN_BAD_LOCALNAME;
1828 }
1829 if (ret)
1830 SetLastError(ret);
1831 TRACE("Returning %d\n", ret);
1832 return ret;
1833 }
1834
1835 /**************************************************************************
1836 * WNetSetConnectionA [MPR.@]
1837 */
1838 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
1839 LPVOID pvValue )
1840 {
1841 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
1842
1843 SetLastError(WN_NO_NETWORK);
1844 return WN_NO_NETWORK;
1845 }
1846
1847 /**************************************************************************
1848 * WNetSetConnectionW [MPR.@]
1849 */
1850 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
1851 LPVOID pvValue )
1852 {
1853 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
1854
1855 SetLastError(WN_NO_NETWORK);
1856 return WN_NO_NETWORK;
1857 }
1858
1859 /*****************************************************************
1860 * WNetGetUniversalNameA [MPR.@]
1861 */
1862 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
1863 LPVOID lpBuffer, LPDWORD lpBufferSize )
1864 {
1865 DWORD err, size;
1866
1867 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1868 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1869
1870 switch (dwInfoLevel)
1871 {
1872 case UNIVERSAL_NAME_INFO_LEVEL:
1873 {
1874 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
1875
1876 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
1877 {
1878 err = ERROR_NOT_CONNECTED;
1879 break;
1880 }
1881
1882 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
1883 if (*lpBufferSize < size)
1884 {
1885 err = WN_MORE_DATA;
1886 break;
1887 }
1888 info->lpUniversalName = (char *)info + sizeof(*info);
1889 lstrcpyA(info->lpUniversalName, lpLocalPath);
1890 err = WN_NO_ERROR;
1891 break;
1892 }
1893 case REMOTE_NAME_INFO_LEVEL:
1894 err = WN_NO_NETWORK;
1895 break;
1896
1897 default:
1898 err = WN_BAD_VALUE;
1899 break;
1900 }
1901
1902 SetLastError(err);
1903 return err;
1904 }
1905
1906 /*****************************************************************
1907 * WNetGetUniversalNameW [MPR.@]
1908 */
1909 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
1910 LPVOID lpBuffer, LPDWORD lpBufferSize )
1911 {
1912 DWORD err, size;
1913
1914 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1915 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1916
1917 switch (dwInfoLevel)
1918 {
1919 case UNIVERSAL_NAME_INFO_LEVEL:
1920 {
1921 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
1922
1923 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
1924 {
1925 err = ERROR_NOT_CONNECTED;
1926 break;
1927 }
1928
1929 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
1930 if (*lpBufferSize < size)
1931 {
1932 err = WN_MORE_DATA;
1933 break;
1934 }
1935 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
1936 lstrcpyW(info->lpUniversalName, lpLocalPath);
1937 err = WN_NO_ERROR;
1938 break;
1939 }
1940 case REMOTE_NAME_INFO_LEVEL:
1941 err = WN_NOT_CONNECTED;
1942 break;
1943
1944 default:
1945 err = WN_BAD_VALUE;
1946 break;
1947 }
1948
1949 if (err != WN_NO_ERROR) SetLastError(err);
1950 return err;
1951 }
1952
1953
1954
1955 /*
1956 * Other Functions
1957 */
1958
1959 /**************************************************************************
1960 * WNetGetUserA [MPR.@]
1961 *
1962 * FIXME: we should not return ourselves, but the owner of the drive lpName
1963 */
1964 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
1965 {
1966 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
1967 return GetLastError();
1968 }
1969
1970 /*****************************************************************
1971 * WNetGetUserW [MPR.@]
1972 *
1973 * FIXME: we should not return ourselves, but the owner of the drive lpName
1974 */
1975 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
1976 {
1977 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
1978 return GetLastError();
1979 }
1980
1981 /*********************************************************************
1982 * WNetConnectionDialog [MPR.@]
1983 */
1984 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
1985 {
1986 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
1987
1988 SetLastError(WN_NO_NETWORK);
1989 return WN_NO_NETWORK;
1990 }
1991
1992 /*********************************************************************
1993 * WNetConnectionDialog1A [MPR.@]
1994 */
1995 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
1996 {
1997 FIXME( "(%p): stub\n", lpConnDlgStruct );
1998
1999 SetLastError(WN_NO_NETWORK);
2000 return WN_NO_NETWORK;
2001 }
2002
2003 /*********************************************************************
2004 * WNetConnectionDialog1W [MPR.@]
2005 */
2006 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2007 {
2008 FIXME( "(%p): stub\n", lpConnDlgStruct );
2009
2010 SetLastError(WN_NO_NETWORK);
2011 return WN_NO_NETWORK;
2012 }
2013
2014 /*********************************************************************
2015 * WNetDisconnectDialog [MPR.@]
2016 */
2017 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2018 {
2019 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2020
2021 SetLastError(WN_NO_NETWORK);
2022 return WN_NO_NETWORK;
2023 }
2024
2025 /*********************************************************************
2026 * WNetDisconnectDialog1A [MPR.@]
2027 */
2028 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2029 {
2030 FIXME( "(%p): stub\n", lpConnDlgStruct );
2031
2032 SetLastError(WN_NO_NETWORK);
2033 return WN_NO_NETWORK;
2034 }
2035
2036 /*********************************************************************
2037 * WNetDisconnectDialog1W [MPR.@]
2038 */
2039 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2040 {
2041 FIXME( "(%p): stub\n", lpConnDlgStruct );
2042
2043 SetLastError(WN_NO_NETWORK);
2044 return WN_NO_NETWORK;
2045 }
2046
2047 /*********************************************************************
2048 * WNetGetLastErrorA [MPR.@]
2049 */
2050 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2051 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2052 LPSTR lpNameBuf, DWORD nNameBufSize )
2053 {
2054 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2055 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2056
2057 SetLastError(WN_NO_NETWORK);
2058 return WN_NO_NETWORK;
2059 }
2060
2061 /*********************************************************************
2062 * WNetGetLastErrorW [MPR.@]
2063 */
2064 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2065 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2066 LPWSTR lpNameBuf, DWORD nNameBufSize )
2067 {
2068 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2069 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2070
2071 SetLastError(WN_NO_NETWORK);
2072 return WN_NO_NETWORK;
2073 }
2074
2075 /*********************************************************************
2076 * WNetGetNetworkInformationA [MPR.@]
2077 */
2078 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2079 LPNETINFOSTRUCT lpNetInfoStruct )
2080 {
2081 DWORD ret;
2082
2083 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2084
2085 if (!lpProvider)
2086 ret = WN_BAD_POINTER;
2087 else
2088 {
2089 int len;
2090
2091 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2092 if (len)
2093 {
2094 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2095
2096 if (wideProvider)
2097 {
2098 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2099 len);
2100 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2101 HeapFree(GetProcessHeap(), 0, wideProvider);
2102 }
2103 else
2104 ret = WN_OUT_OF_MEMORY;
2105 }
2106 else
2107 ret = GetLastError();
2108 }
2109 if (ret)
2110 SetLastError(ret);
2111 TRACE("Returning %d\n", ret);
2112 return ret;
2113 }
2114
2115 /*********************************************************************
2116 * WNetGetNetworkInformationW [MPR.@]
2117 */
2118 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2119 LPNETINFOSTRUCT lpNetInfoStruct )
2120 {
2121 DWORD ret;
2122
2123 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2124
2125 if (!lpProvider)
2126 ret = WN_BAD_POINTER;
2127 else if (!lpNetInfoStruct)
2128 ret = WN_BAD_POINTER;
2129 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2130 ret = WN_BAD_VALUE;
2131 else
2132 {
2133 if (providerTable && providerTable->numProviders)
2134 {
2135 DWORD providerIndex = _findProviderIndexW(lpProvider);
2136
2137 if (providerIndex != BAD_PROVIDER_INDEX)
2138 {
2139 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2140 lpNetInfoStruct->dwProviderVersion =
2141 providerTable->table[providerIndex].dwSpecVersion;
2142 lpNetInfoStruct->dwStatus = NO_ERROR;
2143 lpNetInfoStruct->dwCharacteristics = 0;
2144 lpNetInfoStruct->dwHandle = 0;
2145 lpNetInfoStruct->wNetType =
2146 HIWORD(providerTable->table[providerIndex].dwNetType);
2147 lpNetInfoStruct->dwPrinters = -1;
2148 lpNetInfoStruct->dwDrives = -1;
2149 ret = WN_SUCCESS;
2150 }
2151 else
2152 ret = WN_BAD_PROVIDER;
2153 }
2154 else
2155 ret = WN_NO_NETWORK;
2156 }
2157 if (ret)
2158 SetLastError(ret);
2159 TRACE("Returning %d\n", ret);
2160 return ret;
2161 }
2162
2163 /*****************************************************************
2164 * WNetGetProviderNameA [MPR.@]
2165 */
2166 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2167 LPSTR lpProvider, LPDWORD lpBufferSize )
2168 {
2169 DWORD ret;
2170
2171 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2172 lpBufferSize);
2173
2174 if (!lpProvider)
2175 ret = WN_BAD_POINTER;
2176 else if (!lpBufferSize)
2177 ret = WN_BAD_POINTER;
2178 else
2179 {
2180 if (providerTable)
2181 {
2182 DWORD i;
2183
2184 ret = WN_NO_NETWORK;
2185 for (i = 0; i < providerTable->numProviders &&
2186 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2187 i++)
2188 ;
2189 if (i < providerTable->numProviders)
2190 {
2191 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2192 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2193
2194 if (*lpBufferSize < sizeNeeded)
2195 {
2196 *lpBufferSize = sizeNeeded;
2197 ret = WN_MORE_DATA;
2198 }
2199 else
2200 {
2201 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2202 -1, lpProvider, *lpBufferSize, NULL, NULL);
2203 ret = WN_SUCCESS;
2204 /* FIXME: is *lpBufferSize set to the number of characters
2205 * copied? */
2206 }
2207 }
2208 }
2209 else
2210 ret = WN_NO_NETWORK;
2211 }
2212 if (ret)
2213 SetLastError(ret);
2214 TRACE("Returning %d\n", ret);
2215 return ret;
2216 }
2217
2218 /*****************************************************************
2219 * WNetGetProviderNameW [MPR.@]
2220 */
2221 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2222 LPWSTR lpProvider, LPDWORD lpBufferSize )
2223 {
2224 DWORD ret;
2225
2226 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2227 lpBufferSize);
2228
2229 if (!lpProvider)
2230 ret = WN_BAD_POINTER;
2231 else if (!lpBufferSize)
2232 ret = WN_BAD_POINTER;
2233 else
2234 {
2235 if (providerTable)
2236 {
2237 DWORD i;
2238
2239 ret = WN_NO_NETWORK;
2240 for (i = 0; i < providerTable->numProviders &&
2241 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2242 i++)
2243 ;
2244 if (i < providerTable->numProviders)
2245 {
2246 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2247
2248 if (*lpBufferSize < sizeNeeded)
2249 {
2250 *lpBufferSize = sizeNeeded;
2251 ret = WN_MORE_DATA;
2252 }
2253 else
2254 {
2255 strcpyW(lpProvider, providerTable->table[i].name);
2256 ret = WN_SUCCESS;
2257 /* FIXME: is *lpBufferSize set to the number of characters
2258 * copied? */
2259 }
2260 }
2261 }
2262 else
2263 ret = WN_NO_NETWORK;
2264 }
2265 if (ret)
2266 SetLastError(ret);
2267 TRACE("Returning %d\n", ret);
2268 return ret;
2269 }