quartz: Free two assert calls from having side effects.
[wine/testsucceed.git] / dlls / mpr / wnet.c
blob946f47e74f2a5316b372b7c86c629cf68dd07816
1 /*
2 * MPR WNet functions
4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winnls.h"
27 #include "winioctl.h"
28 #include "winnetwk.h"
29 #include "npapi.h"
30 #include "winreg.h"
31 #include "winuser.h"
32 #define WINE_MOUNTMGR_EXTENSIONS
33 #include "ddk/mountmgr.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36 #include "mprres.h"
37 #include "wnetpriv.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(mpr);
41 /* Data structures representing network service providers. Assumes only one
42 * thread creates them, and that they are constant for the life of the process
43 * (and therefore doesn't synchronize access).
44 * FIXME: only basic provider data and enumeration-related data are implemented
45 * so far, need to implement the rest too.
47 typedef struct _WNetProvider
49 HMODULE hLib;
50 PWSTR name;
51 PF_NPGetCaps getCaps;
52 DWORD dwSpecVersion;
53 DWORD dwNetType;
54 DWORD dwEnumScopes;
55 PF_NPOpenEnum openEnum;
56 PF_NPEnumResource enumResource;
57 PF_NPCloseEnum closeEnum;
58 PF_NPGetResourceInformation getResourceInformation;
59 } WNetProvider, *PWNetProvider;
61 typedef struct _WNetProviderTable
63 LPWSTR entireNetwork;
64 DWORD numAllocated;
65 DWORD numProviders;
66 WNetProvider table[1];
67 } WNetProviderTable, *PWNetProviderTable;
69 #define WNET_ENUMERATOR_TYPE_NULL 0
70 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
71 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
72 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
74 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
75 * the enumeration; it represents one of the following types:
76 * - a 'null' enumeration, one that contains no members
77 * - a global enumeration, one that's executed across all providers
78 * - a provider-specific enumeration, one that's only executed by a single
79 * provider
80 * - a context enumeration. I know this contradicts what I just said about
81 * there being no correspondence between the scope and the type, but it's
82 * necessary for the special case that a "Entire Network" entry needs to
83 * be enumerated in an enumeration of the context scope. Thus an enumeration
84 * of the context scope results in a context type enumerator, which morphs
85 * into a global enumeration (so the enumeration continues across all
86 * providers).
88 typedef struct _WNetEnumerator
90 DWORD enumType;
91 DWORD providerIndex;
92 HANDLE handle;
93 BOOL providerDone;
94 DWORD dwScope;
95 DWORD dwType;
96 DWORD dwUsage;
97 LPNETRESOURCEW lpNet;
98 } WNetEnumerator, *PWNetEnumerator;
100 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
102 /* Returns an index (into the global WNetProviderTable) of the provider with
103 * the given name, or BAD_PROVIDER_INDEX if not found.
105 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
107 static PWNetProviderTable providerTable;
110 * Global provider table functions
113 static void _tryLoadProvider(PCWSTR provider)
115 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
116 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
117 'S','e','r','v','i','c','e','s','\\',0 };
118 static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
119 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
120 WCHAR serviceName[MAX_PATH];
121 HKEY hKey;
123 TRACE("%s\n", debugstr_w(provider));
124 snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt,
125 servicePrefix, provider);
126 serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0';
127 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
128 ERROR_SUCCESS)
130 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
131 'P','a','t','h',0 };
132 WCHAR providerPath[MAX_PATH];
133 DWORD type, size = sizeof(providerPath);
135 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
136 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && type == REG_SZ)
138 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
139 PWSTR name = NULL;
141 size = 0;
142 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
143 if (size)
145 name = HeapAlloc(GetProcessHeap(), 0, size);
146 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
147 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
149 HeapFree(GetProcessHeap(), 0, name);
150 name = NULL;
153 if (name)
155 HMODULE hLib = LoadLibraryW(providerPath);
157 if (hLib)
159 PF_NPGetCaps getCaps = (PF_NPGetCaps)GetProcAddress(hLib,
160 "NPGetCaps");
162 TRACE("loaded lib %p\n", hLib);
163 if (getCaps)
165 PWNetProvider provider =
166 &providerTable->table[providerTable->numProviders];
168 provider->hLib = hLib;
169 provider->name = name;
170 TRACE("name is %s\n", debugstr_w(name));
171 provider->getCaps = getCaps;
172 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
173 provider->dwNetType = getCaps(WNNC_NET_TYPE);
174 TRACE("net type is 0x%08x\n", provider->dwNetType);
175 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
176 if (provider->dwEnumScopes)
178 TRACE("supports enumeration\n");
179 provider->openEnum = (PF_NPOpenEnum)
180 GetProcAddress(hLib, "NPOpenEnum");
181 TRACE("openEnum is %p\n", provider->openEnum);
182 provider->enumResource = (PF_NPEnumResource)
183 GetProcAddress(hLib, "NPEnumResource");
184 TRACE("enumResource is %p\n",
185 provider->enumResource);
186 provider->closeEnum = (PF_NPCloseEnum)
187 GetProcAddress(hLib, "NPCloseEnum");
188 TRACE("closeEnum is %p\n", provider->closeEnum);
189 provider->getResourceInformation = (PF_NPGetResourceInformation)
190 GetProcAddress(hLib, "NPGetResourceInformation");
191 TRACE("getResourceInformation is %p\n",
192 provider->getResourceInformation);
193 if (!provider->openEnum || !provider->enumResource
194 || !provider->closeEnum)
196 provider->openEnum = NULL;
197 provider->enumResource = NULL;
198 provider->closeEnum = NULL;
199 provider->dwEnumScopes = 0;
200 WARN("Couldn't load enumeration functions\n");
203 providerTable->numProviders++;
205 else
207 WARN("Provider %s didn't export NPGetCaps\n",
208 debugstr_w(provider));
209 HeapFree(GetProcessHeap(), 0, name);
210 FreeLibrary(hLib);
213 else
215 WARN("Couldn't load library %s for provider %s\n",
216 debugstr_w(providerPath), debugstr_w(provider));
217 HeapFree(GetProcessHeap(), 0, name);
220 else
222 WARN("Couldn't get provider name for provider %s\n",
223 debugstr_w(provider));
226 else
227 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
228 RegCloseKey(hKey);
230 else
231 WARN("Couldn't open service key for provider %s\n",
232 debugstr_w(provider));
235 void wnetInit(HINSTANCE hInstDll)
237 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
238 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
239 'C','o','n','t','r','o','l','\\',
240 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
241 'O','r','d','e','r',0 };
242 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
243 'O','r','d','e','r',0 };
244 HKEY hKey;
246 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
247 == ERROR_SUCCESS)
249 DWORD size = 0;
251 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
252 if (size)
254 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
256 if (providers)
258 DWORD type;
260 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
261 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
263 PWSTR ptr;
264 DWORD numToAllocate;
266 TRACE("provider order is %s\n", debugstr_w(providers));
267 /* first count commas as a heuristic for how many to
268 * allocate space for */
269 for (ptr = providers, numToAllocate = 1; ptr; )
271 ptr = strchrW(ptr, ',');
272 if (ptr) {
273 numToAllocate++;
274 ptr++;
277 providerTable =
278 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
279 sizeof(WNetProviderTable)
280 + (numToAllocate - 1) * sizeof(WNetProvider));
281 if (providerTable)
283 PWSTR ptrPrev;
284 int entireNetworkLen;
285 LPCWSTR stringresource;
287 entireNetworkLen = LoadStringW(hInstDll,
288 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
289 providerTable->entireNetwork = HeapAlloc(
290 GetProcessHeap(), 0, (entireNetworkLen + 1) *
291 sizeof(WCHAR));
292 if (providerTable->entireNetwork)
294 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
295 providerTable->entireNetwork[entireNetworkLen] = 0;
297 providerTable->numAllocated = numToAllocate;
298 for (ptr = providers; ptr; )
300 ptrPrev = ptr;
301 ptr = strchrW(ptr, ',');
302 if (ptr)
303 *ptr++ = '\0';
304 _tryLoadProvider(ptrPrev);
308 HeapFree(GetProcessHeap(), 0, providers);
311 RegCloseKey(hKey);
315 void wnetFree(void)
317 if (providerTable)
319 DWORD i;
321 for (i = 0; i < providerTable->numProviders; i++)
323 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
324 FreeModule(providerTable->table[i].hLib);
326 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
327 HeapFree(GetProcessHeap(), 0, providerTable);
328 providerTable = NULL;
332 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
334 DWORD ret = BAD_PROVIDER_INDEX;
336 if (providerTable && providerTable->numProviders)
338 DWORD i;
340 for (i = 0; i < providerTable->numProviders &&
341 ret == BAD_PROVIDER_INDEX; i++)
342 if (!strcmpW(lpProvider, providerTable->table[i].name))
343 ret = i;
345 return ret;
349 * Browsing Functions
352 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
354 LPNETRESOURCEW ret;
356 if (lpNet)
358 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
359 if (ret)
361 size_t len;
363 *ret = *lpNet;
364 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
365 if (lpNet->lpRemoteName)
367 len = strlenW(lpNet->lpRemoteName) + 1;
368 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
369 if (ret->lpRemoteName)
370 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
374 else
375 ret = NULL;
376 return ret;
379 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
381 if (lpNet)
383 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
384 HeapFree(GetProcessHeap(), 0, lpNet);
388 static PWNetEnumerator _createNullEnumerator(void)
390 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
391 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
393 if (ret)
394 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
395 return ret;
398 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
399 DWORD dwUsage, LPNETRESOURCEW lpNet)
401 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
402 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
404 if (ret)
406 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
407 ret->dwScope = dwScope;
408 ret->dwType = dwType;
409 ret->dwUsage = dwUsage;
410 ret->lpNet = _copyNetResourceForEnumW(lpNet);
412 return ret;
415 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
416 DWORD dwUsage, DWORD index, HANDLE handle)
418 PWNetEnumerator ret;
420 if (!providerTable || index >= providerTable->numProviders)
421 ret = NULL;
422 else
424 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
425 if (ret)
427 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
428 ret->providerIndex = index;
429 ret->dwScope = dwScope;
430 ret->dwType = dwType;
431 ret->dwUsage = dwUsage;
432 ret->handle = handle;
435 return ret;
438 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
439 DWORD dwUsage)
441 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
442 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
444 if (ret)
446 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
447 ret->dwScope = dwScope;
448 ret->dwType = dwType;
449 ret->dwUsage = dwUsage;
451 return ret;
454 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
455 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
456 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
457 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
458 * if not all members of the array could be thunked, and something else on
459 * failure.
461 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
462 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
464 DWORD i, numToThunk, totalBytes, ret;
465 LPSTR strNext;
467 if (!lpNetArrayIn)
468 return WN_BAD_POINTER;
469 if (!lpcCount)
470 return WN_BAD_POINTER;
471 if (*lpcCount == -1)
472 return WN_BAD_VALUE;
473 if (!lpBuffer)
474 return WN_BAD_POINTER;
475 if (!lpBufferSize)
476 return WN_BAD_POINTER;
478 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
480 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
482 totalBytes += sizeof(NETRESOURCEA);
483 if (lpNet->lpLocalName)
484 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
485 -1, NULL, 0, NULL, NULL);
486 if (lpNet->lpRemoteName)
487 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
488 -1, NULL, 0, NULL, NULL);
489 if (lpNet->lpComment)
490 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
491 -1, NULL, 0, NULL, NULL);
492 if (lpNet->lpProvider)
493 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
494 -1, NULL, 0, NULL, NULL);
495 if (totalBytes < *lpBufferSize)
496 numToThunk = i + 1;
498 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
499 for (i = 0; i < numToThunk; i++)
501 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
502 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
504 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
505 /* lie about string lengths, we already verified how many
506 * we have space for above
508 if (lpNetIn->lpLocalName)
510 lpNetOut->lpLocalName = strNext;
511 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
512 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
514 if (lpNetIn->lpRemoteName)
516 lpNetOut->lpRemoteName = strNext;
517 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
518 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
520 if (lpNetIn->lpComment)
522 lpNetOut->lpComment = strNext;
523 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
524 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
526 if (lpNetIn->lpProvider)
528 lpNetOut->lpProvider = strNext;
529 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
530 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
533 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
534 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
535 *lpcCount, ret);
536 return ret;
539 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
540 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
541 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
542 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
543 * if not all members of the array could be thunked, and something else on
544 * failure.
546 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
547 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
549 DWORD i, numToThunk, totalBytes, ret;
550 LPWSTR strNext;
552 if (!lpNetArrayIn)
553 return WN_BAD_POINTER;
554 if (!lpcCount)
555 return WN_BAD_POINTER;
556 if (*lpcCount == -1)
557 return WN_BAD_VALUE;
558 if (!lpBuffer)
559 return WN_BAD_POINTER;
560 if (!lpBufferSize)
561 return WN_BAD_POINTER;
563 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
565 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
567 totalBytes += sizeof(NETRESOURCEW);
568 if (lpNet->lpLocalName)
569 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
570 -1, NULL, 0) * sizeof(WCHAR);
571 if (lpNet->lpRemoteName)
572 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
573 -1, NULL, 0) * sizeof(WCHAR);
574 if (lpNet->lpComment)
575 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
576 -1, NULL, 0) * sizeof(WCHAR);
577 if (lpNet->lpProvider)
578 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
579 -1, NULL, 0) * sizeof(WCHAR);
580 if (totalBytes < *lpBufferSize)
581 numToThunk = i + 1;
583 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
584 for (i = 0; i < numToThunk; i++)
586 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
587 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
589 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
590 /* lie about string lengths, we already verified how many
591 * we have space for above
593 if (lpNetIn->lpLocalName)
595 lpNetOut->lpLocalName = strNext;
596 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
597 -1, lpNetOut->lpLocalName, *lpBufferSize);
599 if (lpNetIn->lpRemoteName)
601 lpNetOut->lpRemoteName = strNext;
602 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
603 -1, lpNetOut->lpRemoteName, *lpBufferSize);
605 if (lpNetIn->lpComment)
607 lpNetOut->lpComment = strNext;
608 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
609 -1, lpNetOut->lpComment, *lpBufferSize);
611 if (lpNetIn->lpProvider)
613 lpNetOut->lpProvider = strNext;
614 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
615 -1, lpNetOut->lpProvider, *lpBufferSize);
618 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
619 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
620 *lpcCount, ret);
621 return ret;
624 /*********************************************************************
625 * WNetOpenEnumA [MPR.@]
627 * See comments for WNetOpenEnumW.
629 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
630 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
632 DWORD ret;
634 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
635 dwScope, dwType, dwUsage, lpNet, lphEnum );
637 if (!lphEnum)
638 ret = WN_BAD_POINTER;
639 else if (!providerTable || providerTable->numProviders == 0)
641 *lphEnum = NULL;
642 ret = WN_NO_NETWORK;
644 else
646 if (lpNet)
648 LPNETRESOURCEW lpNetWide = NULL;
649 BYTE buf[1024];
650 DWORD size = sizeof(buf), count = 1;
651 BOOL allocated = FALSE;
653 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
654 if (ret == WN_MORE_DATA)
656 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
657 size);
658 if (lpNetWide)
660 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
661 &size);
662 allocated = TRUE;
664 else
665 ret = WN_OUT_OF_MEMORY;
667 else if (ret == WN_SUCCESS)
668 lpNetWide = (LPNETRESOURCEW)buf;
669 if (ret == WN_SUCCESS)
670 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
671 lphEnum);
672 if (allocated)
673 HeapFree(GetProcessHeap(), 0, lpNetWide);
675 else
676 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
678 if (ret)
679 SetLastError(ret);
680 TRACE("Returning %d\n", ret);
681 return ret;
684 /*********************************************************************
685 * WNetOpenEnumW [MPR.@]
687 * Network enumeration has way too many parameters, so I'm not positive I got
688 * them right. What I've got so far:
690 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
691 * all the network providers should be enumerated.
693 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
694 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
695 * lpProvider is set, all the network providers should be enumerated.
696 * (This means the enumeration is a list of network providers, not that the
697 * enumeration is passed on to the providers.)
699 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
700 * resource matches the "Entire Network" resource (no remote name, no
701 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
702 * enumeration is done on every network provider.
704 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
705 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
706 * only to the given network provider.
708 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
709 * no lpProvider is set, enumeration will be tried on every network provider,
710 * in the order in which they're loaded.
712 * - The LPNETRESOURCE should be disregarded for scopes besides
713 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
714 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
716 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
717 * resource in the enumerated list, as well as any machines in your
718 * workgroup. The machines in your workgroup come from doing a
719 * RESOURCE_CONTEXT enumeration of every Network Provider.
721 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
722 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
724 DWORD ret;
726 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
727 dwScope, dwType, dwUsage, lpNet, lphEnum );
729 if (!lphEnum)
730 ret = WN_BAD_POINTER;
731 else if (!providerTable || providerTable->numProviders == 0)
733 *lphEnum = NULL;
734 ret = WN_NO_NETWORK;
736 else
738 switch (dwScope)
740 case RESOURCE_GLOBALNET:
741 if (lpNet)
743 if (lpNet->lpProvider)
745 DWORD index = _findProviderIndexW(lpNet->lpProvider);
747 if (index != BAD_PROVIDER_INDEX)
749 if (providerTable->table[index].openEnum &&
750 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
752 HANDLE handle;
754 ret = providerTable->table[index].openEnum(
755 dwScope, dwType, dwUsage, lpNet, &handle);
756 if (ret == WN_SUCCESS)
758 *lphEnum = _createProviderEnumerator(
759 dwScope, dwType, dwUsage, index, handle);
760 ret = *lphEnum ? WN_SUCCESS :
761 WN_OUT_OF_MEMORY;
764 else
765 ret = WN_NOT_SUPPORTED;
767 else
768 ret = WN_BAD_PROVIDER;
770 else if (lpNet->lpRemoteName)
772 *lphEnum = _createGlobalEnumeratorW(dwScope,
773 dwType, dwUsage, lpNet);
774 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
776 else
778 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
779 providerTable->entireNetwork))
781 /* comment matches the "Entire Network", enumerate
782 * global scope of every provider
784 *lphEnum = _createGlobalEnumeratorW(dwScope,
785 dwType, dwUsage, lpNet);
787 else
789 /* this is the same as not having passed lpNet */
790 *lphEnum = _createGlobalEnumeratorW(dwScope,
791 dwType, dwUsage, NULL);
793 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
796 else
798 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
799 dwUsage, lpNet);
800 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
802 break;
803 case RESOURCE_CONTEXT:
804 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
805 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
806 break;
807 case RESOURCE_REMEMBERED:
808 case RESOURCE_CONNECTED:
809 *lphEnum = _createNullEnumerator();
810 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
811 break;
812 default:
813 WARN("unknown scope 0x%08x\n", dwScope);
814 ret = WN_BAD_VALUE;
817 if (ret)
818 SetLastError(ret);
819 TRACE("Returning %d\n", ret);
820 return ret;
823 /*********************************************************************
824 * WNetEnumResourceA [MPR.@]
826 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
827 LPVOID lpBuffer, LPDWORD lpBufferSize )
829 DWORD ret;
831 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
833 if (!hEnum)
834 ret = WN_BAD_POINTER;
835 else if (!lpcCount)
836 ret = WN_BAD_POINTER;
837 else if (!lpBuffer)
838 ret = WN_BAD_POINTER;
839 else if (!lpBufferSize)
840 ret = WN_BAD_POINTER;
841 else if (*lpBufferSize < sizeof(NETRESOURCEA))
843 *lpBufferSize = sizeof(NETRESOURCEA);
844 ret = WN_MORE_DATA;
846 else
848 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
849 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
851 if (localBuffer)
853 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
854 &localSize);
855 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
857 /* FIXME: this isn't necessarily going to work in the case of
858 * WN_MORE_DATA, because our enumerator may have moved on to
859 * the next provider. MSDN states that a large (16KB) buffer
860 * size is the appropriate usage of this function, so
861 * hopefully it won't be an issue.
863 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
864 lpBuffer, lpBufferSize);
865 *lpcCount = localCount;
867 HeapFree(GetProcessHeap(), 0, localBuffer);
869 else
870 ret = WN_OUT_OF_MEMORY;
872 if (ret)
873 SetLastError(ret);
874 TRACE("Returning %d\n", ret);
875 return ret;
878 static DWORD _countProviderBytesW(PWNetProvider provider)
880 DWORD ret;
882 if (provider)
884 ret = sizeof(NETRESOURCEW);
885 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
887 else
888 ret = 0;
889 return ret;
892 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
893 LPVOID lpBuffer, const DWORD *lpBufferSize)
895 DWORD ret;
897 if (!enumerator)
898 return WN_BAD_POINTER;
899 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
900 return WN_BAD_VALUE;
901 if (!lpcCount)
902 return WN_BAD_POINTER;
903 if (!lpBuffer)
904 return WN_BAD_POINTER;
905 if (!lpBufferSize)
906 return WN_BAD_POINTER;
907 if (*lpBufferSize < sizeof(NETRESOURCEA))
908 return WN_MORE_DATA;
910 if (!providerTable || enumerator->providerIndex >=
911 providerTable->numProviders)
912 ret = WN_NO_MORE_ENTRIES;
913 else
915 DWORD bytes = 0, count = 0, countLimit, i;
916 LPNETRESOURCEW resource;
917 LPWSTR strNext;
919 countLimit = *lpcCount == -1 ?
920 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
921 while (count < countLimit && bytes < *lpBufferSize)
923 DWORD bytesNext = _countProviderBytesW(
924 &providerTable->table[count + enumerator->providerIndex]);
926 if (bytes + bytesNext < *lpBufferSize)
928 bytes += bytesNext;
929 count++;
932 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
933 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
935 resource->dwScope = RESOURCE_GLOBALNET;
936 resource->dwType = RESOURCETYPE_ANY;
937 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
938 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
939 RESOURCEUSAGE_RESERVED;
940 resource->lpLocalName = NULL;
941 resource->lpRemoteName = strNext;
942 strcpyW(resource->lpRemoteName,
943 providerTable->table[i + enumerator->providerIndex].name);
944 strNext += strlenW(resource->lpRemoteName) + 1;
945 resource->lpComment = NULL;
946 resource->lpProvider = strNext;
947 strcpyW(resource->lpProvider,
948 providerTable->table[i + enumerator->providerIndex].name);
949 strNext += strlenW(resource->lpProvider) + 1;
951 enumerator->providerIndex += count;
952 *lpcCount = count;
953 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
955 TRACE("Returning %d\n", ret);
956 return ret;
959 /* Advances the enumerator (assumed to be a global enumerator) to the next
960 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
961 * not open a handle with the next provider.
962 * If the existing handle is NULL, may leave the enumerator unchanged, since
963 * the current provider may support the desired scope.
964 * If the existing handle is not NULL, closes it before moving on.
965 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
966 * provider, and another error on failure.
968 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
970 if (!enumerator)
971 return WN_BAD_POINTER;
972 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
973 return WN_BAD_VALUE;
974 if (!providerTable || enumerator->providerIndex >=
975 providerTable->numProviders)
976 return WN_NO_MORE_ENTRIES;
978 if (enumerator->providerDone)
980 DWORD dwEnum = 0;
981 enumerator->providerDone = FALSE;
982 if (enumerator->handle)
984 providerTable->table[enumerator->providerIndex].closeEnum(
985 enumerator->handle);
986 enumerator->handle = NULL;
987 enumerator->providerIndex++;
989 if (enumerator->dwScope == RESOURCE_CONNECTED)
990 dwEnum = WNNC_ENUM_LOCAL;
991 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
992 dwEnum = WNNC_ENUM_GLOBAL;
993 else if (enumerator->dwScope == RESOURCE_CONTEXT)
994 dwEnum = WNNC_ENUM_CONTEXT;
995 for (; enumerator->providerIndex < providerTable->numProviders &&
996 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
997 & dwEnum); enumerator->providerIndex++)
1000 return enumerator->providerIndex < providerTable->numProviders ?
1001 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1004 /* "Passes through" call to the next provider that supports the enumeration
1005 * type.
1006 * FIXME: if one call to a provider's enumerator succeeds while there's still
1007 * space in lpBuffer, I don't call to the next provider. The caller may not
1008 * expect that it should call EnumResourceW again with a return value of
1009 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1010 * may have to be moved around a bit, ick.
1012 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1013 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1015 DWORD ret;
1017 if (!enumerator)
1018 return WN_BAD_POINTER;
1019 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1020 return WN_BAD_VALUE;
1021 if (!lpcCount)
1022 return WN_BAD_POINTER;
1023 if (!lpBuffer)
1024 return WN_BAD_POINTER;
1025 if (!lpBufferSize)
1026 return WN_BAD_POINTER;
1027 if (*lpBufferSize < sizeof(NETRESOURCEW))
1028 return WN_MORE_DATA;
1030 ret = _globalEnumeratorAdvance(enumerator);
1031 if (ret == WN_SUCCESS)
1033 ret = providerTable->table[enumerator->providerIndex].
1034 openEnum(enumerator->dwScope, enumerator->dwType,
1035 enumerator->dwUsage, enumerator->lpNet,
1036 &enumerator->handle);
1037 if (ret == WN_SUCCESS)
1039 ret = providerTable->table[enumerator->providerIndex].
1040 enumResource(enumerator->handle, lpcCount, lpBuffer,
1041 lpBufferSize);
1042 if (ret != WN_MORE_DATA)
1043 enumerator->providerDone = TRUE;
1046 TRACE("Returning %d\n", ret);
1047 return ret;
1050 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1051 LPVOID lpBuffer, LPDWORD lpBufferSize)
1053 DWORD ret;
1055 if (!enumerator)
1056 return WN_BAD_POINTER;
1057 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1058 return WN_BAD_VALUE;
1059 if (!lpcCount)
1060 return WN_BAD_POINTER;
1061 if (!lpBuffer)
1062 return WN_BAD_POINTER;
1063 if (!lpBufferSize)
1064 return WN_BAD_POINTER;
1065 if (*lpBufferSize < sizeof(NETRESOURCEW))
1066 return WN_MORE_DATA;
1067 if (!providerTable)
1068 return WN_NO_NETWORK;
1070 switch (enumerator->dwScope)
1072 case RESOURCE_GLOBALNET:
1073 if (enumerator->lpNet)
1074 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1075 lpBuffer, lpBufferSize);
1076 else
1077 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1078 lpBufferSize);
1079 break;
1080 case RESOURCE_CONTEXT:
1081 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1082 lpBufferSize);
1083 break;
1084 default:
1085 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1086 ret = WN_NO_MORE_ENTRIES;
1088 TRACE("Returning %d\n", ret);
1089 return ret;
1092 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1093 LPVOID lpBuffer, LPDWORD lpBufferSize)
1095 if (!enumerator)
1096 return WN_BAD_POINTER;
1097 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1098 return WN_BAD_VALUE;
1099 if (!enumerator->handle)
1100 return WN_BAD_VALUE;
1101 if (!lpcCount)
1102 return WN_BAD_POINTER;
1103 if (!lpBuffer)
1104 return WN_BAD_POINTER;
1105 if (!lpBufferSize)
1106 return WN_BAD_POINTER;
1107 if (!providerTable)
1108 return WN_NO_NETWORK;
1109 if (enumerator->providerIndex >= providerTable->numProviders)
1110 return WN_NO_MORE_ENTRIES;
1111 if (!providerTable->table[enumerator->providerIndex].enumResource)
1112 return WN_BAD_VALUE;
1113 return providerTable->table[enumerator->providerIndex].enumResource(
1114 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1117 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1118 LPVOID lpBuffer, LPDWORD lpBufferSize)
1120 DWORD ret;
1121 size_t cchEntireNetworkLen, bytesNeeded;
1123 if (!enumerator)
1124 return WN_BAD_POINTER;
1125 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1126 return WN_BAD_VALUE;
1127 if (!lpcCount)
1128 return WN_BAD_POINTER;
1129 if (!lpBuffer)
1130 return WN_BAD_POINTER;
1131 if (!lpBufferSize)
1132 return WN_BAD_POINTER;
1133 if (!providerTable)
1134 return WN_NO_NETWORK;
1136 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1137 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1138 if (*lpBufferSize < bytesNeeded)
1140 *lpBufferSize = bytesNeeded;
1141 ret = WN_MORE_DATA;
1143 else
1145 LPNETRESOURCEW lpNet = lpBuffer;
1147 lpNet->dwScope = RESOURCE_GLOBALNET;
1148 lpNet->dwType = enumerator->dwType;
1149 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1150 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1151 lpNet->lpLocalName = NULL;
1152 lpNet->lpRemoteName = NULL;
1153 lpNet->lpProvider = NULL;
1154 /* odd, but correct: put comment at end of buffer, so it won't get
1155 * overwritten by subsequent calls to a provider's enumResource
1157 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1158 (cchEntireNetworkLen * sizeof(WCHAR)));
1159 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1160 ret = WN_SUCCESS;
1162 if (ret == WN_SUCCESS)
1164 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1166 /* "Entire Network" entry enumerated--morph this into a global
1167 * enumerator. enumerator->lpNet continues to be NULL, since it has
1168 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1170 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1171 ret = _enumerateGlobalW(enumerator, lpcCount,
1172 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1173 if (ret == WN_SUCCESS)
1175 /* reflect the fact that we already enumerated "Entire Network" */
1176 (*lpcCount)++;
1177 *lpBufferSize = bufferSize + bytesNeeded;
1179 else
1181 /* the provider enumeration failed, but we already succeeded in
1182 * enumerating "Entire Network"--leave type as global to allow a
1183 * retry, but indicate success with a count of one.
1185 ret = WN_SUCCESS;
1186 *lpcCount = 1;
1187 *lpBufferSize = bytesNeeded;
1190 TRACE("Returning %d\n", ret);
1191 return ret;
1194 /*********************************************************************
1195 * WNetEnumResourceW [MPR.@]
1197 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1198 LPVOID lpBuffer, LPDWORD lpBufferSize )
1200 DWORD ret;
1202 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1204 if (!hEnum)
1205 ret = WN_BAD_POINTER;
1206 else if (!lpcCount)
1207 ret = WN_BAD_POINTER;
1208 else if (!lpBuffer)
1209 ret = WN_BAD_POINTER;
1210 else if (!lpBufferSize)
1211 ret = WN_BAD_POINTER;
1212 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1214 *lpBufferSize = sizeof(NETRESOURCEW);
1215 ret = WN_MORE_DATA;
1217 else
1219 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1221 switch (enumerator->enumType)
1223 case WNET_ENUMERATOR_TYPE_NULL:
1224 ret = WN_NO_MORE_ENTRIES;
1225 break;
1226 case WNET_ENUMERATOR_TYPE_GLOBAL:
1227 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1228 lpBufferSize);
1229 break;
1230 case WNET_ENUMERATOR_TYPE_PROVIDER:
1231 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1232 lpBufferSize);
1233 break;
1234 case WNET_ENUMERATOR_TYPE_CONTEXT:
1235 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1236 lpBufferSize);
1237 break;
1238 default:
1239 WARN("bogus enumerator type!\n");
1240 ret = WN_NO_NETWORK;
1243 if (ret)
1244 SetLastError(ret);
1245 TRACE("Returning %d\n", ret);
1246 return ret;
1249 /*********************************************************************
1250 * WNetCloseEnum [MPR.@]
1252 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1254 DWORD ret;
1256 TRACE( "(%p)\n", hEnum );
1258 if (hEnum)
1260 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1262 switch (enumerator->enumType)
1264 case WNET_ENUMERATOR_TYPE_NULL:
1265 ret = WN_SUCCESS;
1266 break;
1267 case WNET_ENUMERATOR_TYPE_GLOBAL:
1268 if (enumerator->lpNet)
1269 _freeEnumNetResource(enumerator->lpNet);
1270 if (enumerator->handle)
1271 providerTable->table[enumerator->providerIndex].
1272 closeEnum(enumerator->handle);
1273 ret = WN_SUCCESS;
1274 break;
1275 case WNET_ENUMERATOR_TYPE_PROVIDER:
1276 if (enumerator->handle)
1277 providerTable->table[enumerator->providerIndex].
1278 closeEnum(enumerator->handle);
1279 ret = WN_SUCCESS;
1280 break;
1281 default:
1282 WARN("bogus enumerator type!\n");
1283 ret = WN_BAD_HANDLE;
1285 HeapFree(GetProcessHeap(), 0, hEnum);
1287 else
1288 ret = WN_BAD_HANDLE;
1289 if (ret)
1290 SetLastError(ret);
1291 TRACE("Returning %d\n", ret);
1292 return ret;
1295 /*********************************************************************
1296 * WNetGetResourceInformationA [MPR.@]
1298 * See WNetGetResourceInformationW
1300 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1301 LPVOID lpBuffer, LPDWORD cbBuffer,
1302 LPSTR *lplpSystem )
1304 DWORD ret;
1306 TRACE( "(%p, %p, %p, %p)\n",
1307 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1309 if (!providerTable || providerTable->numProviders == 0)
1310 ret = WN_NO_NETWORK;
1311 else if (lpNetResource)
1313 LPNETRESOURCEW lpNetResourceW = NULL;
1314 DWORD size = 1024, count = 1;
1315 DWORD len;
1317 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1318 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1319 if (ret == WN_MORE_DATA)
1321 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1322 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1323 if (lpNetResourceW)
1324 ret = _thunkNetResourceArrayAToW(lpNetResource,
1325 &count, lpNetResourceW, &size);
1326 else
1327 ret = WN_OUT_OF_MEMORY;
1329 if (ret == WN_SUCCESS)
1331 LPWSTR lpSystemW = NULL;
1332 LPVOID lpBufferW;
1333 size = 1024;
1334 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1335 if (lpBufferW)
1337 ret = WNetGetResourceInformationW(lpNetResourceW,
1338 lpBufferW, &size, &lpSystemW);
1339 if (ret == WN_MORE_DATA)
1341 HeapFree(GetProcessHeap(), 0, lpBufferW);
1342 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1343 if (lpBufferW)
1344 ret = WNetGetResourceInformationW(lpNetResourceW,
1345 lpBufferW, &size, &lpSystemW);
1346 else
1347 ret = WN_OUT_OF_MEMORY;
1349 if (ret == WN_SUCCESS)
1351 ret = _thunkNetResourceArrayWToA(lpBufferW,
1352 &count, lpBuffer, cbBuffer);
1353 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1354 lpNetResourceW = lpBufferW;
1355 size = sizeof(NETRESOURCEA);
1356 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1357 -1, NULL, 0, NULL, NULL);
1358 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1359 -1, NULL, 0, NULL, NULL);
1361 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1362 -1, NULL, 0, NULL, NULL);
1363 if ((len) && ( size + len < *cbBuffer))
1365 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1366 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1367 *lplpSystem, len, NULL, NULL);
1368 ret = WN_SUCCESS;
1370 else
1371 ret = WN_MORE_DATA;
1373 else
1374 ret = WN_OUT_OF_MEMORY;
1375 HeapFree(GetProcessHeap(), 0, lpBufferW);
1377 else
1378 ret = WN_OUT_OF_MEMORY;
1379 HeapFree(GetProcessHeap(), 0, lpSystemW);
1381 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1383 else
1384 ret = WN_NO_NETWORK;
1386 if (ret)
1387 SetLastError(ret);
1388 TRACE("Returning %d\n", ret);
1389 return ret;
1392 /*********************************************************************
1393 * WNetGetResourceInformationW [MPR.@]
1395 * WNetGetResourceInformationW function identifies the network provider
1396 * that owns the resource and gets information about the type of the resource.
1398 * PARAMS:
1399 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1400 * defines a network resource.
1401 * lpBuffer [ O] the pointer to buffer, containing result. It
1402 * contains NETRESOURCEW structure and strings to
1403 * which the members of the NETRESOURCEW structure
1404 * point.
1405 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1406 * in bytes.
1407 * lplpSystem [ O] the pointer to string in the output buffer,
1408 * containing the part of the resource name without
1409 * names of the server and share.
1411 * RETURNS:
1412 * NO_ERROR if the function succeeds. System error code if the function fails.
1415 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1416 LPVOID lpBuffer, LPDWORD cbBuffer,
1417 LPWSTR *lplpSystem )
1419 DWORD ret = WN_NO_NETWORK;
1420 DWORD index;
1422 TRACE( "(%p, %p, %p, %p)\n",
1423 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1425 if (!(lpBuffer))
1426 ret = WN_OUT_OF_MEMORY;
1427 else if (providerTable != NULL)
1429 /* FIXME: For function value of a variable is indifferent, it does
1430 * search of all providers in a network.
1432 for (index = 0; index < providerTable->numProviders; index++)
1434 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1435 WNNC_DLG_GETRESOURCEINFORMATION)
1437 if (providerTable->table[index].getResourceInformation)
1438 ret = providerTable->table[index].getResourceInformation(
1439 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1440 else
1441 ret = WN_NO_NETWORK;
1442 if (ret == WN_SUCCESS)
1443 break;
1447 if (ret)
1448 SetLastError(ret);
1449 return ret;
1452 /*********************************************************************
1453 * WNetGetResourceParentA [MPR.@]
1455 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1456 LPVOID lpBuffer, LPDWORD lpBufferSize )
1458 FIXME( "(%p, %p, %p): stub\n",
1459 lpNetResource, lpBuffer, lpBufferSize );
1461 SetLastError(WN_NO_NETWORK);
1462 return WN_NO_NETWORK;
1465 /*********************************************************************
1466 * WNetGetResourceParentW [MPR.@]
1468 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1469 LPVOID lpBuffer, LPDWORD lpBufferSize )
1471 FIXME( "(%p, %p, %p): stub\n",
1472 lpNetResource, lpBuffer, lpBufferSize );
1474 SetLastError(WN_NO_NETWORK);
1475 return WN_NO_NETWORK;
1481 * Connection Functions
1484 /*********************************************************************
1485 * WNetAddConnectionA [MPR.@]
1487 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1488 LPCSTR lpLocalName )
1490 FIXME( "(%s, %p, %s): stub\n",
1491 debugstr_a(lpRemoteName), lpPassword, debugstr_a(lpLocalName) );
1493 SetLastError(WN_NO_NETWORK);
1494 return WN_NO_NETWORK;
1497 /*********************************************************************
1498 * WNetAddConnectionW [MPR.@]
1500 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1501 LPCWSTR lpLocalName )
1503 FIXME( "(%s, %p, %s): stub\n",
1504 debugstr_w(lpRemoteName), lpPassword, debugstr_w(lpLocalName) );
1506 SetLastError(WN_NO_NETWORK);
1507 return WN_NO_NETWORK;
1510 /*********************************************************************
1511 * WNetAddConnection2A [MPR.@]
1513 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1514 LPCSTR lpPassword, LPCSTR lpUserID,
1515 DWORD dwFlags )
1517 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1518 lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1520 SetLastError(WN_NO_NETWORK);
1521 return WN_NO_NETWORK;
1524 /*********************************************************************
1525 * WNetAddConnection2W [MPR.@]
1527 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1528 LPCWSTR lpPassword, LPCWSTR lpUserID,
1529 DWORD dwFlags )
1531 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1532 lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1534 SetLastError(WN_NO_NETWORK);
1535 return WN_NO_NETWORK;
1538 /*********************************************************************
1539 * WNetAddConnection3A [MPR.@]
1541 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1542 LPCSTR lpPassword, LPCSTR lpUserID,
1543 DWORD dwFlags )
1545 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1546 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1548 SetLastError(WN_NO_NETWORK);
1549 return WN_NO_NETWORK;
1552 /*********************************************************************
1553 * WNetAddConnection3W [MPR.@]
1555 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1556 LPCWSTR lpPassword, LPCWSTR lpUserID,
1557 DWORD dwFlags )
1559 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1560 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1562 SetLastError(WN_NO_NETWORK);
1563 return WN_NO_NETWORK;
1566 /*****************************************************************
1567 * WNetUseConnectionA [MPR.@]
1569 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1570 LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
1571 LPSTR lpAccessName, LPDWORD lpBufferSize,
1572 LPDWORD lpResult )
1574 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1575 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags,
1576 debugstr_a(lpAccessName), lpBufferSize, lpResult );
1578 SetLastError(WN_NO_NETWORK);
1579 return WN_NO_NETWORK;
1582 /*****************************************************************
1583 * WNetUseConnectionW [MPR.@]
1585 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1586 LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags,
1587 LPWSTR lpAccessName, LPDWORD lpBufferSize,
1588 LPDWORD lpResult )
1590 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1591 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags,
1592 debugstr_w(lpAccessName), lpBufferSize, lpResult );
1594 SetLastError(WN_NO_NETWORK);
1595 return WN_NO_NETWORK;
1598 /*********************************************************************
1599 * WNetCancelConnectionA [MPR.@]
1601 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1603 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1605 return WN_SUCCESS;
1608 /*********************************************************************
1609 * WNetCancelConnectionW [MPR.@]
1611 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1613 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1615 return WN_SUCCESS;
1618 /*********************************************************************
1619 * WNetCancelConnection2A [MPR.@]
1621 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1623 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1625 return WN_SUCCESS;
1628 /*********************************************************************
1629 * WNetCancelConnection2W [MPR.@]
1631 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1633 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1635 return WN_SUCCESS;
1638 /*****************************************************************
1639 * WNetRestoreConnectionA [MPR.@]
1641 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
1643 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1645 SetLastError(WN_NO_NETWORK);
1646 return WN_NO_NETWORK;
1649 /*****************************************************************
1650 * WNetRestoreConnectionW [MPR.@]
1652 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
1654 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1656 SetLastError(WN_NO_NETWORK);
1657 return WN_NO_NETWORK;
1660 /**************************************************************************
1661 * WNetGetConnectionA [MPR.@]
1663 * RETURNS
1664 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1665 * - WN_NOT_CONNECTED drive is a local drive
1666 * - WN_MORE_DATA buffer isn't big enough
1667 * - WN_SUCCESS success (net path in buffer)
1669 * FIXME: need to test return values under different errors
1671 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1672 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1674 DWORD ret;
1676 if (!lpLocalName)
1677 ret = WN_BAD_POINTER;
1678 else if (!lpBufferSize)
1679 ret = WN_BAD_POINTER;
1680 else if (!lpRemoteName && *lpBufferSize)
1681 ret = WN_BAD_POINTER;
1682 else
1684 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1686 if (len)
1688 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1690 if (wideLocalName)
1692 WCHAR wideRemoteStatic[MAX_PATH];
1693 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1695 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1697 /* try once without memory allocation */
1698 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1699 &wideRemoteSize);
1700 if (ret == WN_SUCCESS)
1702 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1703 -1, NULL, 0, NULL, NULL);
1705 if (len <= *lpBufferSize)
1707 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1708 lpRemoteName, *lpBufferSize, NULL, NULL);
1709 ret = WN_SUCCESS;
1711 else
1713 *lpBufferSize = len;
1714 ret = WN_MORE_DATA;
1717 else if (ret == WN_MORE_DATA)
1719 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1720 wideRemoteSize * sizeof(WCHAR));
1722 if (wideRemote)
1724 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1725 &wideRemoteSize);
1726 if (ret == WN_SUCCESS)
1728 if (len <= *lpBufferSize)
1730 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1731 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1732 ret = WN_SUCCESS;
1734 else
1736 *lpBufferSize = len;
1737 ret = WN_MORE_DATA;
1740 HeapFree(GetProcessHeap(), 0, wideRemote);
1742 else
1743 ret = WN_OUT_OF_MEMORY;
1745 HeapFree(GetProcessHeap(), 0, wideLocalName);
1747 else
1748 ret = WN_OUT_OF_MEMORY;
1750 else
1751 ret = WN_BAD_LOCALNAME;
1753 if (ret)
1754 SetLastError(ret);
1755 TRACE("Returning %d\n", ret);
1756 return ret;
1759 /* find the network connection for a given drive; helper for WNetGetConnection */
1760 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
1762 char buffer[1024];
1763 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
1764 HANDLE mgr;
1765 DWORD ret = WN_NOT_CONNECTED;
1767 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
1768 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1769 0, 0 )) == INVALID_HANDLE_VALUE)
1771 ERR( "failed to open mount manager err %u\n", GetLastError() );
1772 return ret;
1774 memset( data, 0, sizeof(*data) );
1775 data->letter = letter;
1776 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
1777 data, sizeof(buffer), NULL, NULL ))
1779 char *p, *mount_point = buffer + data->mount_point_offset;
1780 DWORD len;
1782 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
1784 mount_point += 2;
1785 mount_point[0] = '\\';
1786 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
1788 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
1789 if (len > *size)
1791 *size = len;
1792 ret = WN_MORE_DATA;
1794 else
1796 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
1797 ret = WN_SUCCESS;
1801 CloseHandle( mgr );
1802 return ret;
1805 /**************************************************************************
1806 * WNetGetConnectionW [MPR.@]
1808 * FIXME: need to test return values under different errors
1810 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
1811 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
1813 DWORD ret;
1815 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
1816 lpBufferSize);
1818 if (!lpLocalName)
1819 ret = WN_BAD_POINTER;
1820 else if (!lpBufferSize)
1821 ret = WN_BAD_POINTER;
1822 else if (!lpRemoteName && *lpBufferSize)
1823 ret = WN_BAD_POINTER;
1824 else if (!lpLocalName[0])
1825 ret = WN_BAD_LOCALNAME;
1826 else
1828 if (lpLocalName[1] == ':')
1830 switch(GetDriveTypeW(lpLocalName))
1832 case DRIVE_REMOTE:
1833 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
1834 break;
1835 case DRIVE_REMOVABLE:
1836 case DRIVE_FIXED:
1837 case DRIVE_CDROM:
1838 TRACE("file is local\n");
1839 ret = WN_NOT_CONNECTED;
1840 break;
1841 default:
1842 ret = WN_BAD_LOCALNAME;
1845 else
1846 ret = WN_BAD_LOCALNAME;
1848 if (ret)
1849 SetLastError(ret);
1850 TRACE("Returning %d\n", ret);
1851 return ret;
1854 /**************************************************************************
1855 * WNetSetConnectionA [MPR.@]
1857 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
1858 LPVOID pvValue )
1860 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
1862 SetLastError(WN_NO_NETWORK);
1863 return WN_NO_NETWORK;
1866 /**************************************************************************
1867 * WNetSetConnectionW [MPR.@]
1869 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
1870 LPVOID pvValue )
1872 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
1874 SetLastError(WN_NO_NETWORK);
1875 return WN_NO_NETWORK;
1878 /*****************************************************************
1879 * WNetGetUniversalNameA [MPR.@]
1881 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
1882 LPVOID lpBuffer, LPDWORD lpBufferSize )
1884 DWORD err, size;
1886 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1887 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1889 switch (dwInfoLevel)
1891 case UNIVERSAL_NAME_INFO_LEVEL:
1893 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
1895 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
1896 if (*lpBufferSize < size)
1898 err = WN_MORE_DATA;
1899 break;
1901 info->lpUniversalName = (char *)info + sizeof(*info);
1902 lstrcpyA(info->lpUniversalName, lpLocalPath);
1903 *lpBufferSize = size;
1904 err = WN_NO_ERROR;
1905 break;
1907 case REMOTE_NAME_INFO_LEVEL:
1908 err = WN_NO_NETWORK;
1909 break;
1911 default:
1912 err = WN_BAD_VALUE;
1913 break;
1916 SetLastError(err);
1917 return err;
1920 /*****************************************************************
1921 * WNetGetUniversalNameW [MPR.@]
1923 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
1924 LPVOID lpBuffer, LPDWORD lpBufferSize )
1926 DWORD err, size;
1928 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1929 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1931 switch (dwInfoLevel)
1933 case UNIVERSAL_NAME_INFO_LEVEL:
1935 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
1937 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
1938 if (*lpBufferSize < size)
1940 err = WN_MORE_DATA;
1941 break;
1943 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
1944 lstrcpyW(info->lpUniversalName, lpLocalPath);
1945 *lpBufferSize = size;
1946 err = WN_NO_ERROR;
1947 break;
1949 case REMOTE_NAME_INFO_LEVEL:
1950 err = WN_NO_NETWORK;
1951 break;
1953 default:
1954 err = WN_BAD_VALUE;
1955 break;
1958 if (err != WN_NO_ERROR) SetLastError(err);
1959 return err;
1965 * Other Functions
1968 /**************************************************************************
1969 * WNetGetUserA [MPR.@]
1971 * FIXME: we should not return ourselves, but the owner of the drive lpName
1973 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
1975 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
1976 return GetLastError();
1979 /*****************************************************************
1980 * WNetGetUserW [MPR.@]
1982 * FIXME: we should not return ourselves, but the owner of the drive lpName
1984 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
1986 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
1987 return GetLastError();
1990 /*********************************************************************
1991 * WNetConnectionDialog [MPR.@]
1993 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
1995 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
1997 SetLastError(WN_NO_NETWORK);
1998 return WN_NO_NETWORK;
2001 /*********************************************************************
2002 * WNetConnectionDialog1A [MPR.@]
2004 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2006 FIXME( "(%p): stub\n", lpConnDlgStruct );
2008 SetLastError(WN_NO_NETWORK);
2009 return WN_NO_NETWORK;
2012 /*********************************************************************
2013 * WNetConnectionDialog1W [MPR.@]
2015 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2017 FIXME( "(%p): stub\n", lpConnDlgStruct );
2019 SetLastError(WN_NO_NETWORK);
2020 return WN_NO_NETWORK;
2023 /*********************************************************************
2024 * WNetDisconnectDialog [MPR.@]
2026 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2028 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2030 SetLastError(WN_NO_NETWORK);
2031 return WN_NO_NETWORK;
2034 /*********************************************************************
2035 * WNetDisconnectDialog1A [MPR.@]
2037 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2039 FIXME( "(%p): stub\n", lpConnDlgStruct );
2041 SetLastError(WN_NO_NETWORK);
2042 return WN_NO_NETWORK;
2045 /*********************************************************************
2046 * WNetDisconnectDialog1W [MPR.@]
2048 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2050 FIXME( "(%p): stub\n", lpConnDlgStruct );
2052 SetLastError(WN_NO_NETWORK);
2053 return WN_NO_NETWORK;
2056 /*********************************************************************
2057 * WNetGetLastErrorA [MPR.@]
2059 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2060 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2061 LPSTR lpNameBuf, DWORD nNameBufSize )
2063 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2064 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2066 SetLastError(WN_NO_NETWORK);
2067 return WN_NO_NETWORK;
2070 /*********************************************************************
2071 * WNetGetLastErrorW [MPR.@]
2073 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2074 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2075 LPWSTR lpNameBuf, DWORD nNameBufSize )
2077 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2078 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2080 SetLastError(WN_NO_NETWORK);
2081 return WN_NO_NETWORK;
2084 /*********************************************************************
2085 * WNetGetNetworkInformationA [MPR.@]
2087 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2088 LPNETINFOSTRUCT lpNetInfoStruct )
2090 DWORD ret;
2092 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2094 if (!lpProvider)
2095 ret = WN_BAD_POINTER;
2096 else
2098 int len;
2100 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2101 if (len)
2103 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2105 if (wideProvider)
2107 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2108 len);
2109 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2110 HeapFree(GetProcessHeap(), 0, wideProvider);
2112 else
2113 ret = WN_OUT_OF_MEMORY;
2115 else
2116 ret = GetLastError();
2118 if (ret)
2119 SetLastError(ret);
2120 TRACE("Returning %d\n", ret);
2121 return ret;
2124 /*********************************************************************
2125 * WNetGetNetworkInformationW [MPR.@]
2127 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2128 LPNETINFOSTRUCT lpNetInfoStruct )
2130 DWORD ret;
2132 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2134 if (!lpProvider)
2135 ret = WN_BAD_POINTER;
2136 else if (!lpNetInfoStruct)
2137 ret = WN_BAD_POINTER;
2138 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2139 ret = WN_BAD_VALUE;
2140 else
2142 if (providerTable && providerTable->numProviders)
2144 DWORD providerIndex = _findProviderIndexW(lpProvider);
2146 if (providerIndex != BAD_PROVIDER_INDEX)
2148 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2149 lpNetInfoStruct->dwProviderVersion =
2150 providerTable->table[providerIndex].dwSpecVersion;
2151 lpNetInfoStruct->dwStatus = NO_ERROR;
2152 lpNetInfoStruct->dwCharacteristics = 0;
2153 lpNetInfoStruct->dwHandle = 0;
2154 lpNetInfoStruct->wNetType =
2155 HIWORD(providerTable->table[providerIndex].dwNetType);
2156 lpNetInfoStruct->dwPrinters = -1;
2157 lpNetInfoStruct->dwDrives = -1;
2158 ret = WN_SUCCESS;
2160 else
2161 ret = WN_BAD_PROVIDER;
2163 else
2164 ret = WN_NO_NETWORK;
2166 if (ret)
2167 SetLastError(ret);
2168 TRACE("Returning %d\n", ret);
2169 return ret;
2172 /*****************************************************************
2173 * WNetGetProviderNameA [MPR.@]
2175 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2176 LPSTR lpProvider, LPDWORD lpBufferSize )
2178 DWORD ret;
2180 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2181 lpBufferSize);
2183 if (!lpProvider)
2184 ret = WN_BAD_POINTER;
2185 else if (!lpBufferSize)
2186 ret = WN_BAD_POINTER;
2187 else
2189 if (providerTable)
2191 DWORD i;
2193 ret = WN_NO_NETWORK;
2194 for (i = 0; i < providerTable->numProviders &&
2195 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2196 i++)
2198 if (i < providerTable->numProviders)
2200 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2201 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2203 if (*lpBufferSize < sizeNeeded)
2205 *lpBufferSize = sizeNeeded;
2206 ret = WN_MORE_DATA;
2208 else
2210 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2211 -1, lpProvider, *lpBufferSize, NULL, NULL);
2212 ret = WN_SUCCESS;
2213 /* FIXME: is *lpBufferSize set to the number of characters
2214 * copied? */
2218 else
2219 ret = WN_NO_NETWORK;
2221 if (ret)
2222 SetLastError(ret);
2223 TRACE("Returning %d\n", ret);
2224 return ret;
2227 /*****************************************************************
2228 * WNetGetProviderNameW [MPR.@]
2230 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2231 LPWSTR lpProvider, LPDWORD lpBufferSize )
2233 DWORD ret;
2235 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2236 lpBufferSize);
2238 if (!lpProvider)
2239 ret = WN_BAD_POINTER;
2240 else if (!lpBufferSize)
2241 ret = WN_BAD_POINTER;
2242 else
2244 if (providerTable)
2246 DWORD i;
2248 ret = WN_NO_NETWORK;
2249 for (i = 0; i < providerTable->numProviders &&
2250 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2251 i++)
2253 if (i < providerTable->numProviders)
2255 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2257 if (*lpBufferSize < sizeNeeded)
2259 *lpBufferSize = sizeNeeded;
2260 ret = WN_MORE_DATA;
2262 else
2264 strcpyW(lpProvider, providerTable->table[i].name);
2265 ret = WN_SUCCESS;
2266 /* FIXME: is *lpBufferSize set to the number of characters
2267 * copied? */
2271 else
2272 ret = WN_NO_NETWORK;
2274 if (ret)
2275 SetLastError(ret);
2276 TRACE("Returning %d\n", ret);
2277 return ret;