Added YUV routines needed for v4l driver, and in the future possibly
[wine/gsoc-2012-control.git] / dlls / mpr / wnet.c
bloba0f0bd36004015951f2011be3c2ad877b407c55a
1 /*
2 * MPR WNet functions
4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winnls.h"
26 #include "winnetwk.h"
27 #include "npapi.h"
28 #include "winreg.h"
29 #include "winuser.h"
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
32 #include "mprres.h"
33 #include "wnetpriv.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(mpr);
37 /* Data structures representing network service providers. Assumes only one
38 * thread creates them, and that they are constant for the life of the process
39 * (and therefore doesn't synchronize access).
40 * FIXME: only basic provider data and enumeration-related data are implemented
41 * so far, need to implement the rest too.
43 typedef struct _WNetProvider
45 HMODULE hLib;
46 PWSTR name;
47 PF_NPGetCaps getCaps;
48 DWORD dwSpecVersion;
49 DWORD dwNetType;
50 DWORD dwEnumScopes;
51 PF_NPOpenEnum openEnum;
52 PF_NPEnumResource enumResource;
53 PF_NPCloseEnum closeEnum;
54 } WNetProvider, *PWNetProvider;
56 typedef struct _WNetProviderTable
58 LPWSTR entireNetwork;
59 DWORD numAllocated;
60 DWORD numProviders;
61 WNetProvider table[1];
62 } WNetProviderTable, *PWNetProviderTable;
64 #define WNET_ENUMERATOR_TYPE_NULL 0
65 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
66 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
67 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
69 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
70 * the enumeration; it represents one of the following types:
71 * - a 'null' enumeration, one that contains no members
72 * - a global enumeration, one that's executed across all providers
73 * - a provider-specific enumeration, one that's only executed by a single
74 * provider
75 * - a context enumeration. I know this contradicts what I just said about
76 * there being no correspondence between the scope and the type, but it's
77 * necessary for the special case that a "Entire Network" entry needs to
78 * be enumerated in an enumeration of the context scope. Thus an enumeration
79 * of the context scope results in a context type enumerator, which morphs
80 * into a global enumeration (so the enumeration continues across all
81 * providers).
83 typedef struct _WNetEnumerator
85 DWORD enumType;
86 DWORD providerIndex;
87 HANDLE handle;
88 BOOL providerDone;
89 DWORD dwScope;
90 DWORD dwType;
91 DWORD dwUsage;
92 LPNETRESOURCEW lpNet;
93 } WNetEnumerator, *PWNetEnumerator;
95 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
97 /* Returns an index (into the global WNetProviderTable) of the provider with
98 * the given name, or BAD_PROVIDER_INDEX if not found.
100 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
102 PWNetProviderTable providerTable;
105 * Global provider table functions
108 static void _tryLoadProvider(PCWSTR provider)
110 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
111 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
112 'S','e','r','v','i','c','e','s','\\',0 };
113 static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
114 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
115 WCHAR serviceName[MAX_PATH];
116 HKEY hKey;
118 TRACE("%s\n", debugstr_w(provider));
119 snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt,
120 servicePrefix, provider);
121 serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0';
122 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
123 ERROR_SUCCESS)
125 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
126 'P','a','t','h',0 };
127 WCHAR providerPath[MAX_PATH];
128 DWORD type, size = sizeof(providerPath);
130 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
131 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && type == REG_SZ)
133 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
134 PWSTR name = NULL;
136 size = 0;
137 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
138 if (size)
140 name = HeapAlloc(GetProcessHeap(), 0, size);
141 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
142 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
144 HeapFree(GetProcessHeap(), 0, name);
145 name = NULL;
148 if (name)
150 HMODULE hLib = LoadLibraryW(providerPath);
152 if (hLib)
154 PF_NPGetCaps getCaps = (PF_NPGetCaps)GetProcAddress(hLib,
155 "NPGetCaps");
157 TRACE("loaded lib %p\n", hLib);
158 if (getCaps)
160 PWNetProvider provider =
161 &providerTable->table[providerTable->numProviders];
163 provider->hLib = hLib;
164 provider->name = name;
165 TRACE("name is %s\n", debugstr_w(name));
166 provider->getCaps = getCaps;
167 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
168 provider->dwNetType = getCaps(WNNC_NET_TYPE);
169 TRACE("net type is 0x%08lx\n", provider->dwNetType);
170 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
171 if (provider->dwEnumScopes)
173 TRACE("supports enumeration\n");
174 provider->openEnum = (PF_NPOpenEnum)
175 GetProcAddress(hLib, "NPOpenEnum");
176 TRACE("openEnum is %p\n", provider->openEnum);
177 provider->enumResource = (PF_NPEnumResource)
178 GetProcAddress(hLib, "NPEnumResource");
179 TRACE("enumResource is %p\n",
180 provider->enumResource);
181 provider->closeEnum = (PF_NPCloseEnum)
182 GetProcAddress(hLib, "NPCloseEnum");
183 TRACE("closeEnum is %p\n", provider->closeEnum);
184 if (!provider->openEnum || !provider->enumResource
185 || !provider->closeEnum)
187 provider->openEnum = NULL;
188 provider->enumResource = NULL;
189 provider->closeEnum = NULL;
190 provider->dwEnumScopes = 0;
191 WARN("Couldn't load enumeration functions\n");
194 providerTable->numProviders++;
196 else
198 WARN("Provider %s didn't export NPGetCaps\n",
199 debugstr_w(provider));
200 HeapFree(GetProcessHeap(), 0, name);
201 FreeLibrary(hLib);
204 else
206 WARN("Couldn't load library %s for provider %s\n",
207 debugstr_w(providerPath), debugstr_w(provider));
208 HeapFree(GetProcessHeap(), 0, name);
211 else
213 WARN("Couldn't get provider name for provider %s\n",
214 debugstr_w(provider));
217 else
218 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
219 RegCloseKey(hKey);
221 else
222 WARN("Couldn't open service key for provider %s\n",
223 debugstr_w(provider));
226 void wnetInit(HINSTANCE hInstDll)
228 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
229 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
230 'C','o','n','t','r','o','l','\\',
231 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
232 'O','r','d','e','r',0 };
233 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
234 'O','r','d','e','r',0 };
235 HKEY hKey;
237 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
238 == ERROR_SUCCESS)
240 DWORD size = 0;
242 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
243 if (size)
245 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
247 if (providers)
249 DWORD type;
251 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
252 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
254 PWSTR ptr;
255 DWORD numToAllocate;
257 TRACE("provider order is %s\n", debugstr_w(providers));
258 /* first count commas as a heuristic for how many to
259 * allocate space for */
260 for (ptr = providers, numToAllocate = 1; ptr; )
262 ptr = strchrW(ptr, ',');
263 if (ptr)
264 numToAllocate++;
266 providerTable =
267 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
268 sizeof(WNetProviderTable)
269 + (numToAllocate - 1) * sizeof(WNetProvider));
270 if (providerTable)
272 PWSTR ptrPrev;
273 int entireNetworkLen;
275 entireNetworkLen = LoadStringW(hInstDll,
276 IDS_ENTIRENETWORK, NULL, 0);
277 providerTable->entireNetwork = HeapAlloc(
278 GetProcessHeap(), 0, (entireNetworkLen + 1) *
279 sizeof(WCHAR));
280 if (providerTable->entireNetwork)
281 LoadStringW(hInstDll, IDS_ENTIRENETWORK,
282 providerTable->entireNetwork,
283 entireNetworkLen + 1);
284 providerTable->numAllocated = numToAllocate;
285 for (ptr = providers; ptr; )
287 ptrPrev = ptr;
288 ptr = strchrW(ptr, ',');
289 if (ptr)
290 *ptr = '\0';
291 _tryLoadProvider(ptrPrev);
295 HeapFree(GetProcessHeap(), 0, providers);
298 RegCloseKey(hKey);
302 void wnetFree(void)
304 if (providerTable)
306 DWORD i;
308 for (i = 0; i < providerTable->numProviders; i++)
310 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
311 FreeModule(providerTable->table[i].hLib);
313 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
314 HeapFree(GetProcessHeap(), 0, providerTable);
315 providerTable = NULL;
319 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
321 DWORD ret = BAD_PROVIDER_INDEX;
323 if (providerTable && providerTable->numProviders)
325 DWORD i;
327 for (i = 0; i < providerTable->numProviders &&
328 ret == BAD_PROVIDER_INDEX; i++)
329 if (!strcmpW(lpProvider, providerTable->table[i].name))
330 ret = i;
332 return ret;
336 * Browsing Functions
339 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
341 LPNETRESOURCEW ret;
343 if (lpNet)
345 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
346 if (ret)
348 size_t len;
350 memcpy(ret, lpNet, sizeof(ret));
351 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
352 if (lpNet->lpRemoteName)
354 len = strlenW(lpNet->lpRemoteName) + 1;
355 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
356 if (ret->lpRemoteName)
357 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
361 else
362 ret = NULL;
363 return ret;
366 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
368 if (lpNet)
370 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
371 HeapFree(GetProcessHeap(), 0, lpNet);
375 static PWNetEnumerator _createNullEnumerator(void)
377 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
378 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
380 if (ret)
381 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
382 return ret;
385 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
386 DWORD dwUsage, LPNETRESOURCEW lpNet)
388 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
389 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
391 if (ret)
393 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
394 ret->dwScope = dwScope;
395 ret->dwType = dwType;
396 ret->dwUsage = dwUsage;
397 ret->lpNet = _copyNetResourceForEnumW(lpNet);
399 return ret;
402 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
403 DWORD dwUsage, DWORD index, HANDLE handle)
405 PWNetEnumerator ret;
407 if (!providerTable || index >= providerTable->numProviders)
408 ret = NULL;
409 else
411 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
412 if (ret)
414 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
415 ret->providerIndex = index;
416 ret->dwScope = dwScope;
417 ret->dwType = dwType;
418 ret->dwUsage = dwUsage;
419 ret->handle = handle;
422 return ret;
425 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
426 DWORD dwUsage)
428 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
429 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
431 if (ret)
433 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
434 ret->dwScope = dwScope;
435 ret->dwType = dwType;
436 ret->dwUsage = dwUsage;
438 return ret;
441 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
442 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
443 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
444 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
445 * if not all members of the array could be thunked, and something else on
446 * failure.
448 static DWORD _thunkNetResourceArrayWToA(const LPNETRESOURCEW lpNetArrayIn,
449 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
451 DWORD i, numToThunk, totalBytes, ret;
452 LPSTR strNext;
454 if (!lpNetArrayIn)
455 return WN_BAD_POINTER;
456 if (!lpcCount)
457 return WN_BAD_POINTER;
458 if (*lpcCount == -1)
459 return WN_BAD_VALUE;
460 if (!lpBuffer)
461 return WN_BAD_POINTER;
462 if (!lpBufferSize)
463 return WN_BAD_POINTER;
465 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
467 LPNETRESOURCEW lpNet = lpNetArrayIn + i;
469 totalBytes += sizeof(NETRESOURCEA);
470 if (lpNet->lpLocalName)
471 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
472 -1, NULL, 0, NULL, NULL);
473 if (lpNet->lpRemoteName)
474 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
475 -1, NULL, 0, NULL, NULL);
476 if (lpNet->lpComment)
477 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
478 -1, NULL, 0, NULL, NULL);
479 if (lpNet->lpProvider)
480 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
481 -1, NULL, 0, NULL, NULL);
482 if (totalBytes < *lpBufferSize)
483 numToThunk = i + 1;
485 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
486 for (i = 0; i < numToThunk; i++)
488 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
489 LPNETRESOURCEW lpNetIn = lpNetArrayIn + i;
491 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
492 /* lie about string lengths, we already verified how many
493 * we have space for above
495 if (lpNetIn->lpLocalName)
497 lpNetOut->lpLocalName = strNext;
498 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
499 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
501 if (lpNetIn->lpRemoteName)
503 lpNetOut->lpRemoteName = strNext;
504 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
505 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
507 if (lpNetIn->lpComment)
509 lpNetOut->lpComment = strNext;
510 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
511 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
513 if (lpNetIn->lpProvider)
515 lpNetOut->lpProvider = strNext;
516 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
517 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
520 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
521 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk,
522 *lpcCount, ret);
523 return ret;
526 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
527 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
528 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
529 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
530 * if not all members of the array could be thunked, and something else on
531 * failure.
533 static DWORD _thunkNetResourceArrayAToW(const LPNETRESOURCEA lpNetArrayIn,
534 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
536 DWORD i, numToThunk, totalBytes, ret;
537 LPWSTR strNext;
539 if (!lpNetArrayIn)
540 return WN_BAD_POINTER;
541 if (!lpcCount)
542 return WN_BAD_POINTER;
543 if (*lpcCount == -1)
544 return WN_BAD_VALUE;
545 if (!lpBuffer)
546 return WN_BAD_POINTER;
547 if (!lpBufferSize)
548 return WN_BAD_POINTER;
550 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
552 LPNETRESOURCEA lpNet = lpNetArrayIn + i;
554 totalBytes += sizeof(NETRESOURCEW);
555 if (lpNet->lpLocalName)
556 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
557 -1, NULL, 0) * sizeof(WCHAR);
558 if (lpNet->lpRemoteName)
559 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
560 -1, NULL, 0) * sizeof(WCHAR);
561 if (lpNet->lpComment)
562 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
563 -1, NULL, 0) * sizeof(WCHAR);
564 if (lpNet->lpProvider)
565 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
566 -1, NULL, 0) * sizeof(WCHAR);
567 if (totalBytes < *lpBufferSize)
568 numToThunk = i + 1;
570 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
571 for (i = 0; i < numToThunk; i++)
573 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
574 LPNETRESOURCEA lpNetIn = lpNetArrayIn + i;
576 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
577 /* lie about string lengths, we already verified how many
578 * we have space for above
580 if (lpNetIn->lpLocalName)
582 lpNetOut->lpLocalName = strNext;
583 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
584 -1, lpNetOut->lpLocalName, *lpBufferSize);
586 if (lpNetIn->lpRemoteName)
588 lpNetOut->lpRemoteName = strNext;
589 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
590 -1, lpNetOut->lpRemoteName, *lpBufferSize);
592 if (lpNetIn->lpComment)
594 lpNetOut->lpComment = strNext;
595 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
596 -1, lpNetOut->lpComment, *lpBufferSize);
598 if (lpNetIn->lpProvider)
600 lpNetOut->lpProvider = strNext;
601 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
602 -1, lpNetOut->lpProvider, *lpBufferSize);
605 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
606 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk,
607 *lpcCount, ret);
608 return ret;
611 /*********************************************************************
612 * WNetOpenEnumA [MPR.@]
614 * See comments for WNetOpenEnumW.
616 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
617 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
619 DWORD ret;
621 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
622 dwScope, dwType, dwUsage, lpNet, lphEnum );
624 if (!lphEnum)
625 ret = WN_BAD_POINTER;
626 else if (!providerTable || providerTable->numProviders == 0)
627 ret = WN_NO_NETWORK;
628 else
630 if (lpNet)
632 LPNETRESOURCEW lpNetWide = NULL;
633 BYTE buf[1024];
634 DWORD size = sizeof(buf), count = 1;
635 BOOL allocated = FALSE;
637 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
638 if (ret == WN_MORE_DATA)
640 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
641 size);
642 if (lpNetWide)
644 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
645 &size);
646 allocated = TRUE;
648 else
649 ret = WN_OUT_OF_MEMORY;
651 else if (ret == WN_SUCCESS)
652 lpNetWide = (LPNETRESOURCEW)buf;
653 if (ret == WN_SUCCESS)
654 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
655 lphEnum);
656 if (allocated && lpNetWide)
657 HeapFree(GetProcessHeap(), 0, lpNetWide);
659 else
660 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
662 if (ret)
663 SetLastError(ret);
664 TRACE("Returning %ld\n", ret);
665 return ret;
668 /*********************************************************************
669 * WNetOpenEnumW [MPR.@]
671 * Network enumeration has way too many parameters, so I'm not positive I got
672 * them right. What I've got so far:
674 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
675 * all the network providers should be enumerated.
677 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
678 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
679 * lpProvider is set, all the network providers should be enumerated.
680 * (This means the enumeration is a list of network providers, not that the
681 * enumeration is passed on to the providers.)
683 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
684 * resource matches the "Entire Network" resource (no remote name, no
685 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
686 * enumeration is done on every network provider.
688 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
689 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
690 * only to the given network provider.
692 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
693 * no lpProvider is set, enumeration will be tried on every network provider,
694 * in the order in which they're loaded.
696 * - The LPNETRESOURCE should be disregarded for scopes besides
697 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
698 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
700 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
701 * resource in the enumerated list, as well as any machines in your
702 * workgroup. The machines in your workgroup come from doing a
703 * RESOURCE_CONTEXT enumeration of every Network Provider.
705 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
706 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
708 DWORD ret;
710 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
711 dwScope, dwType, dwUsage, lpNet, lphEnum );
713 if (!lphEnum)
714 ret = WN_BAD_POINTER;
715 else if (!providerTable || providerTable->numProviders == 0)
716 ret = WN_NO_NETWORK;
717 else
719 switch (dwScope)
721 case RESOURCE_GLOBALNET:
722 if (lpNet)
724 if (lpNet->lpProvider)
726 DWORD index = _findProviderIndexW(lpNet->lpProvider);
728 if (index != BAD_PROVIDER_INDEX)
730 if (providerTable->table[index].openEnum &&
731 providerTable->table[index].dwEnumScopes & dwScope)
733 HANDLE handle;
735 ret = providerTable->table[index].openEnum(
736 dwScope, dwType, dwUsage, lpNet, &handle);
737 if (ret == WN_SUCCESS)
739 *lphEnum =
740 (HANDLE)_createProviderEnumerator(
741 dwScope, dwType, dwUsage, index, handle);
742 ret = *lphEnum ? WN_SUCCESS :
743 WN_OUT_OF_MEMORY;
746 else
747 ret = WN_NOT_SUPPORTED;
749 else
750 ret = WN_BAD_PROVIDER;
752 else if (lpNet->lpRemoteName)
754 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
755 dwType, dwUsage, lpNet);
756 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
758 else
760 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
761 providerTable->entireNetwork))
763 /* comment matches the "Entire Network", enumerate
764 * global scope of every provider
766 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
767 dwType, dwUsage, lpNet);
769 else
771 /* this is the same as not having passed lpNet */
772 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
773 dwType, dwUsage, NULL);
775 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
778 else
780 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, dwType,
781 dwUsage, lpNet);
782 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
784 break;
785 case RESOURCE_CONTEXT:
786 *lphEnum = (HANDLE)_createContextEnumerator(dwScope, dwType,
787 dwUsage);
788 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
789 break;
790 case RESOURCE_REMEMBERED:
791 case RESOURCE_CONNECTED:
792 *lphEnum = (HANDLE)_createNullEnumerator();
793 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
794 break;
795 default:
796 WARN("unknown scope 0x%08lx\n", dwScope);
797 ret = WN_BAD_VALUE;
800 if (ret)
801 SetLastError(ret);
802 TRACE("Returning %ld\n", ret);
803 return ret;
806 /*********************************************************************
807 * WNetEnumResourceA [MPR.@]
809 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
810 LPVOID lpBuffer, LPDWORD lpBufferSize )
812 DWORD ret;
814 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
816 if (!hEnum)
817 ret = WN_BAD_POINTER;
818 else if (!lpcCount)
819 ret = WN_BAD_POINTER;
820 if (!lpBuffer)
821 ret = WN_BAD_POINTER;
822 else if (!lpBufferSize)
823 ret = WN_BAD_POINTER;
824 else if (*lpBufferSize < sizeof(NETRESOURCEA))
826 *lpBufferSize = sizeof(NETRESOURCEA);
827 ret = WN_MORE_DATA;
829 else
831 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
832 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
834 if (localBuffer)
836 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
837 &localSize);
838 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
840 /* FIXME: this isn't necessarily going to work in the case of
841 * WN_MORE_DATA, because our enumerator may have moved on to
842 * the next provider. MSDN states that a large (16KB) buffer
843 * size is the appropriate usage of this function, so
844 * hopefully it won't be an issue.
846 ret = _thunkNetResourceArrayWToA((LPNETRESOURCEW)localBuffer,
847 &localCount, lpBuffer, lpBufferSize);
848 *lpcCount = localCount;
850 HeapFree(GetProcessHeap(), 0, localBuffer);
852 else
853 ret = WN_OUT_OF_MEMORY;
855 if (ret)
856 SetLastError(ret);
857 TRACE("Returning %ld\n", ret);
858 return ret;
861 static DWORD _countProviderBytesW(PWNetProvider provider)
863 DWORD ret;
865 if (provider)
867 ret = sizeof(NETRESOURCEW);
868 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
870 else
871 ret = 0;
872 return ret;
875 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
876 LPVOID lpBuffer, LPDWORD lpBufferSize)
878 DWORD ret;
880 if (!enumerator)
881 return WN_BAD_POINTER;
882 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
883 return WN_BAD_VALUE;
884 if (!lpcCount)
885 return WN_BAD_POINTER;
886 if (!lpBuffer)
887 return WN_BAD_POINTER;
888 if (!lpBufferSize)
889 return WN_BAD_POINTER;
890 if (*lpBufferSize < sizeof(NETRESOURCEA))
891 return WN_MORE_DATA;
893 if (!providerTable || enumerator->providerIndex >=
894 providerTable->numProviders)
895 ret = WN_NO_MORE_ENTRIES;
896 else
898 DWORD bytes = 0, count = 0, countLimit, i;
899 LPNETRESOURCEW resource;
900 LPWSTR strNext;
902 countLimit = *lpcCount == -1 ?
903 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
904 while (count < countLimit && bytes < *lpBufferSize)
906 DWORD bytesNext = _countProviderBytesW(
907 &providerTable->table[count + enumerator->providerIndex]);
909 if (bytes + bytesNext < *lpBufferSize)
911 bytes += bytesNext;
912 count++;
915 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
916 for (i = 0, resource = (LPNETRESOURCEW)lpBuffer; i < count;
917 i++, resource++)
919 resource->dwScope = RESOURCE_GLOBALNET;
920 resource->dwType = RESOURCETYPE_ANY;
921 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
922 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
923 RESOURCEUSAGE_RESERVED;
924 resource->lpLocalName = NULL;
925 resource->lpRemoteName = strNext;
926 strcpyW(resource->lpRemoteName,
927 providerTable->table[i + enumerator->providerIndex].name);
928 strNext += strlenW(resource->lpRemoteName) + 1;
929 resource->lpComment = NULL;
930 resource->lpProvider = strNext;
931 strcpyW(resource->lpProvider,
932 providerTable->table[i + enumerator->providerIndex].name);
933 strNext += strlenW(resource->lpProvider) + 1;
935 enumerator->providerIndex += count;
936 *lpcCount = count;
937 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
939 TRACE("Returning %ld\n", ret);
940 return ret;
943 /* Advances the enumerator (assumed to be a global enumerator) to the next
944 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
945 * not open a handle with the next provider.
946 * If the existing handle is NULL, may leave the enumerator unchanged, since
947 * the current provider may support the desired scope.
948 * If the existing handle is not NULL, closes it before moving on.
949 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
950 * provider, and another error on failure.
952 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
954 if (!enumerator)
955 return WN_BAD_POINTER;
956 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
957 return WN_BAD_VALUE;
958 if (!providerTable || enumerator->providerIndex >=
959 providerTable->numProviders)
960 return WN_NO_MORE_ENTRIES;
962 if (enumerator->providerDone)
964 enumerator->providerDone = FALSE;
965 if (enumerator->handle)
967 providerTable->table[enumerator->providerIndex].closeEnum(
968 enumerator->handle);
969 enumerator->handle = NULL;
970 enumerator->providerIndex++;
972 for (; enumerator->providerIndex < providerTable->numProviders &&
973 !(enumerator->dwScope & providerTable->table
974 [enumerator->providerIndex].dwEnumScopes);
975 enumerator->providerIndex++)
978 return enumerator->providerIndex < providerTable->numProviders ?
979 WN_SUCCESS : WN_NO_MORE_ENTRIES;
982 /* "Passes through" call to the next provider that supports the enumeration
983 * type.
984 * FIXME: if one call to a provider's enumerator succeeds while there's still
985 * space in lpBuffer, I don't call to the next provider. The caller may not
986 * expect that it should call EnumResourceW again with a return value of
987 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
988 * may have to be moved around a bit, ick.
990 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
991 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
993 DWORD ret;
995 if (!enumerator)
996 return WN_BAD_POINTER;
997 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
998 return WN_BAD_VALUE;
999 if (!lpcCount)
1000 return WN_BAD_POINTER;
1001 if (!lpBuffer)
1002 return WN_BAD_POINTER;
1003 if (!lpBufferSize)
1004 return WN_BAD_POINTER;
1005 if (*lpBufferSize < sizeof(NETRESOURCEW))
1006 return WN_MORE_DATA;
1008 ret = _globalEnumeratorAdvance(enumerator);
1009 if (ret == WN_SUCCESS)
1011 ret = providerTable->table[enumerator->providerIndex].
1012 openEnum(enumerator->dwScope, enumerator->dwType,
1013 enumerator->dwUsage, enumerator->lpNet,
1014 &enumerator->handle);
1015 if (ret == WN_SUCCESS)
1017 ret = providerTable->table[enumerator->providerIndex].
1018 enumResource(enumerator->handle, lpcCount, lpBuffer,
1019 lpBufferSize);
1020 if (ret != WN_MORE_DATA)
1021 enumerator->providerDone = TRUE;
1024 TRACE("Returning %ld\n", ret);
1025 return ret;
1028 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1029 LPVOID lpBuffer, LPDWORD lpBufferSize)
1031 DWORD ret;
1033 if (!enumerator)
1034 return WN_BAD_POINTER;
1035 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1036 return WN_BAD_VALUE;
1037 if (!lpcCount)
1038 return WN_BAD_POINTER;
1039 if (!lpBuffer)
1040 return WN_BAD_POINTER;
1041 if (!lpBufferSize)
1042 return WN_BAD_POINTER;
1043 if (*lpBufferSize < sizeof(NETRESOURCEW))
1044 return WN_MORE_DATA;
1045 if (!providerTable)
1046 return WN_NO_NETWORK;
1048 switch (enumerator->dwScope)
1050 case RESOURCE_GLOBALNET:
1051 if (enumerator->lpNet)
1052 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1053 lpBuffer, lpBufferSize);
1054 else
1055 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1056 lpBufferSize);
1057 break;
1058 case RESOURCE_CONTEXT:
1059 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1060 lpBufferSize);
1061 break;
1062 default:
1063 WARN("unexpected scope 0x%08lx\n", enumerator->dwScope);
1064 ret = WN_NO_MORE_ENTRIES;
1066 TRACE("Returning %ld\n", ret);
1067 return ret;
1070 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1071 LPVOID lpBuffer, LPDWORD lpBufferSize)
1073 if (!enumerator)
1074 return WN_BAD_POINTER;
1075 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1076 return WN_BAD_VALUE;
1077 if (!enumerator->handle)
1078 return WN_BAD_VALUE;
1079 if (!lpcCount)
1080 return WN_BAD_POINTER;
1081 if (!lpBuffer)
1082 return WN_BAD_POINTER;
1083 if (!lpBufferSize)
1084 return WN_BAD_POINTER;
1085 if (!providerTable)
1086 return WN_NO_NETWORK;
1087 if (enumerator->providerIndex >= providerTable->numProviders)
1088 return WN_NO_MORE_ENTRIES;
1089 if (!providerTable->table[enumerator->providerIndex].enumResource)
1090 return WN_BAD_VALUE;
1091 return providerTable->table[enumerator->providerIndex].enumResource(
1092 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1095 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1096 LPVOID lpBuffer, LPDWORD lpBufferSize)
1098 DWORD ret;
1099 size_t cchEntireNetworkLen, bytesNeeded;
1101 if (!enumerator)
1102 return WN_BAD_POINTER;
1103 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1104 return WN_BAD_VALUE;
1105 if (!lpcCount)
1106 return WN_BAD_POINTER;
1107 if (!lpBuffer)
1108 return WN_BAD_POINTER;
1109 if (!lpBufferSize)
1110 return WN_BAD_POINTER;
1111 if (!providerTable)
1112 return WN_NO_NETWORK;
1114 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1115 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1116 if (*lpBufferSize < bytesNeeded)
1118 *lpBufferSize = bytesNeeded;
1119 ret = WN_MORE_DATA;
1121 else
1123 LPNETRESOURCEW lpNet = (LPNETRESOURCEW)lpBuffer;
1125 lpNet->dwScope = RESOURCE_GLOBALNET;
1126 lpNet->dwType = enumerator->dwType;
1127 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1128 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1129 lpNet->lpLocalName = NULL;
1130 lpNet->lpRemoteName = NULL;
1131 lpNet->lpProvider = NULL;
1132 /* odd, but correct: put comment at end of buffer, so it won't get
1133 * overwritten by subsequent calls to a provider's enumResource
1135 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1136 (cchEntireNetworkLen * sizeof(WCHAR)));
1137 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1138 ret = WN_SUCCESS;
1140 if (ret == WN_SUCCESS)
1142 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1144 /* "Entire Network" entry enumerated--morph this into a global
1145 * enumerator. enumerator->lpNet continues to be NULL, since it has
1146 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1148 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1149 ret = _enumerateGlobalW(enumerator, lpcCount,
1150 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1151 if (ret == WN_SUCCESS)
1153 /* reflect the fact that we already enumerated "Entire Network" */
1154 lpcCount++;
1155 *lpBufferSize = bufferSize + bytesNeeded;
1157 else
1159 /* the provider enumeration failed, but we already succeeded in
1160 * enumerating "Entire Network"--leave type as global to allow a
1161 * retry, but indicate success with a count of one.
1163 ret = WN_SUCCESS;
1164 *lpcCount = 1;
1165 *lpBufferSize = bytesNeeded;
1168 TRACE("Returning %ld\n", ret);
1169 return ret;
1172 /*********************************************************************
1173 * WNetEnumResourceW [MPR.@]
1175 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1176 LPVOID lpBuffer, LPDWORD lpBufferSize )
1178 DWORD ret;
1180 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1182 if (!hEnum)
1183 ret = WN_BAD_POINTER;
1184 else if (!lpcCount)
1185 ret = WN_BAD_POINTER;
1186 else if (!lpBuffer)
1187 ret = WN_BAD_POINTER;
1188 else if (!lpBufferSize)
1189 ret = WN_BAD_POINTER;
1190 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1192 *lpBufferSize = sizeof(NETRESOURCEW);
1193 ret = WN_MORE_DATA;
1195 else
1197 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1199 switch (enumerator->enumType)
1201 case WNET_ENUMERATOR_TYPE_NULL:
1202 ret = WN_NO_MORE_ENTRIES;
1203 break;
1204 case WNET_ENUMERATOR_TYPE_GLOBAL:
1205 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1206 lpBufferSize);
1207 break;
1208 case WNET_ENUMERATOR_TYPE_PROVIDER:
1209 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1210 lpBufferSize);
1211 break;
1212 case WNET_ENUMERATOR_TYPE_CONTEXT:
1213 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1214 lpBufferSize);
1215 break;
1216 default:
1217 WARN("bogus enumerator type!\n");
1218 ret = WN_NO_NETWORK;
1221 if (ret)
1222 SetLastError(ret);
1223 TRACE("Returning %ld\n", ret);
1224 return ret;
1227 /*********************************************************************
1228 * WNetCloseEnum [MPR.@]
1230 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1232 DWORD ret;
1234 TRACE( "(%p)\n", hEnum );
1236 if (hEnum)
1238 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1240 switch (enumerator->enumType)
1242 case WNET_ENUMERATOR_TYPE_NULL:
1243 ret = WN_SUCCESS;
1244 break;
1245 case WNET_ENUMERATOR_TYPE_GLOBAL:
1246 if (enumerator->lpNet)
1247 _freeEnumNetResource(enumerator->lpNet);
1248 if (enumerator->handle)
1249 providerTable->table[enumerator->providerIndex].
1250 closeEnum(enumerator->handle);
1251 ret = WN_SUCCESS;
1252 break;
1253 case WNET_ENUMERATOR_TYPE_PROVIDER:
1254 if (enumerator->handle)
1255 providerTable->table[enumerator->providerIndex].
1256 closeEnum(enumerator->handle);
1257 ret = WN_SUCCESS;
1258 break;
1259 default:
1260 WARN("bogus enumerator type!\n");
1261 ret = WN_BAD_HANDLE;
1263 HeapFree(GetProcessHeap(), 0, hEnum);
1265 else
1266 ret = WN_BAD_HANDLE;
1267 if (ret)
1268 SetLastError(ret);
1269 TRACE("Returning %ld\n", ret);
1270 return ret;
1273 /*********************************************************************
1274 * WNetGetResourceInformationA [MPR.@]
1276 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1277 LPVOID lpBuffer, LPDWORD cbBuffer,
1278 LPSTR *lplpSystem )
1280 FIXME( "(%p, %p, %p, %p): stub\n",
1281 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1283 SetLastError(WN_NO_NETWORK);
1284 return WN_NO_NETWORK;
1287 /*********************************************************************
1288 * WNetGetResourceInformationW [MPR.@]
1290 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1291 LPVOID lpBuffer, LPDWORD cbBuffer,
1292 LPWSTR *lplpSystem )
1294 FIXME( "(%p, %p, %p, %p): stub\n",
1295 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1297 SetLastError(WN_NO_NETWORK);
1298 return WN_NO_NETWORK;
1301 /*********************************************************************
1302 * WNetGetResourceParentA [MPR.@]
1304 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1305 LPVOID lpBuffer, LPDWORD lpBufferSize )
1307 FIXME( "(%p, %p, %p): stub\n",
1308 lpNetResource, lpBuffer, lpBufferSize );
1310 SetLastError(WN_NO_NETWORK);
1311 return WN_NO_NETWORK;
1314 /*********************************************************************
1315 * WNetGetResourceParentW [MPR.@]
1317 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1318 LPVOID lpBuffer, LPDWORD lpBufferSize )
1320 FIXME( "(%p, %p, %p): stub\n",
1321 lpNetResource, lpBuffer, lpBufferSize );
1323 SetLastError(WN_NO_NETWORK);
1324 return WN_NO_NETWORK;
1330 * Connection Functions
1333 /*********************************************************************
1334 * WNetAddConnectionA [MPR.@]
1336 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1337 LPCSTR lpLocalName )
1339 FIXME( "(%s, %p, %s): stub\n",
1340 debugstr_a(lpRemoteName), lpPassword, debugstr_a(lpLocalName) );
1342 SetLastError(WN_NO_NETWORK);
1343 return WN_NO_NETWORK;
1346 /*********************************************************************
1347 * WNetAddConnectionW [MPR.@]
1349 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1350 LPCWSTR lpLocalName )
1352 FIXME( "(%s, %p, %s): stub\n",
1353 debugstr_w(lpRemoteName), lpPassword, debugstr_w(lpLocalName) );
1355 SetLastError(WN_NO_NETWORK);
1356 return WN_NO_NETWORK;
1359 /*********************************************************************
1360 * WNetAddConnection2A [MPR.@]
1362 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1363 LPCSTR lpPassword, LPCSTR lpUserID,
1364 DWORD dwFlags )
1366 FIXME( "(%p, %p, %s, 0x%08lX): stub\n",
1367 lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1369 SetLastError(WN_NO_NETWORK);
1370 return WN_NO_NETWORK;
1373 /*********************************************************************
1374 * WNetAddConnection2W [MPR.@]
1376 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1377 LPCWSTR lpPassword, LPCWSTR lpUserID,
1378 DWORD dwFlags )
1380 FIXME( "(%p, %p, %s, 0x%08lX): stub\n",
1381 lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1383 SetLastError(WN_NO_NETWORK);
1384 return WN_NO_NETWORK;
1387 /*********************************************************************
1388 * WNetAddConnection3A [MPR.@]
1390 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1391 LPCSTR lpPassword, LPCSTR lpUserID,
1392 DWORD dwFlags )
1394 FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n",
1395 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1397 SetLastError(WN_NO_NETWORK);
1398 return WN_NO_NETWORK;
1401 /*********************************************************************
1402 * WNetAddConnection3W [MPR.@]
1404 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1405 LPCWSTR lpPassword, LPCWSTR lpUserID,
1406 DWORD dwFlags )
1408 FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n",
1409 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1411 SetLastError(WN_NO_NETWORK);
1412 return WN_NO_NETWORK;
1415 /*****************************************************************
1416 * WNetUseConnectionA [MPR.@]
1418 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1419 LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
1420 LPSTR lpAccessName, LPDWORD lpBufferSize,
1421 LPDWORD lpResult )
1423 FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n",
1424 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags,
1425 debugstr_a(lpAccessName), lpBufferSize, lpResult );
1427 SetLastError(WN_NO_NETWORK);
1428 return WN_NO_NETWORK;
1431 /*****************************************************************
1432 * WNetUseConnectionW [MPR.@]
1434 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1435 LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags,
1436 LPWSTR lpAccessName, LPDWORD lpBufferSize,
1437 LPDWORD lpResult )
1439 FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n",
1440 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags,
1441 debugstr_w(lpAccessName), lpBufferSize, lpResult );
1443 SetLastError(WN_NO_NETWORK);
1444 return WN_NO_NETWORK;
1447 /*********************************************************************
1448 * WNetCancelConnectionA [MPR.@]
1450 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1452 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1454 return WN_SUCCESS;
1457 /*********************************************************************
1458 * WNetCancelConnectionW [MPR.@]
1460 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1462 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1464 return WN_SUCCESS;
1467 /*********************************************************************
1468 * WNetCancelConnection2A [MPR.@]
1470 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1472 FIXME( "(%s, %08lX, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1474 return WN_SUCCESS;
1477 /*********************************************************************
1478 * WNetCancelConnection2W [MPR.@]
1480 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1482 FIXME( "(%s, %08lX, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1484 return WN_SUCCESS;
1487 /*****************************************************************
1488 * WNetRestoreConnectionA [MPR.@]
1490 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPSTR lpszDevice )
1492 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1494 SetLastError(WN_NO_NETWORK);
1495 return WN_NO_NETWORK;
1498 /*****************************************************************
1499 * WNetRestoreConnectionW [MPR.@]
1501 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPWSTR lpszDevice )
1503 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1505 SetLastError(WN_NO_NETWORK);
1506 return WN_NO_NETWORK;
1509 /**************************************************************************
1510 * WNetGetConnectionA [MPR.@]
1512 * RETURNS
1513 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1514 * - WN_NOT_CONNECTED drive is a local drive
1515 * - WN_MORE_DATA buffer isn't big enough
1516 * - WN_SUCCESS success (net path in buffer)
1518 * FIXME: need to test return values under different errors
1520 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1521 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1523 DWORD ret;
1525 if (!lpLocalName)
1526 ret = WN_BAD_POINTER;
1527 else if (!lpRemoteName)
1528 ret = WN_BAD_POINTER;
1529 else if (!lpBufferSize)
1530 ret = WN_BAD_POINTER;
1531 else
1533 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1535 if (len)
1537 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1539 if (wideLocalName)
1541 WCHAR wideRemoteStatic[MAX_PATH];
1542 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1544 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1546 /* try once without memory allocation */
1547 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1548 &wideRemoteSize);
1549 if (ret == WN_SUCCESS)
1551 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1552 -1, NULL, 0, NULL, NULL);
1554 if (len <= *lpBufferSize)
1556 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1557 lpRemoteName, *lpBufferSize, NULL, NULL);
1558 ret = WN_SUCCESS;
1560 else
1562 *lpBufferSize = len;
1563 ret = WN_MORE_DATA;
1566 else if (ret == WN_MORE_DATA)
1568 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1569 wideRemoteSize * sizeof(WCHAR));
1571 if (wideRemote)
1573 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1574 &wideRemoteSize);
1575 if (ret == WN_SUCCESS)
1577 if (len <= *lpBufferSize)
1579 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1580 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1581 ret = WN_SUCCESS;
1583 else
1585 *lpBufferSize = len;
1586 ret = WN_MORE_DATA;
1589 HeapFree(GetProcessHeap(), 0, wideRemote);
1591 else
1592 ret = WN_OUT_OF_MEMORY;
1594 HeapFree(GetProcessHeap(), 0, wideLocalName);
1596 else
1597 ret = WN_OUT_OF_MEMORY;
1599 else
1600 ret = WN_BAD_LOCALNAME;
1602 if (ret)
1603 SetLastError(ret);
1604 TRACE("Returning %ld\n", ret);
1605 return ret;
1608 /**************************************************************************
1609 * WNetGetConnectionW [MPR.@]
1611 * FIXME: need to test return values under different errors
1613 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
1614 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
1616 DWORD ret;
1618 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
1619 lpBufferSize);
1621 if (!lpLocalName)
1622 ret = WN_BAD_POINTER;
1623 else if (!lpRemoteName)
1624 ret = WN_BAD_POINTER;
1625 else if (!lpBufferSize)
1626 ret = WN_BAD_POINTER;
1627 else if (!lpLocalName[0])
1628 ret = WN_BAD_LOCALNAME;
1629 else
1631 if (lpLocalName[1] == ':')
1633 switch(GetDriveTypeW(lpLocalName))
1635 case DRIVE_REMOTE:
1637 WCHAR remote[MAX_PATH];
1638 if (!QueryDosDeviceW( lpLocalName, remote, MAX_PATH )) remote[0] = 0;
1639 if (strlenW(remote) + 1 > *lpBufferSize)
1641 *lpBufferSize = strlenW(remote) + 1;
1642 ret = WN_MORE_DATA;
1644 else
1646 strcpyW( lpRemoteName, remote );
1647 *lpBufferSize = strlenW(lpRemoteName) + 1;
1648 ret = WN_SUCCESS;
1650 break;
1652 case DRIVE_REMOVABLE:
1653 case DRIVE_FIXED:
1654 case DRIVE_CDROM:
1655 TRACE("file is local\n");
1656 ret = WN_NOT_CONNECTED;
1657 break;
1658 default:
1659 ret = WN_BAD_LOCALNAME;
1662 else
1663 ret = WN_BAD_LOCALNAME;
1665 if (ret)
1666 SetLastError(ret);
1667 TRACE("Returning %ld\n", ret);
1668 return ret;
1671 /**************************************************************************
1672 * WNetSetConnectionA [MPR.@]
1674 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
1675 LPVOID pvValue )
1677 FIXME( "(%s, %08lX, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
1679 SetLastError(WN_NO_NETWORK);
1680 return WN_NO_NETWORK;
1683 /**************************************************************************
1684 * WNetSetConnectionW [MPR.@]
1686 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
1687 LPVOID pvValue )
1689 FIXME( "(%s, %08lX, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
1691 SetLastError(WN_NO_NETWORK);
1692 return WN_NO_NETWORK;
1695 /*****************************************************************
1696 * WNetGetUniversalNameA [MPR.@]
1698 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
1699 LPVOID lpBuffer, LPDWORD lpBufferSize )
1701 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
1702 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1704 SetLastError(WN_NO_NETWORK);
1705 return WN_NO_NETWORK;
1708 /*****************************************************************
1709 * WNetGetUniversalNameW [MPR.@]
1711 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
1712 LPVOID lpBuffer, LPDWORD lpBufferSize )
1714 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
1715 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1717 SetLastError(WN_NO_NETWORK);
1718 return WN_NO_NETWORK;
1724 * Other Functions
1727 /**************************************************************************
1728 * WNetGetUserA [MPR.@]
1730 * FIXME: we should not return ourselves, but the owner of the drive lpName
1732 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
1734 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
1735 return GetLastError();
1738 /*****************************************************************
1739 * WNetGetUserW [MPR.@]
1741 * FIXME: we should not return ourselves, but the owner of the drive lpName
1743 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
1745 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
1746 return GetLastError();
1749 /*********************************************************************
1750 * WNetConnectionDialog [MPR.@]
1752 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
1754 FIXME( "(%p, %08lX): stub\n", hwnd, dwType );
1756 SetLastError(WN_NO_NETWORK);
1757 return WN_NO_NETWORK;
1760 /*********************************************************************
1761 * WNetConnectionDialog1A [MPR.@]
1763 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
1765 FIXME( "(%p): stub\n", lpConnDlgStruct );
1767 SetLastError(WN_NO_NETWORK);
1768 return WN_NO_NETWORK;
1771 /*********************************************************************
1772 * WNetConnectionDialog1W [MPR.@]
1774 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
1776 FIXME( "(%p): stub\n", lpConnDlgStruct );
1778 SetLastError(WN_NO_NETWORK);
1779 return WN_NO_NETWORK;
1782 /*********************************************************************
1783 * WNetDisconnectDialog [MPR.@]
1785 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
1787 FIXME( "(%p, %08lX): stub\n", hwnd, dwType );
1789 SetLastError(WN_NO_NETWORK);
1790 return WN_NO_NETWORK;
1793 /*********************************************************************
1794 * WNetDisconnectDialog1A [MPR.@]
1796 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
1798 FIXME( "(%p): stub\n", lpConnDlgStruct );
1800 SetLastError(WN_NO_NETWORK);
1801 return WN_NO_NETWORK;
1804 /*********************************************************************
1805 * WNetDisconnectDialog1W [MPR.@]
1807 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
1809 FIXME( "(%p): stub\n", lpConnDlgStruct );
1811 SetLastError(WN_NO_NETWORK);
1812 return WN_NO_NETWORK;
1815 /*********************************************************************
1816 * WNetGetLastErrorA [MPR.@]
1818 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
1819 LPSTR lpErrorBuf, DWORD nErrorBufSize,
1820 LPSTR lpNameBuf, DWORD nNameBufSize )
1822 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
1823 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
1825 SetLastError(WN_NO_NETWORK);
1826 return WN_NO_NETWORK;
1829 /*********************************************************************
1830 * WNetGetLastErrorW [MPR.@]
1832 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
1833 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
1834 LPWSTR lpNameBuf, DWORD nNameBufSize )
1836 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
1837 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
1839 SetLastError(WN_NO_NETWORK);
1840 return WN_NO_NETWORK;
1843 /*********************************************************************
1844 * WNetGetNetworkInformationA [MPR.@]
1846 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
1847 LPNETINFOSTRUCT lpNetInfoStruct )
1849 DWORD ret;
1851 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
1853 if (!lpProvider)
1854 ret = WN_BAD_POINTER;
1855 else
1857 int len;
1859 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
1860 if (len)
1862 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1864 if (wideProvider)
1866 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
1867 len);
1868 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
1869 HeapFree(GetProcessHeap(), 0, wideProvider);
1871 else
1872 ret = WN_OUT_OF_MEMORY;
1874 else
1875 ret = GetLastError();
1877 if (ret)
1878 SetLastError(ret);
1879 TRACE("Returning %ld\n", ret);
1880 return ret;
1883 /*********************************************************************
1884 * WNetGetNetworkInformationW [MPR.@]
1886 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
1887 LPNETINFOSTRUCT lpNetInfoStruct )
1889 DWORD ret;
1891 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
1893 if (!lpProvider)
1894 ret = WN_BAD_POINTER;
1895 else if (!lpNetInfoStruct)
1896 ret = WN_BAD_POINTER;
1897 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
1898 ret = WN_BAD_VALUE;
1899 else
1901 if (providerTable && providerTable->numProviders)
1903 DWORD providerIndex = _findProviderIndexW(lpProvider);
1905 if (providerIndex != BAD_PROVIDER_INDEX)
1907 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
1908 lpNetInfoStruct->dwProviderVersion =
1909 providerTable->table[providerIndex].dwSpecVersion;
1910 lpNetInfoStruct->dwStatus = NO_ERROR;
1911 lpNetInfoStruct->dwCharacteristics = 0;
1912 lpNetInfoStruct->dwHandle = (ULONG_PTR)NULL;
1913 lpNetInfoStruct->wNetType =
1914 HIWORD(providerTable->table[providerIndex].dwNetType);
1915 lpNetInfoStruct->dwPrinters = -1;
1916 lpNetInfoStruct->dwDrives = -1;
1917 ret = WN_SUCCESS;
1919 else
1920 ret = WN_BAD_PROVIDER;
1922 else
1923 ret = WN_NO_NETWORK;
1925 if (ret)
1926 SetLastError(ret);
1927 TRACE("Returning %ld\n", ret);
1928 return ret;
1931 /*****************************************************************
1932 * WNetGetProviderNameA [MPR.@]
1934 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
1935 LPSTR lpProvider, LPDWORD lpBufferSize )
1937 DWORD ret;
1939 TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
1940 lpBufferSize);
1942 if (!lpProvider)
1943 ret = WN_BAD_POINTER;
1944 else if (!lpBufferSize)
1945 ret = WN_BAD_POINTER;
1946 else
1948 if (providerTable)
1950 DWORD i;
1952 ret = WN_NO_NETWORK;
1953 for (i = 0; i < providerTable->numProviders &&
1954 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
1955 i++)
1957 if (i < providerTable->numProviders)
1959 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
1960 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
1962 if (*lpBufferSize < sizeNeeded)
1964 *lpBufferSize = sizeNeeded;
1965 ret = WN_MORE_DATA;
1967 else
1969 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
1970 -1, lpProvider, *lpBufferSize, NULL, NULL);
1971 ret = WN_SUCCESS;
1972 /* FIXME: is *lpBufferSize set to the number of characters
1973 * copied? */
1977 else
1978 ret = WN_NO_NETWORK;
1980 if (ret)
1981 SetLastError(ret);
1982 TRACE("Returning %ld\n", ret);
1983 return ret;
1986 /*****************************************************************
1987 * WNetGetProviderNameW [MPR.@]
1989 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
1990 LPWSTR lpProvider, LPDWORD lpBufferSize )
1992 DWORD ret;
1994 TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
1995 lpBufferSize);
1997 if (!lpProvider)
1998 ret = WN_BAD_POINTER;
1999 else if (!lpBufferSize)
2000 ret = WN_BAD_POINTER;
2001 else
2003 if (providerTable)
2005 DWORD i;
2007 ret = WN_NO_NETWORK;
2008 for (i = 0; i < providerTable->numProviders &&
2009 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2010 i++)
2012 if (i < providerTable->numProviders)
2014 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2016 if (*lpBufferSize < sizeNeeded)
2018 *lpBufferSize = sizeNeeded;
2019 ret = WN_MORE_DATA;
2021 else
2023 strcpyW(lpProvider, providerTable->table[i].name);
2024 ret = WN_SUCCESS;
2025 /* FIXME: is *lpBufferSize set to the number of characters
2026 * copied? */
2030 else
2031 ret = WN_NO_NETWORK;
2033 if (ret)
2034 SetLastError(ret);
2035 TRACE("Returning %ld\n", ret);
2036 return ret;