4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
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.
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.
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
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(mpr);
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.
44 typedef struct _WNetProvider
52 PF_NPOpenEnum openEnum;
53 PF_NPEnumResource enumResource;
54 PF_NPCloseEnum closeEnum;
55 PF_NPGetResourceInformation getResourceInformation;
56 } WNetProvider, *PWNetProvider;
58 typedef struct _WNetProviderTable
63 WNetProvider table[1];
64 } WNetProviderTable, *PWNetProviderTable;
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
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
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
85 typedef struct _WNetEnumerator
95 } WNetEnumerator, *PWNetEnumerator;
97 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
99 /* Returns an index (into the global WNetProviderTable) of the provider with
100 * the given name, or BAD_PROVIDER_INDEX if not found.
102 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
104 static PWNetProviderTable providerTable;
107 * Global provider table functions
110 static void _tryLoadProvider(PCWSTR provider)
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];
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) ==
127 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
129 WCHAR providerPath[MAX_PATH];
130 DWORD type, size = sizeof(providerPath);
132 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
133 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && type == REG_SZ)
135 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
139 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
142 name = HeapAlloc(GetProcessHeap(), 0, size);
143 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
144 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
146 HeapFree(GetProcessHeap(), 0, name);
152 HMODULE hLib = LoadLibraryW(providerPath);
156 PF_NPGetCaps getCaps = (PF_NPGetCaps)GetProcAddress(hLib,
159 TRACE("loaded lib %p\n", hLib);
162 PWNetProvider provider =
163 &providerTable->table[providerTable->numProviders];
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)
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)
193 provider->openEnum = NULL;
194 provider->enumResource = NULL;
195 provider->closeEnum = NULL;
196 provider->dwEnumScopes = 0;
197 WARN("Couldn't load enumeration functions\n");
200 providerTable->numProviders++;
204 WARN("Provider %s didn't export NPGetCaps\n",
205 debugstr_w(provider));
206 HeapFree(GetProcessHeap(), 0, name);
212 WARN("Couldn't load library %s for provider %s\n",
213 debugstr_w(providerPath), debugstr_w(provider));
214 HeapFree(GetProcessHeap(), 0, name);
219 WARN("Couldn't get provider name for provider %s\n",
220 debugstr_w(provider));
224 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
228 WARN("Couldn't open service key for provider %s\n",
229 debugstr_w(provider));
232 void wnetInit(HINSTANCE hInstDll)
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 };
243 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
248 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
251 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
257 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
258 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
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; )
268 ptr = strchrW(ptr, ',');
275 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
276 sizeof(WNetProviderTable)
277 + (numToAllocate - 1) * sizeof(WNetProvider));
281 int entireNetworkLen;
283 entireNetworkLen = LoadStringW(hInstDll,
284 IDS_ENTIRENETWORK, NULL, 0);
285 providerTable->entireNetwork = HeapAlloc(
286 GetProcessHeap(), 0, (entireNetworkLen + 1) *
288 if (providerTable->entireNetwork)
289 LoadStringW(hInstDll, IDS_ENTIRENETWORK,
290 providerTable->entireNetwork,
291 entireNetworkLen + 1);
292 providerTable->numAllocated = numToAllocate;
293 for (ptr = providers; ptr; )
296 ptr = strchrW(ptr, ',');
299 _tryLoadProvider(ptrPrev);
303 HeapFree(GetProcessHeap(), 0, providers);
316 for (i = 0; i < providerTable->numProviders; i++)
318 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
319 FreeModule(providerTable->table[i].hLib);
321 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
322 HeapFree(GetProcessHeap(), 0, providerTable);
323 providerTable = NULL;
327 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
329 DWORD ret = BAD_PROVIDER_INDEX;
331 if (providerTable && providerTable->numProviders)
335 for (i = 0; i < providerTable->numProviders &&
336 ret == BAD_PROVIDER_INDEX; i++)
337 if (!strcmpW(lpProvider, providerTable->table[i].name))
347 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
353 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
358 memcpy(ret, lpNet, sizeof(ret));
359 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
360 if (lpNet->lpRemoteName)
362 len = strlenW(lpNet->lpRemoteName) + 1;
363 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
364 if (ret->lpRemoteName)
365 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
374 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
378 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
379 HeapFree(GetProcessHeap(), 0, lpNet);
383 static PWNetEnumerator _createNullEnumerator(void)
385 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
386 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
389 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
393 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
394 DWORD dwUsage, LPNETRESOURCEW lpNet)
396 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
397 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
401 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
402 ret->dwScope = dwScope;
403 ret->dwType = dwType;
404 ret->dwUsage = dwUsage;
405 ret->lpNet = _copyNetResourceForEnumW(lpNet);
410 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
411 DWORD dwUsage, DWORD index, HANDLE handle)
415 if (!providerTable || index >= providerTable->numProviders)
419 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
422 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
423 ret->providerIndex = index;
424 ret->dwScope = dwScope;
425 ret->dwType = dwType;
426 ret->dwUsage = dwUsage;
427 ret->handle = handle;
433 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
436 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
437 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
441 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
442 ret->dwScope = dwScope;
443 ret->dwType = dwType;
444 ret->dwUsage = dwUsage;
449 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
450 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
451 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
452 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
453 * if not all members of the array could be thunked, and something else on
456 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
457 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
459 DWORD i, numToThunk, totalBytes, ret;
463 return WN_BAD_POINTER;
465 return WN_BAD_POINTER;
469 return WN_BAD_POINTER;
471 return WN_BAD_POINTER;
473 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
475 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
477 totalBytes += sizeof(NETRESOURCEA);
478 if (lpNet->lpLocalName)
479 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
480 -1, NULL, 0, NULL, NULL);
481 if (lpNet->lpRemoteName)
482 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
483 -1, NULL, 0, NULL, NULL);
484 if (lpNet->lpComment)
485 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
486 -1, NULL, 0, NULL, NULL);
487 if (lpNet->lpProvider)
488 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
489 -1, NULL, 0, NULL, NULL);
490 if (totalBytes < *lpBufferSize)
493 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
494 for (i = 0; i < numToThunk; i++)
496 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
497 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
499 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
500 /* lie about string lengths, we already verified how many
501 * we have space for above
503 if (lpNetIn->lpLocalName)
505 lpNetOut->lpLocalName = strNext;
506 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
507 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
509 if (lpNetIn->lpRemoteName)
511 lpNetOut->lpRemoteName = strNext;
512 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
513 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
515 if (lpNetIn->lpComment)
517 lpNetOut->lpComment = strNext;
518 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
519 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
521 if (lpNetIn->lpProvider)
523 lpNetOut->lpProvider = strNext;
524 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
525 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
528 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
529 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
534 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
535 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
536 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
537 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
538 * if not all members of the array could be thunked, and something else on
541 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
542 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
544 DWORD i, numToThunk, totalBytes, ret;
548 return WN_BAD_POINTER;
550 return WN_BAD_POINTER;
554 return WN_BAD_POINTER;
556 return WN_BAD_POINTER;
558 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
560 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
562 totalBytes += sizeof(NETRESOURCEW);
563 if (lpNet->lpLocalName)
564 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
565 -1, NULL, 0) * sizeof(WCHAR);
566 if (lpNet->lpRemoteName)
567 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
568 -1, NULL, 0) * sizeof(WCHAR);
569 if (lpNet->lpComment)
570 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
571 -1, NULL, 0) * sizeof(WCHAR);
572 if (lpNet->lpProvider)
573 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
574 -1, NULL, 0) * sizeof(WCHAR);
575 if (totalBytes < *lpBufferSize)
578 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
579 for (i = 0; i < numToThunk; i++)
581 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
582 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
584 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
585 /* lie about string lengths, we already verified how many
586 * we have space for above
588 if (lpNetIn->lpLocalName)
590 lpNetOut->lpLocalName = strNext;
591 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
592 -1, lpNetOut->lpLocalName, *lpBufferSize);
594 if (lpNetIn->lpRemoteName)
596 lpNetOut->lpRemoteName = strNext;
597 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
598 -1, lpNetOut->lpRemoteName, *lpBufferSize);
600 if (lpNetIn->lpComment)
602 lpNetOut->lpComment = strNext;
603 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
604 -1, lpNetOut->lpComment, *lpBufferSize);
606 if (lpNetIn->lpProvider)
608 lpNetOut->lpProvider = strNext;
609 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
610 -1, lpNetOut->lpProvider, *lpBufferSize);
613 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
614 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
619 /*********************************************************************
620 * WNetOpenEnumA [MPR.@]
622 * See comments for WNetOpenEnumW.
624 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
625 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
629 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
630 dwScope, dwType, dwUsage, lpNet, lphEnum );
633 ret = WN_BAD_POINTER;
634 else if (!providerTable || providerTable->numProviders == 0)
640 LPNETRESOURCEW lpNetWide = NULL;
642 DWORD size = sizeof(buf), count = 1;
643 BOOL allocated = FALSE;
645 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
646 if (ret == WN_MORE_DATA)
648 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
652 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
657 ret = WN_OUT_OF_MEMORY;
659 else if (ret == WN_SUCCESS)
660 lpNetWide = (LPNETRESOURCEW)buf;
661 if (ret == WN_SUCCESS)
662 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
665 HeapFree(GetProcessHeap(), 0, lpNetWide);
668 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
672 TRACE("Returning %d\n", ret);
676 /*********************************************************************
677 * WNetOpenEnumW [MPR.@]
679 * Network enumeration has way too many parameters, so I'm not positive I got
680 * them right. What I've got so far:
682 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
683 * all the network providers should be enumerated.
685 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
686 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
687 * lpProvider is set, all the network providers should be enumerated.
688 * (This means the enumeration is a list of network providers, not that the
689 * enumeration is passed on to the providers.)
691 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
692 * resource matches the "Entire Network" resource (no remote name, no
693 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
694 * enumeration is done on every network provider.
696 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
697 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
698 * only to the given network provider.
700 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
701 * no lpProvider is set, enumeration will be tried on every network provider,
702 * in the order in which they're loaded.
704 * - The LPNETRESOURCE should be disregarded for scopes besides
705 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
706 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
708 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
709 * resource in the enumerated list, as well as any machines in your
710 * workgroup. The machines in your workgroup come from doing a
711 * RESOURCE_CONTEXT enumeration of every Network Provider.
713 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
714 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
718 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
719 dwScope, dwType, dwUsage, lpNet, lphEnum );
722 ret = WN_BAD_POINTER;
723 else if (!providerTable || providerTable->numProviders == 0)
729 case RESOURCE_GLOBALNET:
732 if (lpNet->lpProvider)
734 DWORD index = _findProviderIndexW(lpNet->lpProvider);
736 if (index != BAD_PROVIDER_INDEX)
738 if (providerTable->table[index].openEnum &&
739 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
743 ret = providerTable->table[index].openEnum(
744 dwScope, dwType, dwUsage, lpNet, &handle);
745 if (ret == WN_SUCCESS)
748 (HANDLE)_createProviderEnumerator(
749 dwScope, dwType, dwUsage, index, handle);
750 ret = *lphEnum ? WN_SUCCESS :
755 ret = WN_NOT_SUPPORTED;
758 ret = WN_BAD_PROVIDER;
760 else if (lpNet->lpRemoteName)
762 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
763 dwType, dwUsage, lpNet);
764 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
768 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
769 providerTable->entireNetwork))
771 /* comment matches the "Entire Network", enumerate
772 * global scope of every provider
774 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
775 dwType, dwUsage, lpNet);
779 /* this is the same as not having passed lpNet */
780 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
781 dwType, dwUsage, NULL);
783 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
788 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, dwType,
790 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
793 case RESOURCE_CONTEXT:
794 *lphEnum = (HANDLE)_createContextEnumerator(dwScope, dwType,
796 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
798 case RESOURCE_REMEMBERED:
799 case RESOURCE_CONNECTED:
800 *lphEnum = (HANDLE)_createNullEnumerator();
801 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
804 WARN("unknown scope 0x%08x\n", dwScope);
810 TRACE("Returning %d\n", ret);
814 /*********************************************************************
815 * WNetEnumResourceA [MPR.@]
817 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
818 LPVOID lpBuffer, LPDWORD lpBufferSize )
822 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
825 ret = WN_BAD_POINTER;
827 ret = WN_BAD_POINTER;
829 ret = WN_BAD_POINTER;
830 else if (!lpBufferSize)
831 ret = WN_BAD_POINTER;
832 else if (*lpBufferSize < sizeof(NETRESOURCEA))
834 *lpBufferSize = sizeof(NETRESOURCEA);
839 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
840 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
844 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
846 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
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.
854 ret = _thunkNetResourceArrayWToA((LPNETRESOURCEW)localBuffer,
855 &localCount, lpBuffer, lpBufferSize);
856 *lpcCount = localCount;
858 HeapFree(GetProcessHeap(), 0, localBuffer);
861 ret = WN_OUT_OF_MEMORY;
865 TRACE("Returning %d\n", ret);
869 static DWORD _countProviderBytesW(PWNetProvider provider)
875 ret = sizeof(NETRESOURCEW);
876 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
883 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
884 LPVOID lpBuffer, const DWORD *lpBufferSize)
889 return WN_BAD_POINTER;
890 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
893 return WN_BAD_POINTER;
895 return WN_BAD_POINTER;
897 return WN_BAD_POINTER;
898 if (*lpBufferSize < sizeof(NETRESOURCEA))
901 if (!providerTable || enumerator->providerIndex >=
902 providerTable->numProviders)
903 ret = WN_NO_MORE_ENTRIES;
906 DWORD bytes = 0, count = 0, countLimit, i;
907 LPNETRESOURCEW resource;
910 countLimit = *lpcCount == -1 ?
911 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
912 while (count < countLimit && bytes < *lpBufferSize)
914 DWORD bytesNext = _countProviderBytesW(
915 &providerTable->table[count + enumerator->providerIndex]);
917 if (bytes + bytesNext < *lpBufferSize)
923 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
924 for (i = 0, resource = (LPNETRESOURCEW)lpBuffer; i < count;
927 resource->dwScope = RESOURCE_GLOBALNET;
928 resource->dwType = RESOURCETYPE_ANY;
929 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
930 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
931 RESOURCEUSAGE_RESERVED;
932 resource->lpLocalName = NULL;
933 resource->lpRemoteName = strNext;
934 strcpyW(resource->lpRemoteName,
935 providerTable->table[i + enumerator->providerIndex].name);
936 strNext += strlenW(resource->lpRemoteName) + 1;
937 resource->lpComment = NULL;
938 resource->lpProvider = strNext;
939 strcpyW(resource->lpProvider,
940 providerTable->table[i + enumerator->providerIndex].name);
941 strNext += strlenW(resource->lpProvider) + 1;
943 enumerator->providerIndex += count;
945 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
947 TRACE("Returning %d\n", ret);
951 /* Advances the enumerator (assumed to be a global enumerator) to the next
952 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
953 * not open a handle with the next provider.
954 * If the existing handle is NULL, may leave the enumerator unchanged, since
955 * the current provider may support the desired scope.
956 * If the existing handle is not NULL, closes it before moving on.
957 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
958 * provider, and another error on failure.
960 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
963 return WN_BAD_POINTER;
964 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
966 if (!providerTable || enumerator->providerIndex >=
967 providerTable->numProviders)
968 return WN_NO_MORE_ENTRIES;
970 if (enumerator->providerDone)
973 enumerator->providerDone = FALSE;
974 if (enumerator->handle)
976 providerTable->table[enumerator->providerIndex].closeEnum(
978 enumerator->handle = NULL;
979 enumerator->providerIndex++;
981 if (enumerator->dwScope == RESOURCE_CONNECTED)
982 dwEnum = WNNC_ENUM_LOCAL;
983 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
984 dwEnum = WNNC_ENUM_GLOBAL;
985 else if (enumerator->dwScope == RESOURCE_CONTEXT)
986 dwEnum = WNNC_ENUM_CONTEXT;
987 for (; enumerator->providerIndex < providerTable->numProviders &&
988 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
989 & dwEnum); enumerator->providerIndex++)
992 return enumerator->providerIndex < providerTable->numProviders ?
993 WN_SUCCESS : WN_NO_MORE_ENTRIES;
996 /* "Passes through" call to the next provider that supports the enumeration
998 * FIXME: if one call to a provider's enumerator succeeds while there's still
999 * space in lpBuffer, I don't call to the next provider. The caller may not
1000 * expect that it should call EnumResourceW again with a return value of
1001 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1002 * may have to be moved around a bit, ick.
1004 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1005 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1010 return WN_BAD_POINTER;
1011 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1012 return WN_BAD_VALUE;
1014 return WN_BAD_POINTER;
1016 return WN_BAD_POINTER;
1018 return WN_BAD_POINTER;
1019 if (*lpBufferSize < sizeof(NETRESOURCEW))
1020 return WN_MORE_DATA;
1022 ret = _globalEnumeratorAdvance(enumerator);
1023 if (ret == WN_SUCCESS)
1025 ret = providerTable->table[enumerator->providerIndex].
1026 openEnum(enumerator->dwScope, enumerator->dwType,
1027 enumerator->dwUsage, enumerator->lpNet,
1028 &enumerator->handle);
1029 if (ret == WN_SUCCESS)
1031 ret = providerTable->table[enumerator->providerIndex].
1032 enumResource(enumerator->handle, lpcCount, lpBuffer,
1034 if (ret != WN_MORE_DATA)
1035 enumerator->providerDone = TRUE;
1038 TRACE("Returning %d\n", ret);
1042 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1043 LPVOID lpBuffer, LPDWORD lpBufferSize)
1048 return WN_BAD_POINTER;
1049 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1050 return WN_BAD_VALUE;
1052 return WN_BAD_POINTER;
1054 return WN_BAD_POINTER;
1056 return WN_BAD_POINTER;
1057 if (*lpBufferSize < sizeof(NETRESOURCEW))
1058 return WN_MORE_DATA;
1060 return WN_NO_NETWORK;
1062 switch (enumerator->dwScope)
1064 case RESOURCE_GLOBALNET:
1065 if (enumerator->lpNet)
1066 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1067 lpBuffer, lpBufferSize);
1069 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1072 case RESOURCE_CONTEXT:
1073 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1077 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1078 ret = WN_NO_MORE_ENTRIES;
1080 TRACE("Returning %d\n", ret);
1084 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1085 LPVOID lpBuffer, LPDWORD lpBufferSize)
1088 return WN_BAD_POINTER;
1089 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1090 return WN_BAD_VALUE;
1091 if (!enumerator->handle)
1092 return WN_BAD_VALUE;
1094 return WN_BAD_POINTER;
1096 return WN_BAD_POINTER;
1098 return WN_BAD_POINTER;
1100 return WN_NO_NETWORK;
1101 if (enumerator->providerIndex >= providerTable->numProviders)
1102 return WN_NO_MORE_ENTRIES;
1103 if (!providerTable->table[enumerator->providerIndex].enumResource)
1104 return WN_BAD_VALUE;
1105 return providerTable->table[enumerator->providerIndex].enumResource(
1106 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1109 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1110 LPVOID lpBuffer, LPDWORD lpBufferSize)
1113 size_t cchEntireNetworkLen, bytesNeeded;
1116 return WN_BAD_POINTER;
1117 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1118 return WN_BAD_VALUE;
1120 return WN_BAD_POINTER;
1122 return WN_BAD_POINTER;
1124 return WN_BAD_POINTER;
1126 return WN_NO_NETWORK;
1128 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1129 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1130 if (*lpBufferSize < bytesNeeded)
1132 *lpBufferSize = bytesNeeded;
1137 LPNETRESOURCEW lpNet = (LPNETRESOURCEW)lpBuffer;
1139 lpNet->dwScope = RESOURCE_GLOBALNET;
1140 lpNet->dwType = enumerator->dwType;
1141 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1142 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1143 lpNet->lpLocalName = NULL;
1144 lpNet->lpRemoteName = NULL;
1145 lpNet->lpProvider = NULL;
1146 /* odd, but correct: put comment at end of buffer, so it won't get
1147 * overwritten by subsequent calls to a provider's enumResource
1149 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1150 (cchEntireNetworkLen * sizeof(WCHAR)));
1151 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1154 if (ret == WN_SUCCESS)
1156 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1158 /* "Entire Network" entry enumerated--morph this into a global
1159 * enumerator. enumerator->lpNet continues to be NULL, since it has
1160 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1162 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1163 ret = _enumerateGlobalW(enumerator, lpcCount,
1164 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1165 if (ret == WN_SUCCESS)
1167 /* reflect the fact that we already enumerated "Entire Network" */
1169 *lpBufferSize = bufferSize + bytesNeeded;
1173 /* the provider enumeration failed, but we already succeeded in
1174 * enumerating "Entire Network"--leave type as global to allow a
1175 * retry, but indicate success with a count of one.
1179 *lpBufferSize = bytesNeeded;
1182 TRACE("Returning %d\n", ret);
1186 /*********************************************************************
1187 * WNetEnumResourceW [MPR.@]
1189 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1190 LPVOID lpBuffer, LPDWORD lpBufferSize )
1194 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1197 ret = WN_BAD_POINTER;
1199 ret = WN_BAD_POINTER;
1201 ret = WN_BAD_POINTER;
1202 else if (!lpBufferSize)
1203 ret = WN_BAD_POINTER;
1204 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1206 *lpBufferSize = sizeof(NETRESOURCEW);
1211 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1213 switch (enumerator->enumType)
1215 case WNET_ENUMERATOR_TYPE_NULL:
1216 ret = WN_NO_MORE_ENTRIES;
1218 case WNET_ENUMERATOR_TYPE_GLOBAL:
1219 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1222 case WNET_ENUMERATOR_TYPE_PROVIDER:
1223 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1226 case WNET_ENUMERATOR_TYPE_CONTEXT:
1227 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1231 WARN("bogus enumerator type!\n");
1232 ret = WN_NO_NETWORK;
1237 TRACE("Returning %d\n", ret);
1241 /*********************************************************************
1242 * WNetCloseEnum [MPR.@]
1244 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1248 TRACE( "(%p)\n", hEnum );
1252 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1254 switch (enumerator->enumType)
1256 case WNET_ENUMERATOR_TYPE_NULL:
1259 case WNET_ENUMERATOR_TYPE_GLOBAL:
1260 if (enumerator->lpNet)
1261 _freeEnumNetResource(enumerator->lpNet);
1262 if (enumerator->handle)
1263 providerTable->table[enumerator->providerIndex].
1264 closeEnum(enumerator->handle);
1267 case WNET_ENUMERATOR_TYPE_PROVIDER:
1268 if (enumerator->handle)
1269 providerTable->table[enumerator->providerIndex].
1270 closeEnum(enumerator->handle);
1274 WARN("bogus enumerator type!\n");
1275 ret = WN_BAD_HANDLE;
1277 HeapFree(GetProcessHeap(), 0, hEnum);
1280 ret = WN_BAD_HANDLE;
1283 TRACE("Returning %d\n", ret);
1287 /*********************************************************************
1288 * WNetGetResourceInformationA [MPR.@]
1290 * See WNetGetResourceInformationW
1292 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1293 LPVOID lpBuffer, LPDWORD cbBuffer,
1298 TRACE( "(%p, %p, %p, %p)\n",
1299 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1301 if (!providerTable || providerTable->numProviders == 0)
1302 ret = WN_NO_NETWORK;
1303 else if (lpNetResource)
1305 LPNETRESOURCEW lpNetResourceW = NULL;
1306 DWORD size = 1024, count = 1;
1309 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1310 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1311 if (ret == WN_MORE_DATA)
1313 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1315 ret = _thunkNetResourceArrayAToW(lpNetResource,
1316 &count, lpNetResourceW, &size);
1318 ret = WN_OUT_OF_MEMORY;
1320 if (ret == WN_SUCCESS)
1322 LPWSTR lpSystemW = NULL;
1325 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1328 ret = WNetGetResourceInformationW(lpNetResourceW,
1329 lpBufferW, &size, &lpSystemW);
1330 if (ret == WN_MORE_DATA)
1332 HeapFree(GetProcessHeap(), 0, lpBufferW);
1333 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1335 ret = WNetGetResourceInformationW(lpNetResourceW,
1336 lpBufferW, &size, &lpSystemW);
1338 ret = WN_OUT_OF_MEMORY;
1340 if (ret == WN_SUCCESS)
1342 ret = _thunkNetResourceArrayWToA(lpBufferW,
1343 &count, lpBuffer, cbBuffer);
1344 lpNetResourceW = lpBufferW;
1345 size = sizeof(NETRESOURCEA);
1346 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1347 -1, NULL, 0, NULL, NULL);
1348 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1349 -1, NULL, 0, NULL, NULL);
1351 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1352 -1, NULL, 0, NULL, NULL);
1353 if ((len) && ( size + len < *cbBuffer))
1355 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1356 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1357 *lplpSystem, len, NULL, NULL);
1364 ret = WN_OUT_OF_MEMORY;
1365 HeapFree(GetProcessHeap(), 0, lpBufferW);
1368 ret = WN_OUT_OF_MEMORY;
1369 HeapFree(GetProcessHeap(), 0, lpSystemW);
1371 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1374 ret = WN_NO_NETWORK;
1378 TRACE("Returning %d\n", ret);
1382 /*********************************************************************
1383 * WNetGetResourceInformationW [MPR.@]
1385 * WNetGetResourceInformationW function identifies the network provider
1386 * that owns the resource and gets information about the type of the resource.
1389 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1390 * defines a network resource.
1391 * lpBuffer [ O] the pointer to buffer, containing result. It
1392 * contains NETRESOURCEW structure and strings to
1393 * which the members of the NETRESOURCEW structure
1395 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1397 * lplpSystem [ O] the pointer to string in the output buffer,
1398 * containing the part of the resource name without
1399 * names of the server and share.
1402 * NO_ERROR if the function succeeds. System error code if the function fails.
1405 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1406 LPVOID lpBuffer, LPDWORD cbBuffer,
1407 LPWSTR *lplpSystem )
1409 DWORD ret = WN_NO_NETWORK;
1412 TRACE( "(%p, %p, %p, %p)\n",
1413 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1416 ret = WN_OUT_OF_MEMORY;
1419 /* FIXME: For function value of a variable is indifferent, it does
1420 * search of all providers in a network.
1422 for (index = 0; index < providerTable->numProviders; index++)
1424 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1425 WNNC_DLG_GETRESOURCEINFORMATION)
1427 if (providerTable->table[index].getResourceInformation)
1428 ret = providerTable->table[index].getResourceInformation(
1429 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1431 ret = WN_NO_NETWORK;
1432 if (ret == WN_SUCCESS)
1442 /*********************************************************************
1443 * WNetGetResourceParentA [MPR.@]
1445 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1446 LPVOID lpBuffer, LPDWORD lpBufferSize )
1448 FIXME( "(%p, %p, %p): stub\n",
1449 lpNetResource, lpBuffer, lpBufferSize );
1451 SetLastError(WN_NO_NETWORK);
1452 return WN_NO_NETWORK;
1455 /*********************************************************************
1456 * WNetGetResourceParentW [MPR.@]
1458 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1459 LPVOID lpBuffer, LPDWORD lpBufferSize )
1461 FIXME( "(%p, %p, %p): stub\n",
1462 lpNetResource, lpBuffer, lpBufferSize );
1464 SetLastError(WN_NO_NETWORK);
1465 return WN_NO_NETWORK;
1471 * Connection Functions
1474 /*********************************************************************
1475 * WNetAddConnectionA [MPR.@]
1477 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1478 LPCSTR lpLocalName )
1480 FIXME( "(%s, %p, %s): stub\n",
1481 debugstr_a(lpRemoteName), lpPassword, debugstr_a(lpLocalName) );
1483 SetLastError(WN_NO_NETWORK);
1484 return WN_NO_NETWORK;
1487 /*********************************************************************
1488 * WNetAddConnectionW [MPR.@]
1490 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1491 LPCWSTR lpLocalName )
1493 FIXME( "(%s, %p, %s): stub\n",
1494 debugstr_w(lpRemoteName), lpPassword, debugstr_w(lpLocalName) );
1496 SetLastError(WN_NO_NETWORK);
1497 return WN_NO_NETWORK;
1500 /*********************************************************************
1501 * WNetAddConnection2A [MPR.@]
1503 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1504 LPCSTR lpPassword, LPCSTR lpUserID,
1507 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1508 lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1510 SetLastError(WN_NO_NETWORK);
1511 return WN_NO_NETWORK;
1514 /*********************************************************************
1515 * WNetAddConnection2W [MPR.@]
1517 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1518 LPCWSTR lpPassword, LPCWSTR lpUserID,
1521 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1522 lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1524 SetLastError(WN_NO_NETWORK);
1525 return WN_NO_NETWORK;
1528 /*********************************************************************
1529 * WNetAddConnection3A [MPR.@]
1531 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1532 LPCSTR lpPassword, LPCSTR lpUserID,
1535 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1536 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1538 SetLastError(WN_NO_NETWORK);
1539 return WN_NO_NETWORK;
1542 /*********************************************************************
1543 * WNetAddConnection3W [MPR.@]
1545 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1546 LPCWSTR lpPassword, LPCWSTR lpUserID,
1549 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1550 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1552 SetLastError(WN_NO_NETWORK);
1553 return WN_NO_NETWORK;
1556 /*****************************************************************
1557 * WNetUseConnectionA [MPR.@]
1559 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1560 LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
1561 LPSTR lpAccessName, LPDWORD lpBufferSize,
1564 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1565 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags,
1566 debugstr_a(lpAccessName), lpBufferSize, lpResult );
1568 SetLastError(WN_NO_NETWORK);
1569 return WN_NO_NETWORK;
1572 /*****************************************************************
1573 * WNetUseConnectionW [MPR.@]
1575 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1576 LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags,
1577 LPWSTR lpAccessName, LPDWORD lpBufferSize,
1580 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1581 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags,
1582 debugstr_w(lpAccessName), lpBufferSize, lpResult );
1584 SetLastError(WN_NO_NETWORK);
1585 return WN_NO_NETWORK;
1588 /*********************************************************************
1589 * WNetCancelConnectionA [MPR.@]
1591 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1593 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1598 /*********************************************************************
1599 * WNetCancelConnectionW [MPR.@]
1601 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1603 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1608 /*********************************************************************
1609 * WNetCancelConnection2A [MPR.@]
1611 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1613 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1618 /*********************************************************************
1619 * WNetCancelConnection2W [MPR.@]
1621 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1623 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1628 /*****************************************************************
1629 * WNetRestoreConnectionA [MPR.@]
1631 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
1633 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1635 SetLastError(WN_NO_NETWORK);
1636 return WN_NO_NETWORK;
1639 /*****************************************************************
1640 * WNetRestoreConnectionW [MPR.@]
1642 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
1644 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1646 SetLastError(WN_NO_NETWORK);
1647 return WN_NO_NETWORK;
1650 /**************************************************************************
1651 * WNetGetConnectionA [MPR.@]
1654 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1655 * - WN_NOT_CONNECTED drive is a local drive
1656 * - WN_MORE_DATA buffer isn't big enough
1657 * - WN_SUCCESS success (net path in buffer)
1659 * FIXME: need to test return values under different errors
1661 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1662 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1667 ret = WN_BAD_POINTER;
1668 else if (!lpBufferSize)
1669 ret = WN_BAD_POINTER;
1670 else if (!lpRemoteName && *lpBufferSize)
1671 ret = WN_BAD_POINTER;
1674 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1678 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1682 WCHAR wideRemoteStatic[MAX_PATH];
1683 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1685 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1687 /* try once without memory allocation */
1688 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1690 if (ret == WN_SUCCESS)
1692 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1693 -1, NULL, 0, NULL, NULL);
1695 if (len <= *lpBufferSize)
1697 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1698 lpRemoteName, *lpBufferSize, NULL, NULL);
1703 *lpBufferSize = len;
1707 else if (ret == WN_MORE_DATA)
1709 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1710 wideRemoteSize * sizeof(WCHAR));
1714 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1716 if (ret == WN_SUCCESS)
1718 if (len <= *lpBufferSize)
1720 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1721 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1726 *lpBufferSize = len;
1730 HeapFree(GetProcessHeap(), 0, wideRemote);
1733 ret = WN_OUT_OF_MEMORY;
1735 HeapFree(GetProcessHeap(), 0, wideLocalName);
1738 ret = WN_OUT_OF_MEMORY;
1741 ret = WN_BAD_LOCALNAME;
1745 TRACE("Returning %d\n", ret);
1749 /**************************************************************************
1750 * WNetGetConnectionW [MPR.@]
1752 * FIXME: need to test return values under different errors
1754 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
1755 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
1759 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
1763 ret = WN_BAD_POINTER;
1764 else if (!lpBufferSize)
1765 ret = WN_BAD_POINTER;
1766 else if (!lpRemoteName && *lpBufferSize)
1767 ret = WN_BAD_POINTER;
1768 else if (!lpLocalName[0])
1769 ret = WN_BAD_LOCALNAME;
1772 if (lpLocalName[1] == ':')
1774 switch(GetDriveTypeW(lpLocalName))
1778 static const WCHAR unc[] = { 'u','n','c','\\' };
1779 WCHAR rremote[MAX_PATH], *remote = rremote;
1780 if (!QueryDosDeviceW( lpLocalName, remote, MAX_PATH )) remote[0] = 0;
1781 else if (!strncmpW(remote, unc, 4))
1786 else if (remote[0] != '\\' || remote[1] != '\\')
1787 FIXME("Don't know how to convert %s to an unc\n", debugstr_w(remote));
1789 if (strlenW(remote) + 1 > *lpBufferSize)
1791 *lpBufferSize = strlenW(remote) + 1;
1796 strcpyW( lpRemoteName, remote );
1797 *lpBufferSize = strlenW(lpRemoteName) + 1;
1802 case DRIVE_REMOVABLE:
1805 TRACE("file is local\n");
1806 ret = WN_NOT_CONNECTED;
1809 ret = WN_BAD_LOCALNAME;
1813 ret = WN_BAD_LOCALNAME;
1817 TRACE("Returning %d\n", ret);
1821 /**************************************************************************
1822 * WNetSetConnectionA [MPR.@]
1824 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
1827 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
1829 SetLastError(WN_NO_NETWORK);
1830 return WN_NO_NETWORK;
1833 /**************************************************************************
1834 * WNetSetConnectionW [MPR.@]
1836 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
1839 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
1841 SetLastError(WN_NO_NETWORK);
1842 return WN_NO_NETWORK;
1845 /*****************************************************************
1846 * WNetGetUniversalNameA [MPR.@]
1848 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
1849 LPVOID lpBuffer, LPDWORD lpBufferSize )
1853 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1854 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1856 switch (dwInfoLevel)
1858 case UNIVERSAL_NAME_INFO_LEVEL:
1860 LPUNIVERSAL_NAME_INFOA info = (LPUNIVERSAL_NAME_INFOA)lpBuffer;
1862 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
1863 if (*lpBufferSize < size)
1868 info->lpUniversalName = (char *)info + sizeof(*info);
1869 lstrcpyA(info->lpUniversalName, lpLocalPath);
1870 *lpBufferSize = size;
1874 case REMOTE_NAME_INFO_LEVEL:
1875 err = WN_NO_NETWORK;
1887 /*****************************************************************
1888 * WNetGetUniversalNameW [MPR.@]
1890 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
1891 LPVOID lpBuffer, LPDWORD lpBufferSize )
1895 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1896 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1898 switch (dwInfoLevel)
1900 case UNIVERSAL_NAME_INFO_LEVEL:
1902 LPUNIVERSAL_NAME_INFOW info = (LPUNIVERSAL_NAME_INFOW)lpBuffer;
1904 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
1905 if (*lpBufferSize < size)
1910 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
1911 lstrcpyW(info->lpUniversalName, lpLocalPath);
1912 *lpBufferSize = size;
1916 case REMOTE_NAME_INFO_LEVEL:
1917 err = WN_NO_NETWORK;
1935 /**************************************************************************
1936 * WNetGetUserA [MPR.@]
1938 * FIXME: we should not return ourselves, but the owner of the drive lpName
1940 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
1942 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
1943 return GetLastError();
1946 /*****************************************************************
1947 * WNetGetUserW [MPR.@]
1949 * FIXME: we should not return ourselves, but the owner of the drive lpName
1951 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
1953 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
1954 return GetLastError();
1957 /*********************************************************************
1958 * WNetConnectionDialog [MPR.@]
1960 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
1962 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
1964 SetLastError(WN_NO_NETWORK);
1965 return WN_NO_NETWORK;
1968 /*********************************************************************
1969 * WNetConnectionDialog1A [MPR.@]
1971 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
1973 FIXME( "(%p): stub\n", lpConnDlgStruct );
1975 SetLastError(WN_NO_NETWORK);
1976 return WN_NO_NETWORK;
1979 /*********************************************************************
1980 * WNetConnectionDialog1W [MPR.@]
1982 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
1984 FIXME( "(%p): stub\n", lpConnDlgStruct );
1986 SetLastError(WN_NO_NETWORK);
1987 return WN_NO_NETWORK;
1990 /*********************************************************************
1991 * WNetDisconnectDialog [MPR.@]
1993 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
1995 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
1997 SetLastError(WN_NO_NETWORK);
1998 return WN_NO_NETWORK;
2001 /*********************************************************************
2002 * WNetDisconnectDialog1A [MPR.@]
2004 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2006 FIXME( "(%p): stub\n", lpConnDlgStruct );
2008 SetLastError(WN_NO_NETWORK);
2009 return WN_NO_NETWORK;
2012 /*********************************************************************
2013 * WNetDisconnectDialog1W [MPR.@]
2015 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2017 FIXME( "(%p): stub\n", lpConnDlgStruct );
2019 SetLastError(WN_NO_NETWORK);
2020 return WN_NO_NETWORK;
2023 /*********************************************************************
2024 * WNetGetLastErrorA [MPR.@]
2026 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2027 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2028 LPSTR lpNameBuf, DWORD nNameBufSize )
2030 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2031 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2033 SetLastError(WN_NO_NETWORK);
2034 return WN_NO_NETWORK;
2037 /*********************************************************************
2038 * WNetGetLastErrorW [MPR.@]
2040 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2041 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2042 LPWSTR lpNameBuf, DWORD nNameBufSize )
2044 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2045 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2047 SetLastError(WN_NO_NETWORK);
2048 return WN_NO_NETWORK;
2051 /*********************************************************************
2052 * WNetGetNetworkInformationA [MPR.@]
2054 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2055 LPNETINFOSTRUCT lpNetInfoStruct )
2059 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2062 ret = WN_BAD_POINTER;
2067 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2070 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2074 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2076 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2077 HeapFree(GetProcessHeap(), 0, wideProvider);
2080 ret = WN_OUT_OF_MEMORY;
2083 ret = GetLastError();
2087 TRACE("Returning %d\n", ret);
2091 /*********************************************************************
2092 * WNetGetNetworkInformationW [MPR.@]
2094 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2095 LPNETINFOSTRUCT lpNetInfoStruct )
2099 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2102 ret = WN_BAD_POINTER;
2103 else if (!lpNetInfoStruct)
2104 ret = WN_BAD_POINTER;
2105 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2109 if (providerTable && providerTable->numProviders)
2111 DWORD providerIndex = _findProviderIndexW(lpProvider);
2113 if (providerIndex != BAD_PROVIDER_INDEX)
2115 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2116 lpNetInfoStruct->dwProviderVersion =
2117 providerTable->table[providerIndex].dwSpecVersion;
2118 lpNetInfoStruct->dwStatus = NO_ERROR;
2119 lpNetInfoStruct->dwCharacteristics = 0;
2120 lpNetInfoStruct->dwHandle = (ULONG_PTR)NULL;
2121 lpNetInfoStruct->wNetType =
2122 HIWORD(providerTable->table[providerIndex].dwNetType);
2123 lpNetInfoStruct->dwPrinters = -1;
2124 lpNetInfoStruct->dwDrives = -1;
2128 ret = WN_BAD_PROVIDER;
2131 ret = WN_NO_NETWORK;
2135 TRACE("Returning %d\n", ret);
2139 /*****************************************************************
2140 * WNetGetProviderNameA [MPR.@]
2142 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2143 LPSTR lpProvider, LPDWORD lpBufferSize )
2147 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2151 ret = WN_BAD_POINTER;
2152 else if (!lpBufferSize)
2153 ret = WN_BAD_POINTER;
2160 ret = WN_NO_NETWORK;
2161 for (i = 0; i < providerTable->numProviders &&
2162 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2165 if (i < providerTable->numProviders)
2167 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2168 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2170 if (*lpBufferSize < sizeNeeded)
2172 *lpBufferSize = sizeNeeded;
2177 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2178 -1, lpProvider, *lpBufferSize, NULL, NULL);
2180 /* FIXME: is *lpBufferSize set to the number of characters
2186 ret = WN_NO_NETWORK;
2190 TRACE("Returning %d\n", ret);
2194 /*****************************************************************
2195 * WNetGetProviderNameW [MPR.@]
2197 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2198 LPWSTR lpProvider, LPDWORD lpBufferSize )
2202 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2206 ret = WN_BAD_POINTER;
2207 else if (!lpBufferSize)
2208 ret = WN_BAD_POINTER;
2215 ret = WN_NO_NETWORK;
2216 for (i = 0; i < providerTable->numProviders &&
2217 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2220 if (i < providerTable->numProviders)
2222 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2224 if (*lpBufferSize < sizeNeeded)
2226 *lpBufferSize = sizeNeeded;
2231 strcpyW(lpProvider, providerTable->table[i].name);
2233 /* FIXME: is *lpBufferSize set to the number of characters
2239 ret = WN_NO_NETWORK;
2243 TRACE("Returning %d\n", ret);