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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/debug.h"
31 #include "wine/unicode.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
51 PF_NPOpenEnum openEnum;
52 PF_NPEnumResource enumResource;
53 PF_NPCloseEnum closeEnum;
54 } WNetProvider, *PWNetProvider;
56 typedef struct _WNetProviderTable
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
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
83 typedef struct _WNetEnumerator
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];
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) ==
125 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
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 };
137 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &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);
150 HMODULE hLib = LoadLibraryW(providerPath);
154 PF_NPGetCaps getCaps = (PF_NPGetCaps)GetProcAddress(hLib,
157 TRACE("loaded lib %p\n", hLib);
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++;
198 WARN("Provider %s didn't export NPGetCaps\n",
199 debugstr_w(provider));
200 HeapFree(GetProcessHeap(), 0, name);
206 WARN("Couldn't load library %s for provider %s\n",
207 debugstr_w(providerPath), debugstr_w(provider));
208 HeapFree(GetProcessHeap(), 0, name);
213 WARN("Couldn't get provider name for provider %s\n",
214 debugstr_w(provider));
218 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
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 };
237 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
242 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
245 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
251 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
252 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
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, ',');
269 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
270 sizeof(WNetProviderTable)
271 + (numToAllocate - 1) * sizeof(WNetProvider));
275 int entireNetworkLen;
277 entireNetworkLen = LoadStringW(hInstDll,
278 IDS_ENTIRENETWORK, NULL, 0);
279 providerTable->entireNetwork = HeapAlloc(
280 GetProcessHeap(), 0, (entireNetworkLen + 1) *
282 if (providerTable->entireNetwork)
283 LoadStringW(hInstDll, IDS_ENTIRENETWORK,
284 providerTable->entireNetwork,
285 entireNetworkLen + 1);
286 providerTable->numAllocated = numToAllocate;
287 for (ptr = providers; ptr; )
290 ptr = strchrW(ptr, ',');
293 _tryLoadProvider(ptrPrev);
297 HeapFree(GetProcessHeap(), 0, providers);
310 for (i = 0; i < providerTable->numProviders; i++)
312 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
313 FreeModule(providerTable->table[i].hLib);
315 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
316 HeapFree(GetProcessHeap(), 0, providerTable);
317 providerTable = NULL;
321 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
323 DWORD ret = BAD_PROVIDER_INDEX;
325 if (providerTable && providerTable->numProviders)
329 for (i = 0; i < providerTable->numProviders &&
330 ret == BAD_PROVIDER_INDEX; i++)
331 if (!strcmpW(lpProvider, providerTable->table[i].name))
341 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
347 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
352 memcpy(ret, lpNet, sizeof(ret));
353 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
354 if (lpNet->lpRemoteName)
356 len = strlenW(lpNet->lpRemoteName) + 1;
357 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
358 if (ret->lpRemoteName)
359 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
368 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
372 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
373 HeapFree(GetProcessHeap(), 0, lpNet);
377 static PWNetEnumerator _createNullEnumerator(void)
379 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
380 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
383 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
387 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
388 DWORD dwUsage, LPNETRESOURCEW lpNet)
390 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
391 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
395 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
396 ret->dwScope = dwScope;
397 ret->dwType = dwType;
398 ret->dwUsage = dwUsage;
399 ret->lpNet = _copyNetResourceForEnumW(lpNet);
404 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
405 DWORD dwUsage, DWORD index, HANDLE handle)
409 if (!providerTable || index >= providerTable->numProviders)
413 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
416 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
417 ret->providerIndex = index;
418 ret->dwScope = dwScope;
419 ret->dwType = dwType;
420 ret->dwUsage = dwUsage;
421 ret->handle = handle;
427 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
430 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
431 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
435 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
436 ret->dwScope = dwScope;
437 ret->dwType = dwType;
438 ret->dwUsage = dwUsage;
443 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
444 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
445 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
446 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
447 * if not all members of the array could be thunked, and something else on
450 static DWORD _thunkNetResourceArrayWToA(const LPNETRESOURCEW lpNetArrayIn,
451 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
453 DWORD i, numToThunk, totalBytes, ret;
457 return WN_BAD_POINTER;
459 return WN_BAD_POINTER;
463 return WN_BAD_POINTER;
465 return WN_BAD_POINTER;
467 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
469 LPNETRESOURCEW lpNet = lpNetArrayIn + i;
471 totalBytes += sizeof(NETRESOURCEA);
472 if (lpNet->lpLocalName)
473 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
474 -1, NULL, 0, NULL, NULL);
475 if (lpNet->lpRemoteName)
476 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
477 -1, NULL, 0, NULL, NULL);
478 if (lpNet->lpComment)
479 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
480 -1, NULL, 0, NULL, NULL);
481 if (lpNet->lpProvider)
482 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
483 -1, NULL, 0, NULL, NULL);
484 if (totalBytes < *lpBufferSize)
487 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
488 for (i = 0; i < numToThunk; i++)
490 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
491 LPNETRESOURCEW lpNetIn = lpNetArrayIn + i;
493 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
494 /* lie about string lengths, we already verified how many
495 * we have space for above
497 if (lpNetIn->lpLocalName)
499 lpNetOut->lpLocalName = strNext;
500 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
501 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
503 if (lpNetIn->lpRemoteName)
505 lpNetOut->lpRemoteName = strNext;
506 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
507 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
509 if (lpNetIn->lpComment)
511 lpNetOut->lpComment = strNext;
512 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
513 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
515 if (lpNetIn->lpProvider)
517 lpNetOut->lpProvider = strNext;
518 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
519 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
522 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
523 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk,
528 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
529 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
530 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
531 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
532 * if not all members of the array could be thunked, and something else on
535 static DWORD _thunkNetResourceArrayAToW(const LPNETRESOURCEA lpNetArrayIn,
536 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
538 DWORD i, numToThunk, totalBytes, ret;
542 return WN_BAD_POINTER;
544 return WN_BAD_POINTER;
548 return WN_BAD_POINTER;
550 return WN_BAD_POINTER;
552 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
554 LPNETRESOURCEA lpNet = lpNetArrayIn + i;
556 totalBytes += sizeof(NETRESOURCEW);
557 if (lpNet->lpLocalName)
558 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
559 -1, NULL, 0) * sizeof(WCHAR);
560 if (lpNet->lpRemoteName)
561 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
562 -1, NULL, 0) * sizeof(WCHAR);
563 if (lpNet->lpComment)
564 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
565 -1, NULL, 0) * sizeof(WCHAR);
566 if (lpNet->lpProvider)
567 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
568 -1, NULL, 0) * sizeof(WCHAR);
569 if (totalBytes < *lpBufferSize)
572 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
573 for (i = 0; i < numToThunk; i++)
575 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
576 LPNETRESOURCEA lpNetIn = lpNetArrayIn + i;
578 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
579 /* lie about string lengths, we already verified how many
580 * we have space for above
582 if (lpNetIn->lpLocalName)
584 lpNetOut->lpLocalName = strNext;
585 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
586 -1, lpNetOut->lpLocalName, *lpBufferSize);
588 if (lpNetIn->lpRemoteName)
590 lpNetOut->lpRemoteName = strNext;
591 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
592 -1, lpNetOut->lpRemoteName, *lpBufferSize);
594 if (lpNetIn->lpComment)
596 lpNetOut->lpComment = strNext;
597 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
598 -1, lpNetOut->lpComment, *lpBufferSize);
600 if (lpNetIn->lpProvider)
602 lpNetOut->lpProvider = strNext;
603 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
604 -1, lpNetOut->lpProvider, *lpBufferSize);
607 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
608 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk,
613 /*********************************************************************
614 * WNetOpenEnumA [MPR.@]
616 * See comments for WNetOpenEnumW.
618 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
619 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
623 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
624 dwScope, dwType, dwUsage, lpNet, lphEnum );
627 ret = WN_BAD_POINTER;
628 else if (!providerTable || providerTable->numProviders == 0)
634 LPNETRESOURCEW lpNetWide = NULL;
636 DWORD size = sizeof(buf), count = 1;
637 BOOL allocated = FALSE;
639 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
640 if (ret == WN_MORE_DATA)
642 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
646 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
651 ret = WN_OUT_OF_MEMORY;
653 else if (ret == WN_SUCCESS)
654 lpNetWide = (LPNETRESOURCEW)buf;
655 if (ret == WN_SUCCESS)
656 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
659 HeapFree(GetProcessHeap(), 0, lpNetWide);
662 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
666 TRACE("Returning %ld\n", ret);
670 /*********************************************************************
671 * WNetOpenEnumW [MPR.@]
673 * Network enumeration has way too many parameters, so I'm not positive I got
674 * them right. What I've got so far:
676 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
677 * all the network providers should be enumerated.
679 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
680 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
681 * lpProvider is set, all the network providers should be enumerated.
682 * (This means the enumeration is a list of network providers, not that the
683 * enumeration is passed on to the providers.)
685 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
686 * resource matches the "Entire Network" resource (no remote name, no
687 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
688 * enumeration is done on every network provider.
690 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
691 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
692 * only to the given network provider.
694 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
695 * no lpProvider is set, enumeration will be tried on every network provider,
696 * in the order in which they're loaded.
698 * - The LPNETRESOURCE should be disregarded for scopes besides
699 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
700 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
702 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
703 * resource in the enumerated list, as well as any machines in your
704 * workgroup. The machines in your workgroup come from doing a
705 * RESOURCE_CONTEXT enumeration of every Network Provider.
707 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
708 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
712 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
713 dwScope, dwType, dwUsage, lpNet, lphEnum );
716 ret = WN_BAD_POINTER;
717 else if (!providerTable || providerTable->numProviders == 0)
723 case RESOURCE_GLOBALNET:
726 if (lpNet->lpProvider)
728 DWORD index = _findProviderIndexW(lpNet->lpProvider);
730 if (index != BAD_PROVIDER_INDEX)
732 if (providerTable->table[index].openEnum &&
733 providerTable->table[index].dwEnumScopes & dwScope)
737 ret = providerTable->table[index].openEnum(
738 dwScope, dwType, dwUsage, lpNet, &handle);
739 if (ret == WN_SUCCESS)
742 (HANDLE)_createProviderEnumerator(
743 dwScope, dwType, dwUsage, index, handle);
744 ret = *lphEnum ? WN_SUCCESS :
749 ret = WN_NOT_SUPPORTED;
752 ret = WN_BAD_PROVIDER;
754 else if (lpNet->lpRemoteName)
756 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
757 dwType, dwUsage, lpNet);
758 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
762 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
763 providerTable->entireNetwork))
765 /* comment matches the "Entire Network", enumerate
766 * global scope of every provider
768 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
769 dwType, dwUsage, lpNet);
773 /* this is the same as not having passed lpNet */
774 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
775 dwType, dwUsage, NULL);
777 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
782 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, dwType,
784 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
787 case RESOURCE_CONTEXT:
788 *lphEnum = (HANDLE)_createContextEnumerator(dwScope, dwType,
790 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
792 case RESOURCE_REMEMBERED:
793 case RESOURCE_CONNECTED:
794 *lphEnum = (HANDLE)_createNullEnumerator();
795 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
798 WARN("unknown scope 0x%08lx\n", dwScope);
804 TRACE("Returning %ld\n", ret);
808 /*********************************************************************
809 * WNetEnumResourceA [MPR.@]
811 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
812 LPVOID lpBuffer, LPDWORD lpBufferSize )
816 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
819 ret = WN_BAD_POINTER;
821 ret = WN_BAD_POINTER;
823 ret = WN_BAD_POINTER;
824 else if (!lpBufferSize)
825 ret = WN_BAD_POINTER;
826 else if (*lpBufferSize < sizeof(NETRESOURCEA))
828 *lpBufferSize = sizeof(NETRESOURCEA);
833 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
834 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
838 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
840 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
842 /* FIXME: this isn't necessarily going to work in the case of
843 * WN_MORE_DATA, because our enumerator may have moved on to
844 * the next provider. MSDN states that a large (16KB) buffer
845 * size is the appropriate usage of this function, so
846 * hopefully it won't be an issue.
848 ret = _thunkNetResourceArrayWToA((LPNETRESOURCEW)localBuffer,
849 &localCount, lpBuffer, lpBufferSize);
850 *lpcCount = localCount;
852 HeapFree(GetProcessHeap(), 0, localBuffer);
855 ret = WN_OUT_OF_MEMORY;
859 TRACE("Returning %ld\n", ret);
863 static DWORD _countProviderBytesW(PWNetProvider provider)
869 ret = sizeof(NETRESOURCEW);
870 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
877 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
878 LPVOID lpBuffer, LPDWORD lpBufferSize)
883 return WN_BAD_POINTER;
884 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
887 return WN_BAD_POINTER;
889 return WN_BAD_POINTER;
891 return WN_BAD_POINTER;
892 if (*lpBufferSize < sizeof(NETRESOURCEA))
895 if (!providerTable || enumerator->providerIndex >=
896 providerTable->numProviders)
897 ret = WN_NO_MORE_ENTRIES;
900 DWORD bytes = 0, count = 0, countLimit, i;
901 LPNETRESOURCEW resource;
904 countLimit = *lpcCount == -1 ?
905 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
906 while (count < countLimit && bytes < *lpBufferSize)
908 DWORD bytesNext = _countProviderBytesW(
909 &providerTable->table[count + enumerator->providerIndex]);
911 if (bytes + bytesNext < *lpBufferSize)
917 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
918 for (i = 0, resource = (LPNETRESOURCEW)lpBuffer; i < count;
921 resource->dwScope = RESOURCE_GLOBALNET;
922 resource->dwType = RESOURCETYPE_ANY;
923 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
924 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
925 RESOURCEUSAGE_RESERVED;
926 resource->lpLocalName = NULL;
927 resource->lpRemoteName = strNext;
928 strcpyW(resource->lpRemoteName,
929 providerTable->table[i + enumerator->providerIndex].name);
930 strNext += strlenW(resource->lpRemoteName) + 1;
931 resource->lpComment = NULL;
932 resource->lpProvider = strNext;
933 strcpyW(resource->lpProvider,
934 providerTable->table[i + enumerator->providerIndex].name);
935 strNext += strlenW(resource->lpProvider) + 1;
937 enumerator->providerIndex += count;
939 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
941 TRACE("Returning %ld\n", ret);
945 /* Advances the enumerator (assumed to be a global enumerator) to the next
946 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
947 * not open a handle with the next provider.
948 * If the existing handle is NULL, may leave the enumerator unchanged, since
949 * the current provider may support the desired scope.
950 * If the existing handle is not NULL, closes it before moving on.
951 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
952 * provider, and another error on failure.
954 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
957 return WN_BAD_POINTER;
958 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
960 if (!providerTable || enumerator->providerIndex >=
961 providerTable->numProviders)
962 return WN_NO_MORE_ENTRIES;
964 if (enumerator->providerDone)
966 enumerator->providerDone = FALSE;
967 if (enumerator->handle)
969 providerTable->table[enumerator->providerIndex].closeEnum(
971 enumerator->handle = NULL;
972 enumerator->providerIndex++;
974 for (; enumerator->providerIndex < providerTable->numProviders &&
975 !(enumerator->dwScope & providerTable->table
976 [enumerator->providerIndex].dwEnumScopes);
977 enumerator->providerIndex++)
980 return enumerator->providerIndex < providerTable->numProviders ?
981 WN_SUCCESS : WN_NO_MORE_ENTRIES;
984 /* "Passes through" call to the next provider that supports the enumeration
986 * FIXME: if one call to a provider's enumerator succeeds while there's still
987 * space in lpBuffer, I don't call to the next provider. The caller may not
988 * expect that it should call EnumResourceW again with a return value of
989 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
990 * may have to be moved around a bit, ick.
992 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
993 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
998 return WN_BAD_POINTER;
999 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1000 return WN_BAD_VALUE;
1002 return WN_BAD_POINTER;
1004 return WN_BAD_POINTER;
1006 return WN_BAD_POINTER;
1007 if (*lpBufferSize < sizeof(NETRESOURCEW))
1008 return WN_MORE_DATA;
1010 ret = _globalEnumeratorAdvance(enumerator);
1011 if (ret == WN_SUCCESS)
1013 ret = providerTable->table[enumerator->providerIndex].
1014 openEnum(enumerator->dwScope, enumerator->dwType,
1015 enumerator->dwUsage, enumerator->lpNet,
1016 &enumerator->handle);
1017 if (ret == WN_SUCCESS)
1019 ret = providerTable->table[enumerator->providerIndex].
1020 enumResource(enumerator->handle, lpcCount, lpBuffer,
1022 if (ret != WN_MORE_DATA)
1023 enumerator->providerDone = TRUE;
1026 TRACE("Returning %ld\n", ret);
1030 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1031 LPVOID lpBuffer, LPDWORD lpBufferSize)
1036 return WN_BAD_POINTER;
1037 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1038 return WN_BAD_VALUE;
1040 return WN_BAD_POINTER;
1042 return WN_BAD_POINTER;
1044 return WN_BAD_POINTER;
1045 if (*lpBufferSize < sizeof(NETRESOURCEW))
1046 return WN_MORE_DATA;
1048 return WN_NO_NETWORK;
1050 switch (enumerator->dwScope)
1052 case RESOURCE_GLOBALNET:
1053 if (enumerator->lpNet)
1054 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1055 lpBuffer, lpBufferSize);
1057 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1060 case RESOURCE_CONTEXT:
1061 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1065 WARN("unexpected scope 0x%08lx\n", enumerator->dwScope);
1066 ret = WN_NO_MORE_ENTRIES;
1068 TRACE("Returning %ld\n", ret);
1072 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1073 LPVOID lpBuffer, LPDWORD lpBufferSize)
1076 return WN_BAD_POINTER;
1077 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1078 return WN_BAD_VALUE;
1079 if (!enumerator->handle)
1080 return WN_BAD_VALUE;
1082 return WN_BAD_POINTER;
1084 return WN_BAD_POINTER;
1086 return WN_BAD_POINTER;
1088 return WN_NO_NETWORK;
1089 if (enumerator->providerIndex >= providerTable->numProviders)
1090 return WN_NO_MORE_ENTRIES;
1091 if (!providerTable->table[enumerator->providerIndex].enumResource)
1092 return WN_BAD_VALUE;
1093 return providerTable->table[enumerator->providerIndex].enumResource(
1094 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1097 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1098 LPVOID lpBuffer, LPDWORD lpBufferSize)
1101 size_t cchEntireNetworkLen, bytesNeeded;
1104 return WN_BAD_POINTER;
1105 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1106 return WN_BAD_VALUE;
1108 return WN_BAD_POINTER;
1110 return WN_BAD_POINTER;
1112 return WN_BAD_POINTER;
1114 return WN_NO_NETWORK;
1116 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1117 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1118 if (*lpBufferSize < bytesNeeded)
1120 *lpBufferSize = bytesNeeded;
1125 LPNETRESOURCEW lpNet = (LPNETRESOURCEW)lpBuffer;
1127 lpNet->dwScope = RESOURCE_GLOBALNET;
1128 lpNet->dwType = enumerator->dwType;
1129 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1130 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1131 lpNet->lpLocalName = NULL;
1132 lpNet->lpRemoteName = NULL;
1133 lpNet->lpProvider = NULL;
1134 /* odd, but correct: put comment at end of buffer, so it won't get
1135 * overwritten by subsequent calls to a provider's enumResource
1137 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1138 (cchEntireNetworkLen * sizeof(WCHAR)));
1139 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1142 if (ret == WN_SUCCESS)
1144 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1146 /* "Entire Network" entry enumerated--morph this into a global
1147 * enumerator. enumerator->lpNet continues to be NULL, since it has
1148 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1150 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1151 ret = _enumerateGlobalW(enumerator, lpcCount,
1152 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1153 if (ret == WN_SUCCESS)
1155 /* reflect the fact that we already enumerated "Entire Network" */
1157 *lpBufferSize = bufferSize + bytesNeeded;
1161 /* the provider enumeration failed, but we already succeeded in
1162 * enumerating "Entire Network"--leave type as global to allow a
1163 * retry, but indicate success with a count of one.
1167 *lpBufferSize = bytesNeeded;
1170 TRACE("Returning %ld\n", ret);
1174 /*********************************************************************
1175 * WNetEnumResourceW [MPR.@]
1177 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1178 LPVOID lpBuffer, LPDWORD lpBufferSize )
1182 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1185 ret = WN_BAD_POINTER;
1187 ret = WN_BAD_POINTER;
1189 ret = WN_BAD_POINTER;
1190 else if (!lpBufferSize)
1191 ret = WN_BAD_POINTER;
1192 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1194 *lpBufferSize = sizeof(NETRESOURCEW);
1199 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1201 switch (enumerator->enumType)
1203 case WNET_ENUMERATOR_TYPE_NULL:
1204 ret = WN_NO_MORE_ENTRIES;
1206 case WNET_ENUMERATOR_TYPE_GLOBAL:
1207 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1210 case WNET_ENUMERATOR_TYPE_PROVIDER:
1211 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1214 case WNET_ENUMERATOR_TYPE_CONTEXT:
1215 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1219 WARN("bogus enumerator type!\n");
1220 ret = WN_NO_NETWORK;
1225 TRACE("Returning %ld\n", ret);
1229 /*********************************************************************
1230 * WNetCloseEnum [MPR.@]
1232 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1236 TRACE( "(%p)\n", hEnum );
1240 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1242 switch (enumerator->enumType)
1244 case WNET_ENUMERATOR_TYPE_NULL:
1247 case WNET_ENUMERATOR_TYPE_GLOBAL:
1248 if (enumerator->lpNet)
1249 _freeEnumNetResource(enumerator->lpNet);
1250 if (enumerator->handle)
1251 providerTable->table[enumerator->providerIndex].
1252 closeEnum(enumerator->handle);
1255 case WNET_ENUMERATOR_TYPE_PROVIDER:
1256 if (enumerator->handle)
1257 providerTable->table[enumerator->providerIndex].
1258 closeEnum(enumerator->handle);
1262 WARN("bogus enumerator type!\n");
1263 ret = WN_BAD_HANDLE;
1265 HeapFree(GetProcessHeap(), 0, hEnum);
1268 ret = WN_BAD_HANDLE;
1271 TRACE("Returning %ld\n", ret);
1275 /*********************************************************************
1276 * WNetGetResourceInformationA [MPR.@]
1278 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1279 LPVOID lpBuffer, LPDWORD cbBuffer,
1282 FIXME( "(%p, %p, %p, %p): stub\n",
1283 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1285 SetLastError(WN_NO_NETWORK);
1286 return WN_NO_NETWORK;
1289 /*********************************************************************
1290 * WNetGetResourceInformationW [MPR.@]
1292 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1293 LPVOID lpBuffer, LPDWORD cbBuffer,
1294 LPWSTR *lplpSystem )
1296 FIXME( "(%p, %p, %p, %p): stub\n",
1297 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1299 SetLastError(WN_NO_NETWORK);
1300 return WN_NO_NETWORK;
1303 /*********************************************************************
1304 * WNetGetResourceParentA [MPR.@]
1306 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1307 LPVOID lpBuffer, LPDWORD lpBufferSize )
1309 FIXME( "(%p, %p, %p): stub\n",
1310 lpNetResource, lpBuffer, lpBufferSize );
1312 SetLastError(WN_NO_NETWORK);
1313 return WN_NO_NETWORK;
1316 /*********************************************************************
1317 * WNetGetResourceParentW [MPR.@]
1319 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1320 LPVOID lpBuffer, LPDWORD lpBufferSize )
1322 FIXME( "(%p, %p, %p): stub\n",
1323 lpNetResource, lpBuffer, lpBufferSize );
1325 SetLastError(WN_NO_NETWORK);
1326 return WN_NO_NETWORK;
1332 * Connection Functions
1335 /*********************************************************************
1336 * WNetAddConnectionA [MPR.@]
1338 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1339 LPCSTR lpLocalName )
1341 FIXME( "(%s, %p, %s): stub\n",
1342 debugstr_a(lpRemoteName), lpPassword, debugstr_a(lpLocalName) );
1344 SetLastError(WN_NO_NETWORK);
1345 return WN_NO_NETWORK;
1348 /*********************************************************************
1349 * WNetAddConnectionW [MPR.@]
1351 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1352 LPCWSTR lpLocalName )
1354 FIXME( "(%s, %p, %s): stub\n",
1355 debugstr_w(lpRemoteName), lpPassword, debugstr_w(lpLocalName) );
1357 SetLastError(WN_NO_NETWORK);
1358 return WN_NO_NETWORK;
1361 /*********************************************************************
1362 * WNetAddConnection2A [MPR.@]
1364 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1365 LPCSTR lpPassword, LPCSTR lpUserID,
1368 FIXME( "(%p, %p, %s, 0x%08lX): stub\n",
1369 lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1371 SetLastError(WN_NO_NETWORK);
1372 return WN_NO_NETWORK;
1375 /*********************************************************************
1376 * WNetAddConnection2W [MPR.@]
1378 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1379 LPCWSTR lpPassword, LPCWSTR lpUserID,
1382 FIXME( "(%p, %p, %s, 0x%08lX): stub\n",
1383 lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1385 SetLastError(WN_NO_NETWORK);
1386 return WN_NO_NETWORK;
1389 /*********************************************************************
1390 * WNetAddConnection3A [MPR.@]
1392 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1393 LPCSTR lpPassword, LPCSTR lpUserID,
1396 FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n",
1397 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1399 SetLastError(WN_NO_NETWORK);
1400 return WN_NO_NETWORK;
1403 /*********************************************************************
1404 * WNetAddConnection3W [MPR.@]
1406 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1407 LPCWSTR lpPassword, LPCWSTR lpUserID,
1410 FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n",
1411 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1413 SetLastError(WN_NO_NETWORK);
1414 return WN_NO_NETWORK;
1417 /*****************************************************************
1418 * WNetUseConnectionA [MPR.@]
1420 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1421 LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
1422 LPSTR lpAccessName, LPDWORD lpBufferSize,
1425 FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n",
1426 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags,
1427 debugstr_a(lpAccessName), lpBufferSize, lpResult );
1429 SetLastError(WN_NO_NETWORK);
1430 return WN_NO_NETWORK;
1433 /*****************************************************************
1434 * WNetUseConnectionW [MPR.@]
1436 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1437 LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags,
1438 LPWSTR lpAccessName, LPDWORD lpBufferSize,
1441 FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n",
1442 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags,
1443 debugstr_w(lpAccessName), lpBufferSize, lpResult );
1445 SetLastError(WN_NO_NETWORK);
1446 return WN_NO_NETWORK;
1449 /*********************************************************************
1450 * WNetCancelConnectionA [MPR.@]
1452 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1454 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1459 /*********************************************************************
1460 * WNetCancelConnectionW [MPR.@]
1462 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1464 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1469 /*********************************************************************
1470 * WNetCancelConnection2A [MPR.@]
1472 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1474 FIXME( "(%s, %08lX, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1479 /*********************************************************************
1480 * WNetCancelConnection2W [MPR.@]
1482 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1484 FIXME( "(%s, %08lX, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1489 /*****************************************************************
1490 * WNetRestoreConnectionA [MPR.@]
1492 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPSTR lpszDevice )
1494 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1496 SetLastError(WN_NO_NETWORK);
1497 return WN_NO_NETWORK;
1500 /*****************************************************************
1501 * WNetRestoreConnectionW [MPR.@]
1503 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPWSTR lpszDevice )
1505 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1507 SetLastError(WN_NO_NETWORK);
1508 return WN_NO_NETWORK;
1511 /**************************************************************************
1512 * WNetGetConnectionA [MPR.@]
1515 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1516 * - WN_NOT_CONNECTED drive is a local drive
1517 * - WN_MORE_DATA buffer isn't big enough
1518 * - WN_SUCCESS success (net path in buffer)
1520 * FIXME: need to test return values under different errors
1522 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1523 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1528 ret = WN_BAD_POINTER;
1529 else if (!lpRemoteName)
1530 ret = WN_BAD_POINTER;
1531 else if (!lpBufferSize)
1532 ret = WN_BAD_POINTER;
1535 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1539 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1543 WCHAR wideRemoteStatic[MAX_PATH];
1544 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1546 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1548 /* try once without memory allocation */
1549 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1551 if (ret == WN_SUCCESS)
1553 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1554 -1, NULL, 0, NULL, NULL);
1556 if (len <= *lpBufferSize)
1558 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1559 lpRemoteName, *lpBufferSize, NULL, NULL);
1564 *lpBufferSize = len;
1568 else if (ret == WN_MORE_DATA)
1570 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1571 wideRemoteSize * sizeof(WCHAR));
1575 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1577 if (ret == WN_SUCCESS)
1579 if (len <= *lpBufferSize)
1581 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1582 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1587 *lpBufferSize = len;
1591 HeapFree(GetProcessHeap(), 0, wideRemote);
1594 ret = WN_OUT_OF_MEMORY;
1596 HeapFree(GetProcessHeap(), 0, wideLocalName);
1599 ret = WN_OUT_OF_MEMORY;
1602 ret = WN_BAD_LOCALNAME;
1606 TRACE("Returning %ld\n", ret);
1610 /**************************************************************************
1611 * WNetGetConnectionW [MPR.@]
1613 * FIXME: need to test return values under different errors
1615 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
1616 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
1620 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
1624 ret = WN_BAD_POINTER;
1625 else if (!lpRemoteName)
1626 ret = WN_BAD_POINTER;
1627 else if (!lpBufferSize)
1628 ret = WN_BAD_POINTER;
1629 else if (!lpLocalName[0])
1630 ret = WN_BAD_LOCALNAME;
1633 if (lpLocalName[1] == ':')
1635 switch(GetDriveTypeW(lpLocalName))
1639 WCHAR remote[MAX_PATH];
1640 if (!QueryDosDeviceW( lpLocalName, remote, MAX_PATH )) remote[0] = 0;
1641 if (strlenW(remote) + 1 > *lpBufferSize)
1643 *lpBufferSize = strlenW(remote) + 1;
1648 strcpyW( lpRemoteName, remote );
1649 *lpBufferSize = strlenW(lpRemoteName) + 1;
1654 case DRIVE_REMOVABLE:
1657 TRACE("file is local\n");
1658 ret = WN_NOT_CONNECTED;
1661 ret = WN_BAD_LOCALNAME;
1665 ret = WN_BAD_LOCALNAME;
1669 TRACE("Returning %ld\n", ret);
1673 /**************************************************************************
1674 * WNetSetConnectionA [MPR.@]
1676 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
1679 FIXME( "(%s, %08lX, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
1681 SetLastError(WN_NO_NETWORK);
1682 return WN_NO_NETWORK;
1685 /**************************************************************************
1686 * WNetSetConnectionW [MPR.@]
1688 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
1691 FIXME( "(%s, %08lX, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
1693 SetLastError(WN_NO_NETWORK);
1694 return WN_NO_NETWORK;
1697 /*****************************************************************
1698 * WNetGetUniversalNameA [MPR.@]
1700 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
1701 LPVOID lpBuffer, LPDWORD lpBufferSize )
1703 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
1704 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1706 SetLastError(WN_NO_NETWORK);
1707 return WN_NO_NETWORK;
1710 /*****************************************************************
1711 * WNetGetUniversalNameW [MPR.@]
1713 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
1714 LPVOID lpBuffer, LPDWORD lpBufferSize )
1716 LPUNIVERSAL_NAME_INFOW uniw;
1719 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
1720 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1722 switch (dwInfoLevel)
1724 case UNIVERSAL_NAME_INFO_LEVEL:
1726 len = sizeof (*uniw) + lstrlenW(lpLocalPath);
1727 if (*lpBufferSize <= len)
1730 uniw->lpUniversalName = (LPWSTR) &uniw[1];
1731 lstrcpyW(uniw->lpUniversalName, lpLocalPath);
1732 *lpBufferSize = len;
1736 case REMOTE_NAME_INFO_LEVEL:
1737 err = WN_NO_NETWORK;
1754 /**************************************************************************
1755 * WNetGetUserA [MPR.@]
1757 * FIXME: we should not return ourselves, but the owner of the drive lpName
1759 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
1761 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
1762 return GetLastError();
1765 /*****************************************************************
1766 * WNetGetUserW [MPR.@]
1768 * FIXME: we should not return ourselves, but the owner of the drive lpName
1770 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
1772 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
1773 return GetLastError();
1776 /*********************************************************************
1777 * WNetConnectionDialog [MPR.@]
1779 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
1781 FIXME( "(%p, %08lX): stub\n", hwnd, dwType );
1783 SetLastError(WN_NO_NETWORK);
1784 return WN_NO_NETWORK;
1787 /*********************************************************************
1788 * WNetConnectionDialog1A [MPR.@]
1790 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
1792 FIXME( "(%p): stub\n", lpConnDlgStruct );
1794 SetLastError(WN_NO_NETWORK);
1795 return WN_NO_NETWORK;
1798 /*********************************************************************
1799 * WNetConnectionDialog1W [MPR.@]
1801 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
1803 FIXME( "(%p): stub\n", lpConnDlgStruct );
1805 SetLastError(WN_NO_NETWORK);
1806 return WN_NO_NETWORK;
1809 /*********************************************************************
1810 * WNetDisconnectDialog [MPR.@]
1812 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
1814 FIXME( "(%p, %08lX): stub\n", hwnd, dwType );
1816 SetLastError(WN_NO_NETWORK);
1817 return WN_NO_NETWORK;
1820 /*********************************************************************
1821 * WNetDisconnectDialog1A [MPR.@]
1823 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
1825 FIXME( "(%p): stub\n", lpConnDlgStruct );
1827 SetLastError(WN_NO_NETWORK);
1828 return WN_NO_NETWORK;
1831 /*********************************************************************
1832 * WNetDisconnectDialog1W [MPR.@]
1834 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
1836 FIXME( "(%p): stub\n", lpConnDlgStruct );
1838 SetLastError(WN_NO_NETWORK);
1839 return WN_NO_NETWORK;
1842 /*********************************************************************
1843 * WNetGetLastErrorA [MPR.@]
1845 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
1846 LPSTR lpErrorBuf, DWORD nErrorBufSize,
1847 LPSTR lpNameBuf, DWORD nNameBufSize )
1849 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
1850 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
1852 SetLastError(WN_NO_NETWORK);
1853 return WN_NO_NETWORK;
1856 /*********************************************************************
1857 * WNetGetLastErrorW [MPR.@]
1859 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
1860 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
1861 LPWSTR lpNameBuf, DWORD nNameBufSize )
1863 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
1864 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
1866 SetLastError(WN_NO_NETWORK);
1867 return WN_NO_NETWORK;
1870 /*********************************************************************
1871 * WNetGetNetworkInformationA [MPR.@]
1873 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
1874 LPNETINFOSTRUCT lpNetInfoStruct )
1878 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
1881 ret = WN_BAD_POINTER;
1886 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
1889 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1893 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
1895 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
1896 HeapFree(GetProcessHeap(), 0, wideProvider);
1899 ret = WN_OUT_OF_MEMORY;
1902 ret = GetLastError();
1906 TRACE("Returning %ld\n", ret);
1910 /*********************************************************************
1911 * WNetGetNetworkInformationW [MPR.@]
1913 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
1914 LPNETINFOSTRUCT lpNetInfoStruct )
1918 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
1921 ret = WN_BAD_POINTER;
1922 else if (!lpNetInfoStruct)
1923 ret = WN_BAD_POINTER;
1924 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
1928 if (providerTable && providerTable->numProviders)
1930 DWORD providerIndex = _findProviderIndexW(lpProvider);
1932 if (providerIndex != BAD_PROVIDER_INDEX)
1934 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
1935 lpNetInfoStruct->dwProviderVersion =
1936 providerTable->table[providerIndex].dwSpecVersion;
1937 lpNetInfoStruct->dwStatus = NO_ERROR;
1938 lpNetInfoStruct->dwCharacteristics = 0;
1939 lpNetInfoStruct->dwHandle = (ULONG_PTR)NULL;
1940 lpNetInfoStruct->wNetType =
1941 HIWORD(providerTable->table[providerIndex].dwNetType);
1942 lpNetInfoStruct->dwPrinters = -1;
1943 lpNetInfoStruct->dwDrives = -1;
1947 ret = WN_BAD_PROVIDER;
1950 ret = WN_NO_NETWORK;
1954 TRACE("Returning %ld\n", ret);
1958 /*****************************************************************
1959 * WNetGetProviderNameA [MPR.@]
1961 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
1962 LPSTR lpProvider, LPDWORD lpBufferSize )
1966 TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
1970 ret = WN_BAD_POINTER;
1971 else if (!lpBufferSize)
1972 ret = WN_BAD_POINTER;
1979 ret = WN_NO_NETWORK;
1980 for (i = 0; i < providerTable->numProviders &&
1981 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
1984 if (i < providerTable->numProviders)
1986 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
1987 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
1989 if (*lpBufferSize < sizeNeeded)
1991 *lpBufferSize = sizeNeeded;
1996 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
1997 -1, lpProvider, *lpBufferSize, NULL, NULL);
1999 /* FIXME: is *lpBufferSize set to the number of characters
2005 ret = WN_NO_NETWORK;
2009 TRACE("Returning %ld\n", ret);
2013 /*****************************************************************
2014 * WNetGetProviderNameW [MPR.@]
2016 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2017 LPWSTR lpProvider, LPDWORD lpBufferSize )
2021 TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2025 ret = WN_BAD_POINTER;
2026 else if (!lpBufferSize)
2027 ret = WN_BAD_POINTER;
2034 ret = WN_NO_NETWORK;
2035 for (i = 0; i < providerTable->numProviders &&
2036 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2039 if (i < providerTable->numProviders)
2041 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2043 if (*lpBufferSize < sizeNeeded)
2045 *lpBufferSize = sizeNeeded;
2050 strcpyW(lpProvider, providerTable->table[i].name);
2052 /* FIXME: is *lpBufferSize set to the number of characters
2058 ret = WN_NO_NETWORK;
2062 TRACE("Returning %ld\n", ret);