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