stash
[wine/wine64.git] / dlls / mpr / wnet.c
blobb2599e18a7683b56b9def89b33f985229822372e
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)
640 ret = WN_NO_NETWORK;
641 else
643 if (lpNet)
645 LPNETRESOURCEW lpNetWide = NULL;
646 BYTE buf[1024];
647 DWORD size = sizeof(buf), count = 1;
648 BOOL allocated = FALSE;
650 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
651 if (ret == WN_MORE_DATA)
653 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
654 size);
655 if (lpNetWide)
657 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
658 &size);
659 allocated = TRUE;
661 else
662 ret = WN_OUT_OF_MEMORY;
664 else if (ret == WN_SUCCESS)
665 lpNetWide = (LPNETRESOURCEW)buf;
666 if (ret == WN_SUCCESS)
667 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
668 lphEnum);
669 if (allocated)
670 HeapFree(GetProcessHeap(), 0, lpNetWide);
672 else
673 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
675 if (ret)
676 SetLastError(ret);
677 TRACE("Returning %d\n", ret);
678 return ret;
681 /*********************************************************************
682 * WNetOpenEnumW [MPR.@]
684 * Network enumeration has way too many parameters, so I'm not positive I got
685 * them right. What I've got so far:
687 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
688 * all the network providers should be enumerated.
690 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
691 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
692 * lpProvider is set, all the network providers should be enumerated.
693 * (This means the enumeration is a list of network providers, not that the
694 * enumeration is passed on to the providers.)
696 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
697 * resource matches the "Entire Network" resource (no remote name, no
698 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
699 * enumeration is done on every network provider.
701 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
702 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
703 * only to the given network provider.
705 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
706 * no lpProvider is set, enumeration will be tried on every network provider,
707 * in the order in which they're loaded.
709 * - The LPNETRESOURCE should be disregarded for scopes besides
710 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
711 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
713 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
714 * resource in the enumerated list, as well as any machines in your
715 * workgroup. The machines in your workgroup come from doing a
716 * RESOURCE_CONTEXT enumeration of every Network Provider.
718 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
719 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
721 DWORD ret;
723 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
724 dwScope, dwType, dwUsage, lpNet, lphEnum );
726 if (!lphEnum)
727 ret = WN_BAD_POINTER;
728 else if (!providerTable || providerTable->numProviders == 0)
729 ret = WN_NO_NETWORK;
730 else
732 switch (dwScope)
734 case RESOURCE_GLOBALNET:
735 if (lpNet)
737 if (lpNet->lpProvider)
739 DWORD index = _findProviderIndexW(lpNet->lpProvider);
741 if (index != BAD_PROVIDER_INDEX)
743 if (providerTable->table[index].openEnum &&
744 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
746 HANDLE handle;
748 ret = providerTable->table[index].openEnum(
749 dwScope, dwType, dwUsage, lpNet, &handle);
750 if (ret == WN_SUCCESS)
752 *lphEnum =
753 (HANDLE)_createProviderEnumerator(
754 dwScope, dwType, dwUsage, index, handle);
755 ret = *lphEnum ? WN_SUCCESS :
756 WN_OUT_OF_MEMORY;
759 else
760 ret = WN_NOT_SUPPORTED;
762 else
763 ret = WN_BAD_PROVIDER;
765 else if (lpNet->lpRemoteName)
767 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
768 dwType, dwUsage, lpNet);
769 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
771 else
773 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
774 providerTable->entireNetwork))
776 /* comment matches the "Entire Network", enumerate
777 * global scope of every provider
779 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
780 dwType, dwUsage, lpNet);
782 else
784 /* this is the same as not having passed lpNet */
785 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
786 dwType, dwUsage, NULL);
788 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
791 else
793 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, dwType,
794 dwUsage, lpNet);
795 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
797 break;
798 case RESOURCE_CONTEXT:
799 *lphEnum = (HANDLE)_createContextEnumerator(dwScope, dwType,
800 dwUsage);
801 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
802 break;
803 case RESOURCE_REMEMBERED:
804 case RESOURCE_CONNECTED:
805 *lphEnum = (HANDLE)_createNullEnumerator();
806 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
807 break;
808 default:
809 WARN("unknown scope 0x%08x\n", dwScope);
810 ret = WN_BAD_VALUE;
813 if (ret)
814 SetLastError(ret);
815 TRACE("Returning %d\n", ret);
816 return ret;
819 /*********************************************************************
820 * WNetEnumResourceA [MPR.@]
822 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
823 LPVOID lpBuffer, LPDWORD lpBufferSize )
825 DWORD ret;
827 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
829 if (!hEnum)
830 ret = WN_BAD_POINTER;
831 else if (!lpcCount)
832 ret = WN_BAD_POINTER;
833 else if (!lpBuffer)
834 ret = WN_BAD_POINTER;
835 else if (!lpBufferSize)
836 ret = WN_BAD_POINTER;
837 else if (*lpBufferSize < sizeof(NETRESOURCEA))
839 *lpBufferSize = sizeof(NETRESOURCEA);
840 ret = WN_MORE_DATA;
842 else
844 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
845 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
847 if (localBuffer)
849 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
850 &localSize);
851 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
853 /* FIXME: this isn't necessarily going to work in the case of
854 * WN_MORE_DATA, because our enumerator may have moved on to
855 * the next provider. MSDN states that a large (16KB) buffer
856 * size is the appropriate usage of this function, so
857 * hopefully it won't be an issue.
859 ret = _thunkNetResourceArrayWToA((LPNETRESOURCEW)localBuffer,
860 &localCount, lpBuffer, lpBufferSize);
861 *lpcCount = localCount;
863 HeapFree(GetProcessHeap(), 0, localBuffer);
865 else
866 ret = WN_OUT_OF_MEMORY;
868 if (ret)
869 SetLastError(ret);
870 TRACE("Returning %d\n", ret);
871 return ret;
874 static DWORD _countProviderBytesW(PWNetProvider provider)
876 DWORD ret;
878 if (provider)
880 ret = sizeof(NETRESOURCEW);
881 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
883 else
884 ret = 0;
885 return ret;
888 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
889 LPVOID lpBuffer, const DWORD *lpBufferSize)
891 DWORD ret;
893 if (!enumerator)
894 return WN_BAD_POINTER;
895 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
896 return WN_BAD_VALUE;
897 if (!lpcCount)
898 return WN_BAD_POINTER;
899 if (!lpBuffer)
900 return WN_BAD_POINTER;
901 if (!lpBufferSize)
902 return WN_BAD_POINTER;
903 if (*lpBufferSize < sizeof(NETRESOURCEA))
904 return WN_MORE_DATA;
906 if (!providerTable || enumerator->providerIndex >=
907 providerTable->numProviders)
908 ret = WN_NO_MORE_ENTRIES;
909 else
911 DWORD bytes = 0, count = 0, countLimit, i;
912 LPNETRESOURCEW resource;
913 LPWSTR strNext;
915 countLimit = *lpcCount == -1 ?
916 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
917 while (count < countLimit && bytes < *lpBufferSize)
919 DWORD bytesNext = _countProviderBytesW(
920 &providerTable->table[count + enumerator->providerIndex]);
922 if (bytes + bytesNext < *lpBufferSize)
924 bytes += bytesNext;
925 count++;
928 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
929 for (i = 0, resource = (LPNETRESOURCEW)lpBuffer; i < count;
930 i++, resource++)
932 resource->dwScope = RESOURCE_GLOBALNET;
933 resource->dwType = RESOURCETYPE_ANY;
934 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
935 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
936 RESOURCEUSAGE_RESERVED;
937 resource->lpLocalName = NULL;
938 resource->lpRemoteName = strNext;
939 strcpyW(resource->lpRemoteName,
940 providerTable->table[i + enumerator->providerIndex].name);
941 strNext += strlenW(resource->lpRemoteName) + 1;
942 resource->lpComment = NULL;
943 resource->lpProvider = strNext;
944 strcpyW(resource->lpProvider,
945 providerTable->table[i + enumerator->providerIndex].name);
946 strNext += strlenW(resource->lpProvider) + 1;
948 enumerator->providerIndex += count;
949 *lpcCount = count;
950 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
952 TRACE("Returning %d\n", ret);
953 return ret;
956 /* Advances the enumerator (assumed to be a global enumerator) to the next
957 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
958 * not open a handle with the next provider.
959 * If the existing handle is NULL, may leave the enumerator unchanged, since
960 * the current provider may support the desired scope.
961 * If the existing handle is not NULL, closes it before moving on.
962 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
963 * provider, and another error on failure.
965 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
967 if (!enumerator)
968 return WN_BAD_POINTER;
969 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
970 return WN_BAD_VALUE;
971 if (!providerTable || enumerator->providerIndex >=
972 providerTable->numProviders)
973 return WN_NO_MORE_ENTRIES;
975 if (enumerator->providerDone)
977 DWORD dwEnum = 0;
978 enumerator->providerDone = FALSE;
979 if (enumerator->handle)
981 providerTable->table[enumerator->providerIndex].closeEnum(
982 enumerator->handle);
983 enumerator->handle = NULL;
984 enumerator->providerIndex++;
986 if (enumerator->dwScope == RESOURCE_CONNECTED)
987 dwEnum = WNNC_ENUM_LOCAL;
988 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
989 dwEnum = WNNC_ENUM_GLOBAL;
990 else if (enumerator->dwScope == RESOURCE_CONTEXT)
991 dwEnum = WNNC_ENUM_CONTEXT;
992 for (; enumerator->providerIndex < providerTable->numProviders &&
993 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
994 & dwEnum); enumerator->providerIndex++)
997 return enumerator->providerIndex < providerTable->numProviders ?
998 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1001 /* "Passes through" call to the next provider that supports the enumeration
1002 * type.
1003 * FIXME: if one call to a provider's enumerator succeeds while there's still
1004 * space in lpBuffer, I don't call to the next provider. The caller may not
1005 * expect that it should call EnumResourceW again with a return value of
1006 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1007 * may have to be moved around a bit, ick.
1009 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1010 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1012 DWORD ret;
1014 if (!enumerator)
1015 return WN_BAD_POINTER;
1016 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1017 return WN_BAD_VALUE;
1018 if (!lpcCount)
1019 return WN_BAD_POINTER;
1020 if (!lpBuffer)
1021 return WN_BAD_POINTER;
1022 if (!lpBufferSize)
1023 return WN_BAD_POINTER;
1024 if (*lpBufferSize < sizeof(NETRESOURCEW))
1025 return WN_MORE_DATA;
1027 ret = _globalEnumeratorAdvance(enumerator);
1028 if (ret == WN_SUCCESS)
1030 ret = providerTable->table[enumerator->providerIndex].
1031 openEnum(enumerator->dwScope, enumerator->dwType,
1032 enumerator->dwUsage, enumerator->lpNet,
1033 &enumerator->handle);
1034 if (ret == WN_SUCCESS)
1036 ret = providerTable->table[enumerator->providerIndex].
1037 enumResource(enumerator->handle, lpcCount, lpBuffer,
1038 lpBufferSize);
1039 if (ret != WN_MORE_DATA)
1040 enumerator->providerDone = TRUE;
1043 TRACE("Returning %d\n", ret);
1044 return ret;
1047 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1048 LPVOID lpBuffer, LPDWORD lpBufferSize)
1050 DWORD ret;
1052 if (!enumerator)
1053 return WN_BAD_POINTER;
1054 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1055 return WN_BAD_VALUE;
1056 if (!lpcCount)
1057 return WN_BAD_POINTER;
1058 if (!lpBuffer)
1059 return WN_BAD_POINTER;
1060 if (!lpBufferSize)
1061 return WN_BAD_POINTER;
1062 if (*lpBufferSize < sizeof(NETRESOURCEW))
1063 return WN_MORE_DATA;
1064 if (!providerTable)
1065 return WN_NO_NETWORK;
1067 switch (enumerator->dwScope)
1069 case RESOURCE_GLOBALNET:
1070 if (enumerator->lpNet)
1071 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1072 lpBuffer, lpBufferSize);
1073 else
1074 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1075 lpBufferSize);
1076 break;
1077 case RESOURCE_CONTEXT:
1078 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1079 lpBufferSize);
1080 break;
1081 default:
1082 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1083 ret = WN_NO_MORE_ENTRIES;
1085 TRACE("Returning %d\n", ret);
1086 return ret;
1089 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1090 LPVOID lpBuffer, LPDWORD lpBufferSize)
1092 if (!enumerator)
1093 return WN_BAD_POINTER;
1094 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1095 return WN_BAD_VALUE;
1096 if (!enumerator->handle)
1097 return WN_BAD_VALUE;
1098 if (!lpcCount)
1099 return WN_BAD_POINTER;
1100 if (!lpBuffer)
1101 return WN_BAD_POINTER;
1102 if (!lpBufferSize)
1103 return WN_BAD_POINTER;
1104 if (!providerTable)
1105 return WN_NO_NETWORK;
1106 if (enumerator->providerIndex >= providerTable->numProviders)
1107 return WN_NO_MORE_ENTRIES;
1108 if (!providerTable->table[enumerator->providerIndex].enumResource)
1109 return WN_BAD_VALUE;
1110 return providerTable->table[enumerator->providerIndex].enumResource(
1111 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1114 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1115 LPVOID lpBuffer, LPDWORD lpBufferSize)
1117 DWORD ret;
1118 size_t cchEntireNetworkLen, bytesNeeded;
1120 if (!enumerator)
1121 return WN_BAD_POINTER;
1122 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1123 return WN_BAD_VALUE;
1124 if (!lpcCount)
1125 return WN_BAD_POINTER;
1126 if (!lpBuffer)
1127 return WN_BAD_POINTER;
1128 if (!lpBufferSize)
1129 return WN_BAD_POINTER;
1130 if (!providerTable)
1131 return WN_NO_NETWORK;
1133 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1134 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1135 if (*lpBufferSize < bytesNeeded)
1137 *lpBufferSize = bytesNeeded;
1138 ret = WN_MORE_DATA;
1140 else
1142 LPNETRESOURCEW lpNet = (LPNETRESOURCEW)lpBuffer;
1144 lpNet->dwScope = RESOURCE_GLOBALNET;
1145 lpNet->dwType = enumerator->dwType;
1146 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1147 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1148 lpNet->lpLocalName = NULL;
1149 lpNet->lpRemoteName = NULL;
1150 lpNet->lpProvider = NULL;
1151 /* odd, but correct: put comment at end of buffer, so it won't get
1152 * overwritten by subsequent calls to a provider's enumResource
1154 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1155 (cchEntireNetworkLen * sizeof(WCHAR)));
1156 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1157 ret = WN_SUCCESS;
1159 if (ret == WN_SUCCESS)
1161 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1163 /* "Entire Network" entry enumerated--morph this into a global
1164 * enumerator. enumerator->lpNet continues to be NULL, since it has
1165 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1167 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1168 ret = _enumerateGlobalW(enumerator, lpcCount,
1169 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1170 if (ret == WN_SUCCESS)
1172 /* reflect the fact that we already enumerated "Entire Network" */
1173 lpcCount++;
1174 *lpBufferSize = bufferSize + bytesNeeded;
1176 else
1178 /* the provider enumeration failed, but we already succeeded in
1179 * enumerating "Entire Network"--leave type as global to allow a
1180 * retry, but indicate success with a count of one.
1182 ret = WN_SUCCESS;
1183 *lpcCount = 1;
1184 *lpBufferSize = bytesNeeded;
1187 TRACE("Returning %d\n", ret);
1188 return ret;
1191 /*********************************************************************
1192 * WNetEnumResourceW [MPR.@]
1194 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1195 LPVOID lpBuffer, LPDWORD lpBufferSize )
1197 DWORD ret;
1199 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1201 if (!hEnum)
1202 ret = WN_BAD_POINTER;
1203 else if (!lpcCount)
1204 ret = WN_BAD_POINTER;
1205 else if (!lpBuffer)
1206 ret = WN_BAD_POINTER;
1207 else if (!lpBufferSize)
1208 ret = WN_BAD_POINTER;
1209 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1211 *lpBufferSize = sizeof(NETRESOURCEW);
1212 ret = WN_MORE_DATA;
1214 else
1216 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1218 switch (enumerator->enumType)
1220 case WNET_ENUMERATOR_TYPE_NULL:
1221 ret = WN_NO_MORE_ENTRIES;
1222 break;
1223 case WNET_ENUMERATOR_TYPE_GLOBAL:
1224 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1225 lpBufferSize);
1226 break;
1227 case WNET_ENUMERATOR_TYPE_PROVIDER:
1228 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1229 lpBufferSize);
1230 break;
1231 case WNET_ENUMERATOR_TYPE_CONTEXT:
1232 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1233 lpBufferSize);
1234 break;
1235 default:
1236 WARN("bogus enumerator type!\n");
1237 ret = WN_NO_NETWORK;
1240 if (ret)
1241 SetLastError(ret);
1242 TRACE("Returning %d\n", ret);
1243 return ret;
1246 /*********************************************************************
1247 * WNetCloseEnum [MPR.@]
1249 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1251 DWORD ret;
1253 TRACE( "(%p)\n", hEnum );
1255 if (hEnum)
1257 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1259 switch (enumerator->enumType)
1261 case WNET_ENUMERATOR_TYPE_NULL:
1262 ret = WN_SUCCESS;
1263 break;
1264 case WNET_ENUMERATOR_TYPE_GLOBAL:
1265 if (enumerator->lpNet)
1266 _freeEnumNetResource(enumerator->lpNet);
1267 if (enumerator->handle)
1268 providerTable->table[enumerator->providerIndex].
1269 closeEnum(enumerator->handle);
1270 ret = WN_SUCCESS;
1271 break;
1272 case WNET_ENUMERATOR_TYPE_PROVIDER:
1273 if (enumerator->handle)
1274 providerTable->table[enumerator->providerIndex].
1275 closeEnum(enumerator->handle);
1276 ret = WN_SUCCESS;
1277 break;
1278 default:
1279 WARN("bogus enumerator type!\n");
1280 ret = WN_BAD_HANDLE;
1282 HeapFree(GetProcessHeap(), 0, hEnum);
1284 else
1285 ret = WN_BAD_HANDLE;
1286 if (ret)
1287 SetLastError(ret);
1288 TRACE("Returning %d\n", ret);
1289 return ret;
1292 /*********************************************************************
1293 * WNetGetResourceInformationA [MPR.@]
1295 * See WNetGetResourceInformationW
1297 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1298 LPVOID lpBuffer, LPDWORD cbBuffer,
1299 LPSTR *lplpSystem )
1301 DWORD ret;
1303 TRACE( "(%p, %p, %p, %p)\n",
1304 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1306 if (!providerTable || providerTable->numProviders == 0)
1307 ret = WN_NO_NETWORK;
1308 else if (lpNetResource)
1310 LPNETRESOURCEW lpNetResourceW = NULL;
1311 DWORD size = 1024, count = 1;
1312 DWORD len;
1314 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1315 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1316 if (ret == WN_MORE_DATA)
1318 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1319 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1320 if (lpNetResourceW)
1321 ret = _thunkNetResourceArrayAToW(lpNetResource,
1322 &count, lpNetResourceW, &size);
1323 else
1324 ret = WN_OUT_OF_MEMORY;
1326 if (ret == WN_SUCCESS)
1328 LPWSTR lpSystemW = NULL;
1329 LPVOID lpBufferW;
1330 size = 1024;
1331 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1332 if (lpBufferW)
1334 ret = WNetGetResourceInformationW(lpNetResourceW,
1335 lpBufferW, &size, &lpSystemW);
1336 if (ret == WN_MORE_DATA)
1338 HeapFree(GetProcessHeap(), 0, lpBufferW);
1339 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1340 if (lpBufferW)
1341 ret = WNetGetResourceInformationW(lpNetResourceW,
1342 lpBufferW, &size, &lpSystemW);
1343 else
1344 ret = WN_OUT_OF_MEMORY;
1346 if (ret == WN_SUCCESS)
1348 ret = _thunkNetResourceArrayWToA(lpBufferW,
1349 &count, lpBuffer, cbBuffer);
1350 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1351 lpNetResourceW = lpBufferW;
1352 size = sizeof(NETRESOURCEA);
1353 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1354 -1, NULL, 0, NULL, NULL);
1355 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1356 -1, NULL, 0, NULL, NULL);
1358 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1359 -1, NULL, 0, NULL, NULL);
1360 if ((len) && ( size + len < *cbBuffer))
1362 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1363 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1364 *lplpSystem, len, NULL, NULL);
1365 ret = WN_SUCCESS;
1367 else
1368 ret = WN_MORE_DATA;
1370 else
1371 ret = WN_OUT_OF_MEMORY;
1372 HeapFree(GetProcessHeap(), 0, lpBufferW);
1374 else
1375 ret = WN_OUT_OF_MEMORY;
1376 HeapFree(GetProcessHeap(), 0, lpSystemW);
1378 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1380 else
1381 ret = WN_NO_NETWORK;
1383 if (ret)
1384 SetLastError(ret);
1385 TRACE("Returning %d\n", ret);
1386 return ret;
1389 /*********************************************************************
1390 * WNetGetResourceInformationW [MPR.@]
1392 * WNetGetResourceInformationW function identifies the network provider
1393 * that owns the resource and gets information about the type of the resource.
1395 * PARAMS:
1396 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1397 * defines a network resource.
1398 * lpBuffer [ O] the pointer to buffer, containing result. It
1399 * contains NETRESOURCEW structure and strings to
1400 * which the members of the NETRESOURCEW structure
1401 * point.
1402 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1403 * in bytes.
1404 * lplpSystem [ O] the pointer to string in the output buffer,
1405 * containing the part of the resource name without
1406 * names of the server and share.
1408 * RETURNS:
1409 * NO_ERROR if the function succeeds. System error code if the function fails.
1412 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1413 LPVOID lpBuffer, LPDWORD cbBuffer,
1414 LPWSTR *lplpSystem )
1416 DWORD ret = WN_NO_NETWORK;
1417 DWORD index;
1419 TRACE( "(%p, %p, %p, %p)\n",
1420 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1422 if (!(lpBuffer))
1423 ret = WN_OUT_OF_MEMORY;
1424 else if (providerTable != NULL)
1426 /* FIXME: For function value of a variable is indifferent, it does
1427 * search of all providers in a network.
1429 for (index = 0; index < providerTable->numProviders; index++)
1431 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1432 WNNC_DLG_GETRESOURCEINFORMATION)
1434 if (providerTable->table[index].getResourceInformation)
1435 ret = providerTable->table[index].getResourceInformation(
1436 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1437 else
1438 ret = WN_NO_NETWORK;
1439 if (ret == WN_SUCCESS)
1440 break;
1444 if (ret)
1445 SetLastError(ret);
1446 return ret;
1449 /*********************************************************************
1450 * WNetGetResourceParentA [MPR.@]
1452 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1453 LPVOID lpBuffer, LPDWORD lpBufferSize )
1455 FIXME( "(%p, %p, %p): stub\n",
1456 lpNetResource, lpBuffer, lpBufferSize );
1458 SetLastError(WN_NO_NETWORK);
1459 return WN_NO_NETWORK;
1462 /*********************************************************************
1463 * WNetGetResourceParentW [MPR.@]
1465 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1466 LPVOID lpBuffer, LPDWORD lpBufferSize )
1468 FIXME( "(%p, %p, %p): stub\n",
1469 lpNetResource, lpBuffer, lpBufferSize );
1471 SetLastError(WN_NO_NETWORK);
1472 return WN_NO_NETWORK;
1478 * Connection Functions
1481 /*********************************************************************
1482 * WNetAddConnectionA [MPR.@]
1484 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1485 LPCSTR lpLocalName )
1487 FIXME( "(%s, %p, %s): stub\n",
1488 debugstr_a(lpRemoteName), lpPassword, debugstr_a(lpLocalName) );
1490 SetLastError(WN_NO_NETWORK);
1491 return WN_NO_NETWORK;
1494 /*********************************************************************
1495 * WNetAddConnectionW [MPR.@]
1497 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1498 LPCWSTR lpLocalName )
1500 FIXME( "(%s, %p, %s): stub\n",
1501 debugstr_w(lpRemoteName), lpPassword, debugstr_w(lpLocalName) );
1503 SetLastError(WN_NO_NETWORK);
1504 return WN_NO_NETWORK;
1507 /*********************************************************************
1508 * WNetAddConnection2A [MPR.@]
1510 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1511 LPCSTR lpPassword, LPCSTR lpUserID,
1512 DWORD dwFlags )
1514 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1515 lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1517 SetLastError(WN_NO_NETWORK);
1518 return WN_NO_NETWORK;
1521 /*********************************************************************
1522 * WNetAddConnection2W [MPR.@]
1524 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1525 LPCWSTR lpPassword, LPCWSTR lpUserID,
1526 DWORD dwFlags )
1528 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1529 lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1531 SetLastError(WN_NO_NETWORK);
1532 return WN_NO_NETWORK;
1535 /*********************************************************************
1536 * WNetAddConnection3A [MPR.@]
1538 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1539 LPCSTR lpPassword, LPCSTR lpUserID,
1540 DWORD dwFlags )
1542 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1543 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1545 SetLastError(WN_NO_NETWORK);
1546 return WN_NO_NETWORK;
1549 /*********************************************************************
1550 * WNetAddConnection3W [MPR.@]
1552 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1553 LPCWSTR lpPassword, LPCWSTR lpUserID,
1554 DWORD dwFlags )
1556 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1557 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1559 SetLastError(WN_NO_NETWORK);
1560 return WN_NO_NETWORK;
1563 /*****************************************************************
1564 * WNetUseConnectionA [MPR.@]
1566 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1567 LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
1568 LPSTR lpAccessName, LPDWORD lpBufferSize,
1569 LPDWORD lpResult )
1571 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1572 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags,
1573 debugstr_a(lpAccessName), lpBufferSize, lpResult );
1575 SetLastError(WN_NO_NETWORK);
1576 return WN_NO_NETWORK;
1579 /*****************************************************************
1580 * WNetUseConnectionW [MPR.@]
1582 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1583 LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags,
1584 LPWSTR lpAccessName, LPDWORD lpBufferSize,
1585 LPDWORD lpResult )
1587 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1588 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags,
1589 debugstr_w(lpAccessName), lpBufferSize, lpResult );
1591 SetLastError(WN_NO_NETWORK);
1592 return WN_NO_NETWORK;
1595 /*********************************************************************
1596 * WNetCancelConnectionA [MPR.@]
1598 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1600 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1602 return WN_SUCCESS;
1605 /*********************************************************************
1606 * WNetCancelConnectionW [MPR.@]
1608 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1610 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1612 return WN_SUCCESS;
1615 /*********************************************************************
1616 * WNetCancelConnection2A [MPR.@]
1618 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1620 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1622 return WN_SUCCESS;
1625 /*********************************************************************
1626 * WNetCancelConnection2W [MPR.@]
1628 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1630 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1632 return WN_SUCCESS;
1635 /*****************************************************************
1636 * WNetRestoreConnectionA [MPR.@]
1638 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
1640 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1642 SetLastError(WN_NO_NETWORK);
1643 return WN_NO_NETWORK;
1646 /*****************************************************************
1647 * WNetRestoreConnectionW [MPR.@]
1649 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
1651 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1653 SetLastError(WN_NO_NETWORK);
1654 return WN_NO_NETWORK;
1657 /**************************************************************************
1658 * WNetGetConnectionA [MPR.@]
1660 * RETURNS
1661 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1662 * - WN_NOT_CONNECTED drive is a local drive
1663 * - WN_MORE_DATA buffer isn't big enough
1664 * - WN_SUCCESS success (net path in buffer)
1666 * FIXME: need to test return values under different errors
1668 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1669 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1671 DWORD ret;
1673 if (!lpLocalName)
1674 ret = WN_BAD_POINTER;
1675 else if (!lpBufferSize)
1676 ret = WN_BAD_POINTER;
1677 else if (!lpRemoteName && *lpBufferSize)
1678 ret = WN_BAD_POINTER;
1679 else
1681 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1683 if (len)
1685 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1687 if (wideLocalName)
1689 WCHAR wideRemoteStatic[MAX_PATH];
1690 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1692 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1694 /* try once without memory allocation */
1695 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1696 &wideRemoteSize);
1697 if (ret == WN_SUCCESS)
1699 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1700 -1, NULL, 0, NULL, NULL);
1702 if (len <= *lpBufferSize)
1704 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1705 lpRemoteName, *lpBufferSize, NULL, NULL);
1706 ret = WN_SUCCESS;
1708 else
1710 *lpBufferSize = len;
1711 ret = WN_MORE_DATA;
1714 else if (ret == WN_MORE_DATA)
1716 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1717 wideRemoteSize * sizeof(WCHAR));
1719 if (wideRemote)
1721 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1722 &wideRemoteSize);
1723 if (ret == WN_SUCCESS)
1725 if (len <= *lpBufferSize)
1727 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1728 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1729 ret = WN_SUCCESS;
1731 else
1733 *lpBufferSize = len;
1734 ret = WN_MORE_DATA;
1737 HeapFree(GetProcessHeap(), 0, wideRemote);
1739 else
1740 ret = WN_OUT_OF_MEMORY;
1742 HeapFree(GetProcessHeap(), 0, wideLocalName);
1744 else
1745 ret = WN_OUT_OF_MEMORY;
1747 else
1748 ret = WN_BAD_LOCALNAME;
1750 if (ret)
1751 SetLastError(ret);
1752 TRACE("Returning %d\n", ret);
1753 return ret;
1756 /* find the network connection for a given drive; helper for WNetGetConnection */
1757 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
1759 char buffer[1024];
1760 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
1761 HANDLE mgr;
1762 DWORD ret = WN_NOT_CONNECTED;
1764 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
1765 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1766 0, 0 )) == INVALID_HANDLE_VALUE)
1768 ERR( "failed to open mount manager err %u\n", GetLastError() );
1769 return ret;
1771 memset( data, 0, sizeof(*data) );
1772 data->letter = letter;
1773 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
1774 data, sizeof(buffer), NULL, NULL ))
1776 char *p, *mount_point = buffer + data->mount_point_offset;
1777 DWORD len;
1779 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
1781 mount_point += 2;
1782 mount_point[0] = '\\';
1783 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
1785 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
1786 if (len > *size)
1788 *size = len;
1789 ret = WN_MORE_DATA;
1791 else
1793 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
1794 ret = WN_SUCCESS;
1798 CloseHandle( mgr );
1799 return ret;
1802 /**************************************************************************
1803 * WNetGetConnectionW [MPR.@]
1805 * FIXME: need to test return values under different errors
1807 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
1808 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
1810 DWORD ret;
1812 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
1813 lpBufferSize);
1815 if (!lpLocalName)
1816 ret = WN_BAD_POINTER;
1817 else if (!lpBufferSize)
1818 ret = WN_BAD_POINTER;
1819 else if (!lpRemoteName && *lpBufferSize)
1820 ret = WN_BAD_POINTER;
1821 else if (!lpLocalName[0])
1822 ret = WN_BAD_LOCALNAME;
1823 else
1825 if (lpLocalName[1] == ':')
1827 switch(GetDriveTypeW(lpLocalName))
1829 case DRIVE_REMOTE:
1830 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
1831 break;
1832 case DRIVE_REMOVABLE:
1833 case DRIVE_FIXED:
1834 case DRIVE_CDROM:
1835 TRACE("file is local\n");
1836 ret = WN_NOT_CONNECTED;
1837 break;
1838 default:
1839 ret = WN_BAD_LOCALNAME;
1842 else
1843 ret = WN_BAD_LOCALNAME;
1845 if (ret)
1846 SetLastError(ret);
1847 TRACE("Returning %d\n", ret);
1848 return ret;
1851 /**************************************************************************
1852 * WNetSetConnectionA [MPR.@]
1854 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
1855 LPVOID pvValue )
1857 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
1859 SetLastError(WN_NO_NETWORK);
1860 return WN_NO_NETWORK;
1863 /**************************************************************************
1864 * WNetSetConnectionW [MPR.@]
1866 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
1867 LPVOID pvValue )
1869 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
1871 SetLastError(WN_NO_NETWORK);
1872 return WN_NO_NETWORK;
1875 /*****************************************************************
1876 * WNetGetUniversalNameA [MPR.@]
1878 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
1879 LPVOID lpBuffer, LPDWORD lpBufferSize )
1881 DWORD err, size;
1883 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1884 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1886 switch (dwInfoLevel)
1888 case UNIVERSAL_NAME_INFO_LEVEL:
1890 LPUNIVERSAL_NAME_INFOA info = (LPUNIVERSAL_NAME_INFOA)lpBuffer;
1892 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
1893 if (*lpBufferSize < size)
1895 err = WN_MORE_DATA;
1896 break;
1898 info->lpUniversalName = (char *)info + sizeof(*info);
1899 lstrcpyA(info->lpUniversalName, lpLocalPath);
1900 *lpBufferSize = size;
1901 err = WN_NO_ERROR;
1902 break;
1904 case REMOTE_NAME_INFO_LEVEL:
1905 err = WN_NO_NETWORK;
1906 break;
1908 default:
1909 err = WN_BAD_VALUE;
1910 break;
1913 SetLastError(err);
1914 return err;
1917 /*****************************************************************
1918 * WNetGetUniversalNameW [MPR.@]
1920 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
1921 LPVOID lpBuffer, LPDWORD lpBufferSize )
1923 DWORD err, size;
1925 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1926 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1928 switch (dwInfoLevel)
1930 case UNIVERSAL_NAME_INFO_LEVEL:
1932 LPUNIVERSAL_NAME_INFOW info = (LPUNIVERSAL_NAME_INFOW)lpBuffer;
1934 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
1935 if (*lpBufferSize < size)
1937 err = WN_MORE_DATA;
1938 break;
1940 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
1941 lstrcpyW(info->lpUniversalName, lpLocalPath);
1942 *lpBufferSize = size;
1943 err = WN_NO_ERROR;
1944 break;
1946 case REMOTE_NAME_INFO_LEVEL:
1947 err = WN_NO_NETWORK;
1948 break;
1950 default:
1951 err = WN_BAD_VALUE;
1952 break;
1955 SetLastError(err);
1956 return err;
1962 * Other Functions
1965 /**************************************************************************
1966 * WNetGetUserA [MPR.@]
1968 * FIXME: we should not return ourselves, but the owner of the drive lpName
1970 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
1972 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
1973 return GetLastError();
1976 /*****************************************************************
1977 * WNetGetUserW [MPR.@]
1979 * FIXME: we should not return ourselves, but the owner of the drive lpName
1981 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
1983 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
1984 return GetLastError();
1987 /*********************************************************************
1988 * WNetConnectionDialog [MPR.@]
1990 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
1992 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
1994 SetLastError(WN_NO_NETWORK);
1995 return WN_NO_NETWORK;
1998 /*********************************************************************
1999 * WNetConnectionDialog1A [MPR.@]
2001 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2003 FIXME( "(%p): stub\n", lpConnDlgStruct );
2005 SetLastError(WN_NO_NETWORK);
2006 return WN_NO_NETWORK;
2009 /*********************************************************************
2010 * WNetConnectionDialog1W [MPR.@]
2012 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2014 FIXME( "(%p): stub\n", lpConnDlgStruct );
2016 SetLastError(WN_NO_NETWORK);
2017 return WN_NO_NETWORK;
2020 /*********************************************************************
2021 * WNetDisconnectDialog [MPR.@]
2023 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2025 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2027 SetLastError(WN_NO_NETWORK);
2028 return WN_NO_NETWORK;
2031 /*********************************************************************
2032 * WNetDisconnectDialog1A [MPR.@]
2034 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2036 FIXME( "(%p): stub\n", lpConnDlgStruct );
2038 SetLastError(WN_NO_NETWORK);
2039 return WN_NO_NETWORK;
2042 /*********************************************************************
2043 * WNetDisconnectDialog1W [MPR.@]
2045 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2047 FIXME( "(%p): stub\n", lpConnDlgStruct );
2049 SetLastError(WN_NO_NETWORK);
2050 return WN_NO_NETWORK;
2053 /*********************************************************************
2054 * WNetGetLastErrorA [MPR.@]
2056 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2057 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2058 LPSTR lpNameBuf, DWORD nNameBufSize )
2060 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2061 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2063 SetLastError(WN_NO_NETWORK);
2064 return WN_NO_NETWORK;
2067 /*********************************************************************
2068 * WNetGetLastErrorW [MPR.@]
2070 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2071 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2072 LPWSTR lpNameBuf, DWORD nNameBufSize )
2074 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2075 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2077 SetLastError(WN_NO_NETWORK);
2078 return WN_NO_NETWORK;
2081 /*********************************************************************
2082 * WNetGetNetworkInformationA [MPR.@]
2084 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2085 LPNETINFOSTRUCT lpNetInfoStruct )
2087 DWORD ret;
2089 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2091 if (!lpProvider)
2092 ret = WN_BAD_POINTER;
2093 else
2095 int len;
2097 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2098 if (len)
2100 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2102 if (wideProvider)
2104 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2105 len);
2106 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2107 HeapFree(GetProcessHeap(), 0, wideProvider);
2109 else
2110 ret = WN_OUT_OF_MEMORY;
2112 else
2113 ret = GetLastError();
2115 if (ret)
2116 SetLastError(ret);
2117 TRACE("Returning %d\n", ret);
2118 return ret;
2121 /*********************************************************************
2122 * WNetGetNetworkInformationW [MPR.@]
2124 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2125 LPNETINFOSTRUCT lpNetInfoStruct )
2127 DWORD ret;
2129 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2131 if (!lpProvider)
2132 ret = WN_BAD_POINTER;
2133 else if (!lpNetInfoStruct)
2134 ret = WN_BAD_POINTER;
2135 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2136 ret = WN_BAD_VALUE;
2137 else
2139 if (providerTable && providerTable->numProviders)
2141 DWORD providerIndex = _findProviderIndexW(lpProvider);
2143 if (providerIndex != BAD_PROVIDER_INDEX)
2145 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2146 lpNetInfoStruct->dwProviderVersion =
2147 providerTable->table[providerIndex].dwSpecVersion;
2148 lpNetInfoStruct->dwStatus = NO_ERROR;
2149 lpNetInfoStruct->dwCharacteristics = 0;
2150 lpNetInfoStruct->dwHandle = 0;
2151 lpNetInfoStruct->wNetType =
2152 HIWORD(providerTable->table[providerIndex].dwNetType);
2153 lpNetInfoStruct->dwPrinters = -1;
2154 lpNetInfoStruct->dwDrives = -1;
2155 ret = WN_SUCCESS;
2157 else
2158 ret = WN_BAD_PROVIDER;
2160 else
2161 ret = WN_NO_NETWORK;
2163 if (ret)
2164 SetLastError(ret);
2165 TRACE("Returning %d\n", ret);
2166 return ret;
2169 /*****************************************************************
2170 * WNetGetProviderNameA [MPR.@]
2172 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2173 LPSTR lpProvider, LPDWORD lpBufferSize )
2175 DWORD ret;
2177 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2178 lpBufferSize);
2180 if (!lpProvider)
2181 ret = WN_BAD_POINTER;
2182 else if (!lpBufferSize)
2183 ret = WN_BAD_POINTER;
2184 else
2186 if (providerTable)
2188 DWORD i;
2190 ret = WN_NO_NETWORK;
2191 for (i = 0; i < providerTable->numProviders &&
2192 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2193 i++)
2195 if (i < providerTable->numProviders)
2197 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2198 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2200 if (*lpBufferSize < sizeNeeded)
2202 *lpBufferSize = sizeNeeded;
2203 ret = WN_MORE_DATA;
2205 else
2207 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2208 -1, lpProvider, *lpBufferSize, NULL, NULL);
2209 ret = WN_SUCCESS;
2210 /* FIXME: is *lpBufferSize set to the number of characters
2211 * copied? */
2215 else
2216 ret = WN_NO_NETWORK;
2218 if (ret)
2219 SetLastError(ret);
2220 TRACE("Returning %d\n", ret);
2221 return ret;
2224 /*****************************************************************
2225 * WNetGetProviderNameW [MPR.@]
2227 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2228 LPWSTR lpProvider, LPDWORD lpBufferSize )
2230 DWORD ret;
2232 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2233 lpBufferSize);
2235 if (!lpProvider)
2236 ret = WN_BAD_POINTER;
2237 else if (!lpBufferSize)
2238 ret = WN_BAD_POINTER;
2239 else
2241 if (providerTable)
2243 DWORD i;
2245 ret = WN_NO_NETWORK;
2246 for (i = 0; i < providerTable->numProviders &&
2247 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2248 i++)
2250 if (i < providerTable->numProviders)
2252 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2254 if (*lpBufferSize < sizeNeeded)
2256 *lpBufferSize = sizeNeeded;
2257 ret = WN_MORE_DATA;
2259 else
2261 strcpyW(lpProvider, providerTable->table[i].name);
2262 ret = WN_SUCCESS;
2263 /* FIXME: is *lpBufferSize set to the number of characters
2264 * copied? */
2268 else
2269 ret = WN_NO_NETWORK;
2271 if (ret)
2272 SetLastError(ret);
2273 TRACE("Returning %d\n", ret);
2274 return ret;