4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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 = (PWSTR)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 = (PWSTR)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, ',');
266 providerTable = (PWNetProviderTable)
267 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
268 sizeof(WNetProviderTable)
269 + (numToAllocate - 1) * sizeof(WNetProvider));
273 int entireNetworkLen;
275 entireNetworkLen = LoadStringW(hInstDll,
276 IDS_ENTIRENETWORK, NULL, 0);
277 providerTable->entireNetwork = (LPWSTR)HeapAlloc(
278 GetProcessHeap(), 0, (entireNetworkLen + 1) *
280 if (providerTable->entireNetwork)
281 LoadStringW(hInstDll, IDS_ENTIRENETWORK,
282 providerTable->entireNetwork,
283 entireNetworkLen + 1);
284 providerTable->numAllocated = numToAllocate;
285 for (ptr = providers; ptr; )
288 ptr = strchrW(ptr, ',');
291 _tryLoadProvider(ptrPrev);
295 HeapFree(GetProcessHeap(), 0, providers);
308 for (i = 0; i < providerTable->numProviders; i++)
310 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
311 FreeModule(providerTable->table[i].hLib);
313 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
314 HeapFree(GetProcessHeap(), 0, providerTable);
315 providerTable = NULL;
319 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
321 DWORD ret = BAD_PROVIDER_INDEX;
323 if (providerTable && providerTable->numProviders)
327 for (i = 0; i < providerTable->numProviders &&
328 ret == BAD_PROVIDER_INDEX; i++)
329 if (!strcmpW(lpProvider, providerTable->table[i].name))
339 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
345 ret = (LPNETRESOURCEW)HeapAlloc(GetProcessHeap(), 0,
346 sizeof(NETRESOURCEW));
351 memcpy(ret, lpNet, sizeof(ret));
352 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
353 if (lpNet->lpRemoteName)
355 len = strlenW(lpNet->lpRemoteName) + 1;
356 ret->lpRemoteName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
357 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 = (PWNetEnumerator)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 = (PWNetEnumerator)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 = (PWNetEnumerator)HeapAlloc(GetProcessHeap(),
414 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
417 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
418 ret->providerIndex = index;
419 ret->dwScope = dwScope;
420 ret->dwType = dwType;
421 ret->dwUsage = dwUsage;
422 ret->handle = handle;
428 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
431 PWNetEnumerator ret = (PWNetEnumerator)HeapAlloc(GetProcessHeap(),
432 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
436 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
437 ret->dwScope = dwScope;
438 ret->dwType = dwType;
439 ret->dwUsage = dwUsage;
444 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
445 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
446 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
447 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
448 * if not all members of the array could be thunked, and something else on
451 static DWORD _thunkNetResourceArrayWToA(const LPNETRESOURCEW lpNetArrayIn,
452 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
454 DWORD i, numToThunk, totalBytes, ret;
458 return WN_BAD_POINTER;
460 return WN_BAD_POINTER;
464 return WN_BAD_POINTER;
466 return WN_BAD_POINTER;
468 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
470 LPNETRESOURCEW lpNet = lpNetArrayIn + i;
472 totalBytes += sizeof(NETRESOURCEA);
473 if (lpNet->lpLocalName)
474 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
475 -1, NULL, 0, NULL, NULL);
476 if (lpNet->lpRemoteName)
477 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
478 -1, NULL, 0, NULL, NULL);
479 if (lpNet->lpComment)
480 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
481 -1, NULL, 0, NULL, NULL);
482 if (lpNet->lpProvider)
483 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
484 -1, NULL, 0, NULL, NULL);
485 if (totalBytes < *lpBufferSize)
488 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
489 for (i = 0; i < numToThunk; i++)
491 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
492 LPNETRESOURCEW lpNetIn = lpNetArrayIn + i;
494 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
495 /* lie about string lengths, we already verified how many
496 * we have space for above
498 if (lpNetIn->lpLocalName)
500 lpNetOut->lpLocalName = strNext;
501 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
502 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
504 if (lpNetIn->lpRemoteName)
506 lpNetOut->lpRemoteName = strNext;
507 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
508 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
510 if (lpNetIn->lpComment)
512 lpNetOut->lpComment = strNext;
513 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
514 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
516 if (lpNetIn->lpProvider)
518 lpNetOut->lpProvider = strNext;
519 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
520 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
523 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
524 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk,
529 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
530 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
531 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
532 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
533 * if not all members of the array could be thunked, and something else on
536 static DWORD _thunkNetResourceArrayAToW(const LPNETRESOURCEA lpNetArrayIn,
537 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
539 DWORD i, numToThunk, totalBytes, ret;
543 return WN_BAD_POINTER;
545 return WN_BAD_POINTER;
549 return WN_BAD_POINTER;
551 return WN_BAD_POINTER;
553 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
555 LPNETRESOURCEA lpNet = lpNetArrayIn + i;
557 totalBytes += sizeof(NETRESOURCEW);
558 if (lpNet->lpLocalName)
559 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
560 -1, NULL, 0) * sizeof(WCHAR);
561 if (lpNet->lpRemoteName)
562 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
563 -1, NULL, 0) * sizeof(WCHAR);
564 if (lpNet->lpComment)
565 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
566 -1, NULL, 0) * sizeof(WCHAR);
567 if (lpNet->lpProvider)
568 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
569 -1, NULL, 0) * sizeof(WCHAR);
570 if (totalBytes < *lpBufferSize)
573 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
574 for (i = 0; i < numToThunk; i++)
576 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
577 LPNETRESOURCEA lpNetIn = lpNetArrayIn + i;
579 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
580 /* lie about string lengths, we already verified how many
581 * we have space for above
583 if (lpNetIn->lpLocalName)
585 lpNetOut->lpLocalName = strNext;
586 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
587 -1, lpNetOut->lpLocalName, *lpBufferSize);
589 if (lpNetIn->lpRemoteName)
591 lpNetOut->lpRemoteName = strNext;
592 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
593 -1, lpNetOut->lpRemoteName, *lpBufferSize);
595 if (lpNetIn->lpComment)
597 lpNetOut->lpComment = strNext;
598 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
599 -1, lpNetOut->lpComment, *lpBufferSize);
601 if (lpNetIn->lpProvider)
603 lpNetOut->lpProvider = strNext;
604 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
605 -1, lpNetOut->lpProvider, *lpBufferSize);
608 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
609 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk,
614 /*********************************************************************
615 * WNetOpenEnumA [MPR.@]
617 * See comments for WNetOpenEnumW.
619 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
620 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
624 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
625 dwScope, dwType, dwUsage, lpNet, lphEnum );
628 ret = WN_BAD_POINTER;
629 else if (!providerTable || providerTable->numProviders == 0)
635 LPNETRESOURCEW lpNetWide = NULL;
637 DWORD size = sizeof(buf), count = 1;
638 BOOL allocated = FALSE;
640 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
641 if (ret == WN_MORE_DATA)
643 lpNetWide = (LPNETRESOURCEW)HeapAlloc(GetProcessHeap(), 0,
647 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
652 ret = WN_OUT_OF_MEMORY;
654 else if (ret == WN_SUCCESS)
655 lpNetWide = (LPNETRESOURCEW)buf;
656 if (ret == WN_SUCCESS)
657 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
659 if (allocated && lpNetWide)
660 HeapFree(GetProcessHeap(), 0, lpNetWide);
663 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
667 TRACE("Returning %ld\n", ret);
671 /*********************************************************************
672 * WNetOpenEnumW [MPR.@]
674 * Network enumeration has way too many parameters, so I'm not positive I got
675 * them right. What I've got so far:
677 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
678 * all the network providers should be enumerated.
680 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
681 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
682 * lpProvider is set, all the network providers should be enumerated.
683 * (This means the enumeration is a list of network providers, not that the
684 * enumeration is passed on to the providers.)
686 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
687 * resource matches the "Entire Network" resource (no remote name, no
688 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
689 * enumeration is done on every network provider.
691 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
692 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
693 * only to the given network provider.
695 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
696 * no lpProvider is set, enumeration will be tried on every network provider,
697 * in the order in which they're loaded.
699 * - The LPNETRESOURCE should be disregarded for scopes besides
700 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
701 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
703 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
704 * resource in the enumerated list, as well as any machines in your
705 * workgroup. The machines in your workgroup come from doing a
706 * RESOURCE_CONTEXT enumeration of every Network Provider.
708 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
709 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
713 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
714 dwScope, dwType, dwUsage, lpNet, lphEnum );
717 ret = WN_BAD_POINTER;
718 else if (!providerTable || providerTable->numProviders == 0)
724 case RESOURCE_GLOBALNET:
727 if (lpNet->lpProvider)
729 DWORD index = _findProviderIndexW(lpNet->lpProvider);
731 if (index != BAD_PROVIDER_INDEX)
733 if (providerTable->table[index].openEnum &&
734 providerTable->table[index].dwEnumScopes & dwScope)
738 ret = providerTable->table[index].openEnum(
739 dwScope, dwType, dwUsage, lpNet, &handle);
740 if (ret == WN_SUCCESS)
743 (HANDLE)_createProviderEnumerator(
744 dwScope, dwType, dwUsage, index, handle);
745 ret = *lphEnum ? WN_SUCCESS :
750 ret = WN_NOT_SUPPORTED;
753 ret = WN_BAD_PROVIDER;
755 else if (lpNet->lpRemoteName)
757 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
758 dwType, dwUsage, lpNet);
759 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
763 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
764 providerTable->entireNetwork))
766 /* comment matches the "Entire Network", enumerate
767 * global scope of every provider
769 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
770 dwType, dwUsage, lpNet);
774 /* this is the same as not having passed lpNet */
775 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
776 dwType, dwUsage, NULL);
778 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
783 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, dwType,
785 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
788 case RESOURCE_CONTEXT:
789 *lphEnum = (HANDLE)_createContextEnumerator(dwScope, dwType,
791 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
793 case RESOURCE_REMEMBERED:
794 case RESOURCE_CONNECTED:
795 *lphEnum = (HANDLE)_createNullEnumerator();
796 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
799 WARN("unknown scope 0x%08lx\n", dwScope);
805 TRACE("Returning %ld\n", ret);
809 /*********************************************************************
810 * WNetEnumResourceA [MPR.@]
812 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
813 LPVOID lpBuffer, LPDWORD lpBufferSize )
817 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
820 ret = WN_BAD_POINTER;
822 ret = WN_BAD_POINTER;
824 ret = WN_BAD_POINTER;
825 else if (!lpBufferSize)
826 ret = WN_BAD_POINTER;
827 else if (*lpBufferSize < sizeof(NETRESOURCEA))
829 *lpBufferSize = sizeof(NETRESOURCEA);
834 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
835 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
839 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
841 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
843 /* FIXME: this isn't necessarily going to work in the case of
844 * WN_MORE_DATA, because our enumerator may have moved on to
845 * the next provider. MSDN states that a large (16KB) buffer
846 * size is the appropriate usage of this function, so
847 * hopefully it won't be an issue.
849 ret = _thunkNetResourceArrayWToA((LPNETRESOURCEW)localBuffer,
850 &localCount, lpBuffer, lpBufferSize);
851 *lpcCount = localCount;
853 HeapFree(GetProcessHeap(), 0, localBuffer);
856 ret = WN_OUT_OF_MEMORY;
860 TRACE("Returning %ld\n", ret);
864 static DWORD _countProviderBytesW(PWNetProvider provider)
870 ret = sizeof(NETRESOURCEW);
871 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
878 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
879 LPVOID lpBuffer, LPDWORD lpBufferSize)
884 return WN_BAD_POINTER;
885 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
888 return WN_BAD_POINTER;
890 return WN_BAD_POINTER;
892 return WN_BAD_POINTER;
893 if (*lpBufferSize < sizeof(NETRESOURCEA))
896 if (!providerTable || enumerator->providerIndex >=
897 providerTable->numProviders)
898 ret = WN_NO_MORE_ENTRIES;
901 DWORD bytes = 0, count = 0, countLimit, i;
902 LPNETRESOURCEW resource;
905 countLimit = *lpcCount == -1 ?
906 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
907 while (count < countLimit && bytes < *lpBufferSize)
909 DWORD bytesNext = _countProviderBytesW(
910 &providerTable->table[count + enumerator->providerIndex]);
912 if (bytes + bytesNext < *lpBufferSize)
918 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
919 for (i = 0, resource = (LPNETRESOURCEW)lpBuffer; i < count;
922 resource->dwScope = RESOURCE_GLOBALNET;
923 resource->dwType = RESOURCETYPE_ANY;
924 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
925 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
926 RESOURCEUSAGE_RESERVED;
927 resource->lpLocalName = NULL;
928 resource->lpRemoteName = strNext;
929 strcpyW(resource->lpRemoteName,
930 providerTable->table[i + enumerator->providerIndex].name);
931 strNext += strlenW(resource->lpRemoteName) + 1;
932 resource->lpComment = NULL;
933 resource->lpProvider = strNext;
934 strcpyW(resource->lpProvider,
935 providerTable->table[i + enumerator->providerIndex].name);
936 strNext += strlenW(resource->lpProvider) + 1;
938 enumerator->providerIndex += count;
940 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
942 TRACE("Returning %ld\n", ret);
946 /* Advances the enumerator (assumed to be a global enumerator) to the next
947 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
948 * not open a handle with the next provider.
949 * If the existing handle is NULL, may leave the enumerator unchanged, since
950 * the current provider may support the desired scope.
951 * If the existing handle is not NULL, closes it before moving on.
952 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
953 * provider, and another error on failure.
955 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
958 return WN_BAD_POINTER;
959 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
961 if (!providerTable || enumerator->providerIndex >=
962 providerTable->numProviders)
963 return WN_NO_MORE_ENTRIES;
965 if (enumerator->providerDone)
967 enumerator->providerDone = FALSE;
968 if (enumerator->handle)
970 providerTable->table[enumerator->providerIndex].closeEnum(
972 enumerator->handle = NULL;
973 enumerator->providerIndex++;
975 for (; enumerator->providerIndex < providerTable->numProviders &&
976 !(enumerator->dwScope & providerTable->table
977 [enumerator->providerIndex].dwEnumScopes);
978 enumerator->providerIndex++)
981 return enumerator->providerIndex < providerTable->numProviders ?
982 WN_SUCCESS : WN_NO_MORE_ENTRIES;
985 /* "Passes through" call to the next provider that supports the enumeration
987 * FIXME: if one call to a provider's enumerator succeeds while there's still
988 * space in lpBuffer, I don't call to the next provider. The caller may not
989 * expect that it should call EnumResourceW again with a return value of
990 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
991 * may have to be moved around a bit, ick.
993 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
994 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
999 return WN_BAD_POINTER;
1000 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1001 return WN_BAD_VALUE;
1003 return WN_BAD_POINTER;
1005 return WN_BAD_POINTER;
1007 return WN_BAD_POINTER;
1008 if (*lpBufferSize < sizeof(NETRESOURCEW))
1009 return WN_MORE_DATA;
1011 ret = _globalEnumeratorAdvance(enumerator);
1012 if (ret == WN_SUCCESS)
1014 ret = providerTable->table[enumerator->providerIndex].
1015 openEnum(enumerator->dwScope, enumerator->dwType,
1016 enumerator->dwUsage, enumerator->lpNet,
1017 &enumerator->handle);
1018 if (ret == WN_SUCCESS)
1020 ret = providerTable->table[enumerator->providerIndex].
1021 enumResource(enumerator->handle, lpcCount, lpBuffer,
1023 if (ret != WN_MORE_DATA)
1024 enumerator->providerDone = TRUE;
1027 TRACE("Returning %ld\n", ret);
1031 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1032 LPVOID lpBuffer, LPDWORD lpBufferSize)
1037 return WN_BAD_POINTER;
1038 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1039 return WN_BAD_VALUE;
1041 return WN_BAD_POINTER;
1043 return WN_BAD_POINTER;
1045 return WN_BAD_POINTER;
1046 if (*lpBufferSize < sizeof(NETRESOURCEW))
1047 return WN_MORE_DATA;
1049 return WN_NO_NETWORK;
1051 switch (enumerator->dwScope)
1053 case RESOURCE_GLOBALNET:
1054 if (enumerator->lpNet)
1055 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1056 lpBuffer, lpBufferSize);
1058 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1061 case RESOURCE_CONTEXT:
1062 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1066 WARN("unexpected scope 0x%08lx\n", enumerator->dwScope);
1067 ret = WN_NO_MORE_ENTRIES;
1069 TRACE("Returning %ld\n", ret);
1073 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1074 LPVOID lpBuffer, LPDWORD lpBufferSize)
1077 return WN_BAD_POINTER;
1078 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1079 return WN_BAD_VALUE;
1080 if (!enumerator->handle)
1081 return WN_BAD_VALUE;
1083 return WN_BAD_POINTER;
1085 return WN_BAD_POINTER;
1087 return WN_BAD_POINTER;
1089 return WN_NO_NETWORK;
1090 if (enumerator->providerIndex >= providerTable->numProviders)
1091 return WN_NO_MORE_ENTRIES;
1092 if (!providerTable->table[enumerator->providerIndex].enumResource)
1093 return WN_BAD_VALUE;
1094 return providerTable->table[enumerator->providerIndex].enumResource(
1095 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1098 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1099 LPVOID lpBuffer, LPDWORD lpBufferSize)
1102 size_t cchEntireNetworkLen, bytesNeeded;
1105 return WN_BAD_POINTER;
1106 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1107 return WN_BAD_VALUE;
1109 return WN_BAD_POINTER;
1111 return WN_BAD_POINTER;
1113 return WN_BAD_POINTER;
1115 return WN_NO_NETWORK;
1117 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1118 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1119 if (*lpBufferSize < bytesNeeded)
1121 *lpBufferSize = bytesNeeded;
1126 LPNETRESOURCEW lpNet = (LPNETRESOURCEW)lpBuffer;
1128 lpNet->dwScope = RESOURCE_GLOBALNET;
1129 lpNet->dwType = enumerator->dwType;
1130 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1131 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1132 lpNet->lpLocalName = NULL;
1133 lpNet->lpRemoteName = NULL;
1134 lpNet->lpProvider = NULL;
1135 /* odd, but correct: put comment at end of buffer, so it won't get
1136 * overwritten by subsequent calls to a provider's enumResource
1138 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1139 (cchEntireNetworkLen * sizeof(WCHAR)));
1140 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1143 if (ret == WN_SUCCESS)
1145 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1147 /* "Entire Network" entry enumerated--morph this into a global
1148 * enumerator. enumerator->lpNet continues to be NULL, since it has
1149 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1151 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1152 ret = _enumerateGlobalW(enumerator, lpcCount,
1153 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1154 if (ret == WN_SUCCESS)
1156 /* reflect the fact that we already enumerated "Entire Network" */
1158 *lpBufferSize = bufferSize + bytesNeeded;
1162 /* the provider enumeration failed, but we already succeeded in
1163 * enumerating "Entire Network"--leave type as global to allow a
1164 * retry, but indicate success with a count of one.
1168 *lpBufferSize = bytesNeeded;
1171 TRACE("Returning %ld\n", ret);
1175 /*********************************************************************
1176 * WNetEnumResourceW [MPR.@]
1178 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1179 LPVOID lpBuffer, LPDWORD lpBufferSize )
1183 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1186 ret = WN_BAD_POINTER;
1188 ret = WN_BAD_POINTER;
1190 ret = WN_BAD_POINTER;
1191 else if (!lpBufferSize)
1192 ret = WN_BAD_POINTER;
1193 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1195 *lpBufferSize = sizeof(NETRESOURCEW);
1200 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1202 switch (enumerator->enumType)
1204 case WNET_ENUMERATOR_TYPE_NULL:
1205 ret = WN_NO_MORE_ENTRIES;
1207 case WNET_ENUMERATOR_TYPE_GLOBAL:
1208 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1211 case WNET_ENUMERATOR_TYPE_PROVIDER:
1212 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1215 case WNET_ENUMERATOR_TYPE_CONTEXT:
1216 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1220 WARN("bogus enumerator type!\n");
1221 ret = WN_NO_NETWORK;
1226 TRACE("Returning %ld\n", ret);
1230 /*********************************************************************
1231 * WNetCloseEnum [MPR.@]
1233 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1237 TRACE( "(%p)\n", hEnum );
1241 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1243 switch (enumerator->enumType)
1245 case WNET_ENUMERATOR_TYPE_NULL:
1248 case WNET_ENUMERATOR_TYPE_GLOBAL:
1249 if (enumerator->lpNet)
1250 _freeEnumNetResource(enumerator->lpNet);
1251 if (enumerator->handle)
1252 providerTable->table[enumerator->providerIndex].
1253 closeEnum(enumerator->handle);
1256 case WNET_ENUMERATOR_TYPE_PROVIDER:
1257 if (enumerator->handle)
1258 providerTable->table[enumerator->providerIndex].
1259 closeEnum(enumerator->handle);
1263 WARN("bogus enumerator type!\n");
1264 ret = WN_BAD_HANDLE;
1266 HeapFree(GetProcessHeap(), 0, hEnum);
1269 ret = WN_BAD_HANDLE;
1272 TRACE("Returning %ld\n", ret);
1276 /*********************************************************************
1277 * WNetGetResourceInformationA [MPR.@]
1279 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1280 LPVOID lpBuffer, LPDWORD cbBuffer,
1283 FIXME( "(%p, %p, %p, %p): stub\n",
1284 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1286 SetLastError(WN_NO_NETWORK);
1287 return WN_NO_NETWORK;
1290 /*********************************************************************
1291 * WNetGetResourceInformationW [MPR.@]
1293 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1294 LPVOID lpBuffer, LPDWORD cbBuffer,
1295 LPWSTR *lplpSystem )
1297 FIXME( "(%p, %p, %p, %p): stub\n",
1298 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1300 SetLastError(WN_NO_NETWORK);
1301 return WN_NO_NETWORK;
1304 /*********************************************************************
1305 * WNetGetResourceParentA [MPR.@]
1307 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1308 LPVOID lpBuffer, LPDWORD lpBufferSize )
1310 FIXME( "(%p, %p, %p): stub\n",
1311 lpNetResource, lpBuffer, lpBufferSize );
1313 SetLastError(WN_NO_NETWORK);
1314 return WN_NO_NETWORK;
1317 /*********************************************************************
1318 * WNetGetResourceParentW [MPR.@]
1320 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1321 LPVOID lpBuffer, LPDWORD lpBufferSize )
1323 FIXME( "(%p, %p, %p): stub\n",
1324 lpNetResource, lpBuffer, lpBufferSize );
1326 SetLastError(WN_NO_NETWORK);
1327 return WN_NO_NETWORK;
1333 * Connection Functions
1336 /*********************************************************************
1337 * WNetAddConnectionA [MPR.@]
1339 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1340 LPCSTR lpLocalName )
1342 FIXME( "(%s, %p, %s): stub\n",
1343 debugstr_a(lpRemoteName), lpPassword, debugstr_a(lpLocalName) );
1345 SetLastError(WN_NO_NETWORK);
1346 return WN_NO_NETWORK;
1349 /*********************************************************************
1350 * WNetAddConnectionW [MPR.@]
1352 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1353 LPCWSTR lpLocalName )
1355 FIXME( "(%s, %p, %s): stub\n",
1356 debugstr_w(lpRemoteName), lpPassword, debugstr_w(lpLocalName) );
1358 SetLastError(WN_NO_NETWORK);
1359 return WN_NO_NETWORK;
1362 /*********************************************************************
1363 * WNetAddConnection2A [MPR.@]
1365 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1366 LPCSTR lpPassword, LPCSTR lpUserID,
1369 FIXME( "(%p, %p, %s, 0x%08lX): stub\n",
1370 lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1372 SetLastError(WN_NO_NETWORK);
1373 return WN_NO_NETWORK;
1376 /*********************************************************************
1377 * WNetAddConnection2W [MPR.@]
1379 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1380 LPCWSTR lpPassword, LPCWSTR lpUserID,
1383 FIXME( "(%p, %p, %s, 0x%08lX): stub\n",
1384 lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1386 SetLastError(WN_NO_NETWORK);
1387 return WN_NO_NETWORK;
1390 /*********************************************************************
1391 * WNetAddConnection3A [MPR.@]
1393 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1394 LPCSTR lpPassword, LPCSTR lpUserID,
1397 FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n",
1398 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1400 SetLastError(WN_NO_NETWORK);
1401 return WN_NO_NETWORK;
1404 /*********************************************************************
1405 * WNetAddConnection3W [MPR.@]
1407 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1408 LPCWSTR lpPassword, LPCWSTR lpUserID,
1411 FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n",
1412 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1414 SetLastError(WN_NO_NETWORK);
1415 return WN_NO_NETWORK;
1418 /*****************************************************************
1419 * WNetUseConnectionA [MPR.@]
1421 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1422 LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
1423 LPSTR lpAccessName, LPDWORD lpBufferSize,
1426 FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n",
1427 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags,
1428 debugstr_a(lpAccessName), lpBufferSize, lpResult );
1430 SetLastError(WN_NO_NETWORK);
1431 return WN_NO_NETWORK;
1434 /*****************************************************************
1435 * WNetUseConnectionW [MPR.@]
1437 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1438 LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags,
1439 LPWSTR lpAccessName, LPDWORD lpBufferSize,
1442 FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n",
1443 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags,
1444 debugstr_w(lpAccessName), lpBufferSize, lpResult );
1446 SetLastError(WN_NO_NETWORK);
1447 return WN_NO_NETWORK;
1450 /*********************************************************************
1451 * WNetCancelConnectionA [MPR.@]
1453 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1455 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1460 /*********************************************************************
1461 * WNetCancelConnectionW [MPR.@]
1463 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1465 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1470 /*********************************************************************
1471 * WNetCancelConnection2A [MPR.@]
1473 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1475 FIXME( "(%s, %08lX, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1480 /*********************************************************************
1481 * WNetCancelConnection2W [MPR.@]
1483 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1485 FIXME( "(%s, %08lX, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1490 /*****************************************************************
1491 * WNetRestoreConnectionA [MPR.@]
1493 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPSTR lpszDevice )
1495 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1497 SetLastError(WN_NO_NETWORK);
1498 return WN_NO_NETWORK;
1501 /*****************************************************************
1502 * WNetRestoreConnectionW [MPR.@]
1504 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPWSTR lpszDevice )
1506 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1508 SetLastError(WN_NO_NETWORK);
1509 return WN_NO_NETWORK;
1512 /**************************************************************************
1513 * WNetGetConnectionA [MPR.@]
1516 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1517 * - WN_NOT_CONNECTED drive is a local drive
1518 * - WN_MORE_DATA buffer isn't big enough
1519 * - WN_SUCCESS success (net path in buffer)
1521 * FIXME: need to test return values under different errors
1523 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1524 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1529 ret = WN_BAD_POINTER;
1530 else if (!lpRemoteName)
1531 ret = WN_BAD_POINTER;
1532 else if (!lpBufferSize)
1533 ret = WN_BAD_POINTER;
1536 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1540 PWSTR wideLocalName = (PWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1544 WCHAR wideRemoteStatic[MAX_PATH];
1545 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1547 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1549 /* try once without memory allocation */
1550 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1552 if (ret == WN_SUCCESS)
1554 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1555 -1, NULL, 0, NULL, NULL);
1557 if (len <= *lpBufferSize)
1559 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1560 lpRemoteName, *lpBufferSize, NULL, NULL);
1565 *lpBufferSize = len;
1569 else if (ret == WN_MORE_DATA)
1571 PWSTR wideRemote = (PWSTR)HeapAlloc(GetProcessHeap(), 0,
1572 wideRemoteSize * sizeof(WCHAR));
1576 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1578 if (ret == WN_SUCCESS)
1580 if (len <= *lpBufferSize)
1582 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1583 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1588 *lpBufferSize = len;
1592 HeapFree(GetProcessHeap(), 0, wideRemote);
1595 ret = WN_OUT_OF_MEMORY;
1597 HeapFree(GetProcessHeap(), 0, wideLocalName);
1600 ret = WN_OUT_OF_MEMORY;
1603 ret = WN_BAD_LOCALNAME;
1607 TRACE("Returning %ld\n", ret);
1611 /**************************************************************************
1612 * WNetGetConnectionW [MPR.@]
1614 * FIXME: need to test return values under different errors
1616 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
1617 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
1621 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
1625 ret = WN_BAD_POINTER;
1626 else if (!lpRemoteName)
1627 ret = WN_BAD_POINTER;
1628 else if (!lpBufferSize)
1629 ret = WN_BAD_POINTER;
1630 else if (!lpLocalName[0])
1631 ret = WN_BAD_LOCALNAME;
1634 if (lpLocalName[1] == ':')
1636 switch(GetDriveTypeW(lpLocalName))
1640 WCHAR remote[MAX_PATH];
1641 if (!QueryDosDeviceW( lpLocalName, remote, MAX_PATH )) remote[0] = 0;
1642 if (strlenW(remote) + 1 > *lpBufferSize)
1644 *lpBufferSize = strlenW(remote) + 1;
1649 strcpyW( lpRemoteName, remote );
1650 *lpBufferSize = strlenW(lpRemoteName) + 1;
1655 case DRIVE_REMOVABLE:
1658 TRACE("file is local\n");
1659 ret = WN_NOT_CONNECTED;
1662 ret = WN_BAD_LOCALNAME;
1666 ret = WN_BAD_LOCALNAME;
1670 TRACE("Returning %ld\n", ret);
1674 /**************************************************************************
1675 * WNetSetConnectionA [MPR.@]
1677 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
1680 FIXME( "(%s, %08lX, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
1682 SetLastError(WN_NO_NETWORK);
1683 return WN_NO_NETWORK;
1686 /**************************************************************************
1687 * WNetSetConnectionW [MPR.@]
1689 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
1692 FIXME( "(%s, %08lX, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
1694 SetLastError(WN_NO_NETWORK);
1695 return WN_NO_NETWORK;
1698 /*****************************************************************
1699 * WNetGetUniversalNameA [MPR.@]
1701 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
1702 LPVOID lpBuffer, LPDWORD lpBufferSize )
1704 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
1705 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1707 SetLastError(WN_NO_NETWORK);
1708 return WN_NO_NETWORK;
1711 /*****************************************************************
1712 * WNetGetUniversalNameW [MPR.@]
1714 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
1715 LPVOID lpBuffer, LPDWORD lpBufferSize )
1717 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
1718 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1720 SetLastError(WN_NO_NETWORK);
1721 return WN_NO_NETWORK;
1730 /**************************************************************************
1731 * WNetGetUserA [MPR.@]
1733 * FIXME: we should not return ourselves, but the owner of the drive lpName
1735 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
1737 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
1738 return GetLastError();
1741 /*****************************************************************
1742 * WNetGetUserW [MPR.@]
1744 * FIXME: we should not return ourselves, but the owner of the drive lpName
1746 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
1748 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
1749 return GetLastError();
1752 /*********************************************************************
1753 * WNetConnectionDialog [MPR.@]
1755 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
1757 FIXME( "(%p, %08lX): stub\n", hwnd, dwType );
1759 SetLastError(WN_NO_NETWORK);
1760 return WN_NO_NETWORK;
1763 /*********************************************************************
1764 * WNetConnectionDialog1A [MPR.@]
1766 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
1768 FIXME( "(%p): stub\n", lpConnDlgStruct );
1770 SetLastError(WN_NO_NETWORK);
1771 return WN_NO_NETWORK;
1774 /*********************************************************************
1775 * WNetConnectionDialog1W [MPR.@]
1777 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
1779 FIXME( "(%p): stub\n", lpConnDlgStruct );
1781 SetLastError(WN_NO_NETWORK);
1782 return WN_NO_NETWORK;
1785 /*********************************************************************
1786 * WNetDisconnectDialog [MPR.@]
1788 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
1790 FIXME( "(%p, %08lX): stub\n", hwnd, dwType );
1792 SetLastError(WN_NO_NETWORK);
1793 return WN_NO_NETWORK;
1796 /*********************************************************************
1797 * WNetDisconnectDialog1A [MPR.@]
1799 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
1801 FIXME( "(%p): stub\n", lpConnDlgStruct );
1803 SetLastError(WN_NO_NETWORK);
1804 return WN_NO_NETWORK;
1807 /*********************************************************************
1808 * WNetDisconnectDialog1W [MPR.@]
1810 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
1812 FIXME( "(%p): stub\n", lpConnDlgStruct );
1814 SetLastError(WN_NO_NETWORK);
1815 return WN_NO_NETWORK;
1818 /*********************************************************************
1819 * WNetGetLastErrorA [MPR.@]
1821 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
1822 LPSTR lpErrorBuf, DWORD nErrorBufSize,
1823 LPSTR lpNameBuf, DWORD nNameBufSize )
1825 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
1826 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
1828 SetLastError(WN_NO_NETWORK);
1829 return WN_NO_NETWORK;
1832 /*********************************************************************
1833 * WNetGetLastErrorW [MPR.@]
1835 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
1836 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
1837 LPWSTR lpNameBuf, DWORD nNameBufSize )
1839 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
1840 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
1842 SetLastError(WN_NO_NETWORK);
1843 return WN_NO_NETWORK;
1846 /*********************************************************************
1847 * WNetGetNetworkInformationA [MPR.@]
1849 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
1850 LPNETINFOSTRUCT lpNetInfoStruct )
1854 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
1857 ret = WN_BAD_POINTER;
1862 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
1865 LPWSTR wideProvider = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
1866 len * sizeof(WCHAR));
1870 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
1872 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
1873 HeapFree(GetProcessHeap(), 0, wideProvider);
1876 ret = WN_OUT_OF_MEMORY;
1879 ret = GetLastError();
1883 TRACE("Returning %ld\n", ret);
1887 /*********************************************************************
1888 * WNetGetNetworkInformationW [MPR.@]
1890 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
1891 LPNETINFOSTRUCT lpNetInfoStruct )
1895 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
1898 ret = WN_BAD_POINTER;
1899 else if (!lpNetInfoStruct)
1900 ret = WN_BAD_POINTER;
1901 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
1905 if (providerTable && providerTable->numProviders)
1907 DWORD providerIndex = _findProviderIndexW(lpProvider);
1909 if (providerIndex != BAD_PROVIDER_INDEX)
1911 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
1912 lpNetInfoStruct->dwProviderVersion =
1913 providerTable->table[providerIndex].dwSpecVersion;
1914 lpNetInfoStruct->dwStatus = NO_ERROR;
1915 lpNetInfoStruct->dwCharacteristics = 0;
1916 lpNetInfoStruct->dwHandle = (ULONG_PTR)NULL;
1917 lpNetInfoStruct->wNetType =
1918 HIWORD(providerTable->table[providerIndex].dwNetType);
1919 lpNetInfoStruct->dwPrinters = -1;
1920 lpNetInfoStruct->dwDrives = -1;
1924 ret = WN_BAD_PROVIDER;
1927 ret = WN_NO_NETWORK;
1931 TRACE("Returning %ld\n", ret);
1935 /*****************************************************************
1936 * WNetGetProviderNameA [MPR.@]
1938 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
1939 LPSTR lpProvider, LPDWORD lpBufferSize )
1943 TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
1947 ret = WN_BAD_POINTER;
1948 else if (!lpBufferSize)
1949 ret = WN_BAD_POINTER;
1956 ret = WN_NO_NETWORK;
1957 for (i = 0; i < providerTable->numProviders &&
1958 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
1961 if (i < providerTable->numProviders)
1963 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
1964 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
1966 if (*lpBufferSize < sizeNeeded)
1968 *lpBufferSize = sizeNeeded;
1973 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
1974 -1, lpProvider, *lpBufferSize, NULL, NULL);
1976 /* FIXME: is *lpBufferSize set to the number of characters
1982 ret = WN_NO_NETWORK;
1986 TRACE("Returning %ld\n", ret);
1990 /*****************************************************************
1991 * WNetGetProviderNameW [MPR.@]
1993 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
1994 LPWSTR lpProvider, LPDWORD lpBufferSize )
1998 TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2002 ret = WN_BAD_POINTER;
2003 else if (!lpBufferSize)
2004 ret = WN_BAD_POINTER;
2011 ret = WN_NO_NETWORK;
2012 for (i = 0; i < providerTable->numProviders &&
2013 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2016 if (i < providerTable->numProviders)
2018 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2020 if (*lpBufferSize < sizeNeeded)
2022 *lpBufferSize = sizeNeeded;
2027 strcpyW(lpProvider, providerTable->table[i].name);
2029 /* FIXME: is *lpBufferSize set to the number of characters
2035 ret = WN_NO_NETWORK;
2039 TRACE("Returning %ld\n", ret);