d3d11/tests: Test creating SM4 shaders on feature level 9.
[wine.git] / dlls / mpr / wnet.c
blob62e14796e446f68e27bb797dd6b4eeab177ff858
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 PF_NPAddConnection addConnection;
60 PF_NPAddConnection3 addConnection3;
61 } WNetProvider, *PWNetProvider;
63 typedef struct _WNetProviderTable
65 LPWSTR entireNetwork;
66 DWORD numAllocated;
67 DWORD numProviders;
68 WNetProvider table[1];
69 } WNetProviderTable, *PWNetProviderTable;
71 #define WNET_ENUMERATOR_TYPE_NULL 0
72 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
73 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
74 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
76 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
77 * the enumeration; it represents one of the following types:
78 * - a 'null' enumeration, one that contains no members
79 * - a global enumeration, one that's executed across all providers
80 * - a provider-specific enumeration, one that's only executed by a single
81 * provider
82 * - a context enumeration. I know this contradicts what I just said about
83 * there being no correspondence between the scope and the type, but it's
84 * necessary for the special case that a "Entire Network" entry needs to
85 * be enumerated in an enumeration of the context scope. Thus an enumeration
86 * of the context scope results in a context type enumerator, which morphs
87 * into a global enumeration (so the enumeration continues across all
88 * providers).
90 typedef struct _WNetEnumerator
92 DWORD enumType;
93 DWORD providerIndex;
94 HANDLE handle;
95 BOOL providerDone;
96 DWORD dwScope;
97 DWORD dwType;
98 DWORD dwUsage;
99 LPNETRESOURCEW lpNet;
100 } WNetEnumerator, *PWNetEnumerator;
102 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
104 /* Returns an index (into the global WNetProviderTable) of the provider with
105 * the given name, or BAD_PROVIDER_INDEX if not found.
107 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
109 static PWNetProviderTable providerTable;
112 * Global provider table functions
115 static void _tryLoadProvider(PCWSTR provider)
117 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
118 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
119 'S','e','r','v','i','c','e','s','\\',0 };
120 static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
121 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
122 WCHAR serviceName[MAX_PATH];
123 HKEY hKey;
125 TRACE("%s\n", debugstr_w(provider));
126 snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt,
127 servicePrefix, provider);
128 serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0';
129 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
130 ERROR_SUCCESS)
132 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
133 'P','a','t','h',0 };
134 WCHAR providerPath[MAX_PATH];
135 DWORD type, size = sizeof(providerPath);
137 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
138 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && (type == REG_SZ || type == REG_EXPAND_SZ))
140 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
141 PWSTR name = NULL;
143 if (type == REG_EXPAND_SZ)
145 WCHAR path[MAX_PATH];
146 if (ExpandEnvironmentStringsW(providerPath, path, MAX_PATH)) lstrcpyW( providerPath, path );
149 size = 0;
150 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
151 if (size)
153 name = HeapAlloc(GetProcessHeap(), 0, size);
154 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
155 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
157 HeapFree(GetProcessHeap(), 0, name);
158 name = NULL;
161 if (name)
163 HMODULE hLib = LoadLibraryW(providerPath);
165 if (hLib)
167 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
169 PF_NPGetCaps getCaps = MPR_GETPROC(NPGetCaps);
171 TRACE("loaded lib %p\n", hLib);
172 if (getCaps)
174 PWNetProvider provider =
175 &providerTable->table[providerTable->numProviders];
177 provider->hLib = hLib;
178 provider->name = name;
179 TRACE("name is %s\n", debugstr_w(name));
180 provider->getCaps = getCaps;
181 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
182 provider->dwNetType = getCaps(WNNC_NET_TYPE);
183 TRACE("net type is 0x%08x\n", provider->dwNetType);
184 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
185 if (provider->dwEnumScopes)
187 TRACE("supports enumeration\n");
188 provider->openEnum = MPR_GETPROC(NPOpenEnum);
189 TRACE("NPOpenEnum %p\n", provider->openEnum);
190 provider->enumResource = MPR_GETPROC(NPEnumResource);
191 TRACE("NPEnumResource %p\n", provider->enumResource);
192 provider->closeEnum = MPR_GETPROC(NPCloseEnum);
193 TRACE("NPCloseEnum %p\n", provider->closeEnum);
194 provider->getResourceInformation = MPR_GETPROC(NPGetResourceInformation);
195 TRACE("NPGetResourceInformation %p\n", provider->getResourceInformation);
196 if (!provider->openEnum ||
197 !provider->enumResource ||
198 !provider->closeEnum)
200 provider->openEnum = NULL;
201 provider->enumResource = NULL;
202 provider->closeEnum = NULL;
203 provider->dwEnumScopes = 0;
204 WARN("Couldn't load enumeration functions\n");
207 provider->addConnection = MPR_GETPROC(NPAddConnection);
208 provider->addConnection3 = MPR_GETPROC(NPAddConnection3);
209 TRACE("NPAddConnection %p\n", provider->addConnection);
210 TRACE("NPAddConnection3 %p\n", provider->addConnection3);
211 providerTable->numProviders++;
213 else
215 WARN("Provider %s didn't export NPGetCaps\n",
216 debugstr_w(provider));
217 HeapFree(GetProcessHeap(), 0, name);
218 FreeLibrary(hLib);
221 #undef MPR_GETPROC
223 else
225 WARN("Couldn't load library %s for provider %s\n",
226 debugstr_w(providerPath), debugstr_w(provider));
227 HeapFree(GetProcessHeap(), 0, name);
230 else
232 WARN("Couldn't get provider name for provider %s\n",
233 debugstr_w(provider));
236 else
237 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
238 RegCloseKey(hKey);
240 else
241 WARN("Couldn't open service key for provider %s\n",
242 debugstr_w(provider));
245 void wnetInit(HINSTANCE hInstDll)
247 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
248 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
249 'C','o','n','t','r','o','l','\\',
250 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
251 'O','r','d','e','r',0 };
252 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
253 'O','r','d','e','r',0 };
254 HKEY hKey;
256 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
257 == ERROR_SUCCESS)
259 DWORD size = 0;
261 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
262 if (size)
264 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
266 if (providers)
268 DWORD type;
270 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
271 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
273 PWSTR ptr;
274 DWORD numToAllocate;
276 TRACE("provider order is %s\n", debugstr_w(providers));
277 /* first count commas as a heuristic for how many to
278 * allocate space for */
279 for (ptr = providers, numToAllocate = 1; ptr; )
281 ptr = strchrW(ptr, ',');
282 if (ptr) {
283 numToAllocate++;
284 ptr++;
287 providerTable =
288 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
289 sizeof(WNetProviderTable)
290 + (numToAllocate - 1) * sizeof(WNetProvider));
291 if (providerTable)
293 PWSTR ptrPrev;
294 int entireNetworkLen;
295 LPCWSTR stringresource;
297 entireNetworkLen = LoadStringW(hInstDll,
298 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
299 providerTable->entireNetwork = HeapAlloc(
300 GetProcessHeap(), 0, (entireNetworkLen + 1) *
301 sizeof(WCHAR));
302 if (providerTable->entireNetwork)
304 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
305 providerTable->entireNetwork[entireNetworkLen] = 0;
307 providerTable->numAllocated = numToAllocate;
308 for (ptr = providers; ptr; )
310 ptrPrev = ptr;
311 ptr = strchrW(ptr, ',');
312 if (ptr)
313 *ptr++ = '\0';
314 _tryLoadProvider(ptrPrev);
318 HeapFree(GetProcessHeap(), 0, providers);
321 RegCloseKey(hKey);
325 void wnetFree(void)
327 if (providerTable)
329 DWORD i;
331 for (i = 0; i < providerTable->numProviders; i++)
333 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
334 FreeModule(providerTable->table[i].hLib);
336 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
337 HeapFree(GetProcessHeap(), 0, providerTable);
338 providerTable = NULL;
342 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
344 DWORD ret = BAD_PROVIDER_INDEX;
346 if (providerTable && providerTable->numProviders)
348 DWORD i;
350 for (i = 0; i < providerTable->numProviders &&
351 ret == BAD_PROVIDER_INDEX; i++)
352 if (!strcmpW(lpProvider, providerTable->table[i].name))
353 ret = i;
355 return ret;
359 * Browsing Functions
362 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
364 LPNETRESOURCEW ret;
366 if (lpNet)
368 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
369 if (ret)
371 size_t len;
373 *ret = *lpNet;
374 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
375 if (lpNet->lpRemoteName)
377 len = strlenW(lpNet->lpRemoteName) + 1;
378 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
379 if (ret->lpRemoteName)
380 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
384 else
385 ret = NULL;
386 return ret;
389 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
391 if (lpNet)
393 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
394 HeapFree(GetProcessHeap(), 0, lpNet);
398 static PWNetEnumerator _createNullEnumerator(void)
400 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
401 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
403 if (ret)
404 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
405 return ret;
408 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
409 DWORD dwUsage, LPNETRESOURCEW lpNet)
411 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
412 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
414 if (ret)
416 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
417 ret->dwScope = dwScope;
418 ret->dwType = dwType;
419 ret->dwUsage = dwUsage;
420 ret->lpNet = _copyNetResourceForEnumW(lpNet);
422 return ret;
425 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
426 DWORD dwUsage, DWORD index, HANDLE handle)
428 PWNetEnumerator ret;
430 if (!providerTable || index >= providerTable->numProviders)
431 ret = NULL;
432 else
434 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
435 if (ret)
437 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
438 ret->providerIndex = index;
439 ret->dwScope = dwScope;
440 ret->dwType = dwType;
441 ret->dwUsage = dwUsage;
442 ret->handle = handle;
445 return ret;
448 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
449 DWORD dwUsage)
451 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
452 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
454 if (ret)
456 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
457 ret->dwScope = dwScope;
458 ret->dwType = dwType;
459 ret->dwUsage = dwUsage;
461 return ret;
464 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
465 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
466 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
467 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
468 * if not all members of the array could be thunked, and something else on
469 * failure.
471 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
472 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
474 DWORD i, numToThunk, totalBytes, ret;
475 LPSTR strNext;
477 if (!lpNetArrayIn)
478 return WN_BAD_POINTER;
479 if (!lpcCount)
480 return WN_BAD_POINTER;
481 if (*lpcCount == -1)
482 return WN_BAD_VALUE;
483 if (!lpBuffer)
484 return WN_BAD_POINTER;
485 if (!lpBufferSize)
486 return WN_BAD_POINTER;
488 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
490 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
492 totalBytes += sizeof(NETRESOURCEA);
493 if (lpNet->lpLocalName)
494 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
495 -1, NULL, 0, NULL, NULL);
496 if (lpNet->lpRemoteName)
497 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
498 -1, NULL, 0, NULL, NULL);
499 if (lpNet->lpComment)
500 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
501 -1, NULL, 0, NULL, NULL);
502 if (lpNet->lpProvider)
503 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
504 -1, NULL, 0, NULL, NULL);
505 if (totalBytes < *lpBufferSize)
506 numToThunk = i + 1;
508 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
509 for (i = 0; i < numToThunk; i++)
511 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
512 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
514 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
515 /* lie about string lengths, we already verified how many
516 * we have space for above
518 if (lpNetIn->lpLocalName)
520 lpNetOut->lpLocalName = strNext;
521 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
522 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
524 if (lpNetIn->lpRemoteName)
526 lpNetOut->lpRemoteName = strNext;
527 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
528 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
530 if (lpNetIn->lpComment)
532 lpNetOut->lpComment = strNext;
533 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
534 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
536 if (lpNetIn->lpProvider)
538 lpNetOut->lpProvider = strNext;
539 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
540 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
543 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
544 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
545 *lpcCount, ret);
546 return ret;
549 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
550 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
551 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
552 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
553 * if not all members of the array could be thunked, and something else on
554 * failure.
556 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
557 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
559 DWORD i, numToThunk, totalBytes, ret;
560 LPWSTR strNext;
562 if (!lpNetArrayIn)
563 return WN_BAD_POINTER;
564 if (!lpcCount)
565 return WN_BAD_POINTER;
566 if (*lpcCount == -1)
567 return WN_BAD_VALUE;
568 if (!lpBuffer)
569 return WN_BAD_POINTER;
570 if (!lpBufferSize)
571 return WN_BAD_POINTER;
573 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
575 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
577 totalBytes += sizeof(NETRESOURCEW);
578 if (lpNet->lpLocalName)
579 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
580 -1, NULL, 0) * sizeof(WCHAR);
581 if (lpNet->lpRemoteName)
582 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
583 -1, NULL, 0) * sizeof(WCHAR);
584 if (lpNet->lpComment)
585 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
586 -1, NULL, 0) * sizeof(WCHAR);
587 if (lpNet->lpProvider)
588 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
589 -1, NULL, 0) * sizeof(WCHAR);
590 if (totalBytes < *lpBufferSize)
591 numToThunk = i + 1;
593 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
594 for (i = 0; i < numToThunk; i++)
596 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
597 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
599 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
600 /* lie about string lengths, we already verified how many
601 * we have space for above
603 if (lpNetIn->lpLocalName)
605 lpNetOut->lpLocalName = strNext;
606 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
607 -1, lpNetOut->lpLocalName, *lpBufferSize);
609 if (lpNetIn->lpRemoteName)
611 lpNetOut->lpRemoteName = strNext;
612 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
613 -1, lpNetOut->lpRemoteName, *lpBufferSize);
615 if (lpNetIn->lpComment)
617 lpNetOut->lpComment = strNext;
618 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
619 -1, lpNetOut->lpComment, *lpBufferSize);
621 if (lpNetIn->lpProvider)
623 lpNetOut->lpProvider = strNext;
624 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
625 -1, lpNetOut->lpProvider, *lpBufferSize);
628 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
629 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
630 *lpcCount, ret);
631 return ret;
634 /*********************************************************************
635 * WNetOpenEnumA [MPR.@]
637 * See comments for WNetOpenEnumW.
639 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
640 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
642 DWORD ret;
644 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
645 dwScope, dwType, dwUsage, lpNet, lphEnum );
647 if (!lphEnum)
648 ret = WN_BAD_POINTER;
649 else if (!providerTable || providerTable->numProviders == 0)
651 *lphEnum = NULL;
652 ret = WN_NO_NETWORK;
654 else
656 if (lpNet)
658 LPNETRESOURCEW lpNetWide = NULL;
659 BYTE buf[1024];
660 DWORD size = sizeof(buf), count = 1;
661 BOOL allocated = FALSE;
663 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
664 if (ret == WN_MORE_DATA)
666 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
667 size);
668 if (lpNetWide)
670 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
671 &size);
672 allocated = TRUE;
674 else
675 ret = WN_OUT_OF_MEMORY;
677 else if (ret == WN_SUCCESS)
678 lpNetWide = (LPNETRESOURCEW)buf;
679 if (ret == WN_SUCCESS)
680 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
681 lphEnum);
682 if (allocated)
683 HeapFree(GetProcessHeap(), 0, lpNetWide);
685 else
686 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
688 if (ret)
689 SetLastError(ret);
690 TRACE("Returning %d\n", ret);
691 return ret;
694 /*********************************************************************
695 * WNetOpenEnumW [MPR.@]
697 * Network enumeration has way too many parameters, so I'm not positive I got
698 * them right. What I've got so far:
700 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
701 * all the network providers should be enumerated.
703 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
704 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
705 * lpProvider is set, all the network providers should be enumerated.
706 * (This means the enumeration is a list of network providers, not that the
707 * enumeration is passed on to the providers.)
709 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
710 * resource matches the "Entire Network" resource (no remote name, no
711 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
712 * enumeration is done on every network provider.
714 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
715 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
716 * only to the given network provider.
718 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
719 * no lpProvider is set, enumeration will be tried on every network provider,
720 * in the order in which they're loaded.
722 * - The LPNETRESOURCE should be disregarded for scopes besides
723 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
724 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
726 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
727 * resource in the enumerated list, as well as any machines in your
728 * workgroup. The machines in your workgroup come from doing a
729 * RESOURCE_CONTEXT enumeration of every Network Provider.
731 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
732 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
734 DWORD ret;
736 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
737 dwScope, dwType, dwUsage, lpNet, lphEnum );
739 if (!lphEnum)
740 ret = WN_BAD_POINTER;
741 else if (!providerTable || providerTable->numProviders == 0)
743 *lphEnum = NULL;
744 ret = WN_NO_NETWORK;
746 else
748 switch (dwScope)
750 case RESOURCE_GLOBALNET:
751 if (lpNet)
753 if (lpNet->lpProvider)
755 DWORD index = _findProviderIndexW(lpNet->lpProvider);
757 if (index != BAD_PROVIDER_INDEX)
759 if (providerTable->table[index].openEnum &&
760 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
762 HANDLE handle;
764 ret = providerTable->table[index].openEnum(
765 dwScope, dwType, dwUsage, lpNet, &handle);
766 if (ret == WN_SUCCESS)
768 *lphEnum = _createProviderEnumerator(
769 dwScope, dwType, dwUsage, index, handle);
770 ret = *lphEnum ? WN_SUCCESS :
771 WN_OUT_OF_MEMORY;
774 else
775 ret = WN_NOT_SUPPORTED;
777 else
778 ret = WN_BAD_PROVIDER;
780 else if (lpNet->lpRemoteName)
782 *lphEnum = _createGlobalEnumeratorW(dwScope,
783 dwType, dwUsage, lpNet);
784 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
786 else
788 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
789 providerTable->entireNetwork))
791 /* comment matches the "Entire Network", enumerate
792 * global scope of every provider
794 *lphEnum = _createGlobalEnumeratorW(dwScope,
795 dwType, dwUsage, lpNet);
797 else
799 /* this is the same as not having passed lpNet */
800 *lphEnum = _createGlobalEnumeratorW(dwScope,
801 dwType, dwUsage, NULL);
803 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
806 else
808 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
809 dwUsage, lpNet);
810 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
812 break;
813 case RESOURCE_CONTEXT:
814 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
815 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
816 break;
817 case RESOURCE_REMEMBERED:
818 case RESOURCE_CONNECTED:
819 *lphEnum = _createNullEnumerator();
820 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
821 break;
822 default:
823 WARN("unknown scope 0x%08x\n", dwScope);
824 ret = WN_BAD_VALUE;
827 if (ret)
828 SetLastError(ret);
829 TRACE("Returning %d\n", ret);
830 return ret;
833 /*********************************************************************
834 * WNetEnumResourceA [MPR.@]
836 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
837 LPVOID lpBuffer, LPDWORD lpBufferSize )
839 DWORD ret;
841 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
843 if (!hEnum)
844 ret = WN_BAD_POINTER;
845 else if (!lpcCount)
846 ret = WN_BAD_POINTER;
847 else if (!lpBuffer)
848 ret = WN_BAD_POINTER;
849 else if (!lpBufferSize)
850 ret = WN_BAD_POINTER;
851 else if (*lpBufferSize < sizeof(NETRESOURCEA))
853 *lpBufferSize = sizeof(NETRESOURCEA);
854 ret = WN_MORE_DATA;
856 else
858 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
859 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
861 if (localBuffer)
863 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
864 &localSize);
865 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
867 /* FIXME: this isn't necessarily going to work in the case of
868 * WN_MORE_DATA, because our enumerator may have moved on to
869 * the next provider. MSDN states that a large (16KB) buffer
870 * size is the appropriate usage of this function, so
871 * hopefully it won't be an issue.
873 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
874 lpBuffer, lpBufferSize);
875 *lpcCount = localCount;
877 HeapFree(GetProcessHeap(), 0, localBuffer);
879 else
880 ret = WN_OUT_OF_MEMORY;
882 if (ret)
883 SetLastError(ret);
884 TRACE("Returning %d\n", ret);
885 return ret;
888 static DWORD _countProviderBytesW(PWNetProvider provider)
890 DWORD ret;
892 if (provider)
894 ret = sizeof(NETRESOURCEW);
895 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
897 else
898 ret = 0;
899 return ret;
902 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
903 LPVOID lpBuffer, const DWORD *lpBufferSize)
905 DWORD ret;
907 if (!enumerator)
908 return WN_BAD_POINTER;
909 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
910 return WN_BAD_VALUE;
911 if (!lpcCount)
912 return WN_BAD_POINTER;
913 if (!lpBuffer)
914 return WN_BAD_POINTER;
915 if (!lpBufferSize)
916 return WN_BAD_POINTER;
917 if (*lpBufferSize < sizeof(NETRESOURCEA))
918 return WN_MORE_DATA;
920 if (!providerTable || enumerator->providerIndex >=
921 providerTable->numProviders)
922 ret = WN_NO_MORE_ENTRIES;
923 else
925 DWORD bytes = 0, count = 0, countLimit, i;
926 LPNETRESOURCEW resource;
927 LPWSTR strNext;
929 countLimit = *lpcCount == -1 ?
930 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
931 while (count < countLimit && bytes < *lpBufferSize)
933 DWORD bytesNext = _countProviderBytesW(
934 &providerTable->table[count + enumerator->providerIndex]);
936 if (bytes + bytesNext < *lpBufferSize)
938 bytes += bytesNext;
939 count++;
942 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
943 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
945 resource->dwScope = RESOURCE_GLOBALNET;
946 resource->dwType = RESOURCETYPE_ANY;
947 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
948 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
949 RESOURCEUSAGE_RESERVED;
950 resource->lpLocalName = NULL;
951 resource->lpRemoteName = strNext;
952 strcpyW(resource->lpRemoteName,
953 providerTable->table[i + enumerator->providerIndex].name);
954 strNext += strlenW(resource->lpRemoteName) + 1;
955 resource->lpComment = NULL;
956 resource->lpProvider = strNext;
957 strcpyW(resource->lpProvider,
958 providerTable->table[i + enumerator->providerIndex].name);
959 strNext += strlenW(resource->lpProvider) + 1;
961 enumerator->providerIndex += count;
962 *lpcCount = count;
963 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
965 TRACE("Returning %d\n", ret);
966 return ret;
969 /* Advances the enumerator (assumed to be a global enumerator) to the next
970 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
971 * not open a handle with the next provider.
972 * If the existing handle is NULL, may leave the enumerator unchanged, since
973 * the current provider may support the desired scope.
974 * If the existing handle is not NULL, closes it before moving on.
975 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
976 * provider, and another error on failure.
978 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
980 if (!enumerator)
981 return WN_BAD_POINTER;
982 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
983 return WN_BAD_VALUE;
984 if (!providerTable || enumerator->providerIndex >=
985 providerTable->numProviders)
986 return WN_NO_MORE_ENTRIES;
988 if (enumerator->providerDone)
990 DWORD dwEnum = 0;
991 enumerator->providerDone = FALSE;
992 if (enumerator->handle)
994 providerTable->table[enumerator->providerIndex].closeEnum(
995 enumerator->handle);
996 enumerator->handle = NULL;
997 enumerator->providerIndex++;
999 if (enumerator->dwScope == RESOURCE_CONNECTED)
1000 dwEnum = WNNC_ENUM_LOCAL;
1001 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
1002 dwEnum = WNNC_ENUM_GLOBAL;
1003 else if (enumerator->dwScope == RESOURCE_CONTEXT)
1004 dwEnum = WNNC_ENUM_CONTEXT;
1005 for (; enumerator->providerIndex < providerTable->numProviders &&
1006 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
1007 & dwEnum); enumerator->providerIndex++)
1010 return enumerator->providerIndex < providerTable->numProviders ?
1011 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1014 /* "Passes through" call to the next provider that supports the enumeration
1015 * type.
1016 * FIXME: if one call to a provider's enumerator succeeds while there's still
1017 * space in lpBuffer, I don't call to the next provider. The caller may not
1018 * expect that it should call EnumResourceW again with a return value of
1019 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1020 * may have to be moved around a bit, ick.
1022 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1023 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1025 DWORD ret;
1027 if (!enumerator)
1028 return WN_BAD_POINTER;
1029 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1030 return WN_BAD_VALUE;
1031 if (!lpcCount)
1032 return WN_BAD_POINTER;
1033 if (!lpBuffer)
1034 return WN_BAD_POINTER;
1035 if (!lpBufferSize)
1036 return WN_BAD_POINTER;
1037 if (*lpBufferSize < sizeof(NETRESOURCEW))
1038 return WN_MORE_DATA;
1040 ret = _globalEnumeratorAdvance(enumerator);
1041 if (ret == WN_SUCCESS)
1043 ret = providerTable->table[enumerator->providerIndex].
1044 openEnum(enumerator->dwScope, enumerator->dwType,
1045 enumerator->dwUsage, enumerator->lpNet,
1046 &enumerator->handle);
1047 if (ret == WN_SUCCESS)
1049 ret = providerTable->table[enumerator->providerIndex].
1050 enumResource(enumerator->handle, lpcCount, lpBuffer,
1051 lpBufferSize);
1052 if (ret != WN_MORE_DATA)
1053 enumerator->providerDone = TRUE;
1056 TRACE("Returning %d\n", ret);
1057 return ret;
1060 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1061 LPVOID lpBuffer, LPDWORD lpBufferSize)
1063 DWORD ret;
1065 if (!enumerator)
1066 return WN_BAD_POINTER;
1067 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1068 return WN_BAD_VALUE;
1069 if (!lpcCount)
1070 return WN_BAD_POINTER;
1071 if (!lpBuffer)
1072 return WN_BAD_POINTER;
1073 if (!lpBufferSize)
1074 return WN_BAD_POINTER;
1075 if (*lpBufferSize < sizeof(NETRESOURCEW))
1076 return WN_MORE_DATA;
1077 if (!providerTable)
1078 return WN_NO_NETWORK;
1080 switch (enumerator->dwScope)
1082 case RESOURCE_GLOBALNET:
1083 if (enumerator->lpNet)
1084 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1085 lpBuffer, lpBufferSize);
1086 else
1087 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1088 lpBufferSize);
1089 break;
1090 case RESOURCE_CONTEXT:
1091 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1092 lpBufferSize);
1093 break;
1094 default:
1095 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1096 ret = WN_NO_MORE_ENTRIES;
1098 TRACE("Returning %d\n", ret);
1099 return ret;
1102 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1103 LPVOID lpBuffer, LPDWORD lpBufferSize)
1105 if (!enumerator)
1106 return WN_BAD_POINTER;
1107 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1108 return WN_BAD_VALUE;
1109 if (!enumerator->handle)
1110 return WN_BAD_VALUE;
1111 if (!lpcCount)
1112 return WN_BAD_POINTER;
1113 if (!lpBuffer)
1114 return WN_BAD_POINTER;
1115 if (!lpBufferSize)
1116 return WN_BAD_POINTER;
1117 if (!providerTable)
1118 return WN_NO_NETWORK;
1119 if (enumerator->providerIndex >= providerTable->numProviders)
1120 return WN_NO_MORE_ENTRIES;
1121 if (!providerTable->table[enumerator->providerIndex].enumResource)
1122 return WN_BAD_VALUE;
1123 return providerTable->table[enumerator->providerIndex].enumResource(
1124 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1127 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1128 LPVOID lpBuffer, LPDWORD lpBufferSize)
1130 DWORD ret;
1131 size_t cchEntireNetworkLen, bytesNeeded;
1133 if (!enumerator)
1134 return WN_BAD_POINTER;
1135 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1136 return WN_BAD_VALUE;
1137 if (!lpcCount)
1138 return WN_BAD_POINTER;
1139 if (!lpBuffer)
1140 return WN_BAD_POINTER;
1141 if (!lpBufferSize)
1142 return WN_BAD_POINTER;
1143 if (!providerTable)
1144 return WN_NO_NETWORK;
1146 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1147 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1148 if (*lpBufferSize < bytesNeeded)
1150 *lpBufferSize = bytesNeeded;
1151 ret = WN_MORE_DATA;
1153 else
1155 LPNETRESOURCEW lpNet = lpBuffer;
1157 lpNet->dwScope = RESOURCE_GLOBALNET;
1158 lpNet->dwType = enumerator->dwType;
1159 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1160 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1161 lpNet->lpLocalName = NULL;
1162 lpNet->lpRemoteName = NULL;
1163 lpNet->lpProvider = NULL;
1164 /* odd, but correct: put comment at end of buffer, so it won't get
1165 * overwritten by subsequent calls to a provider's enumResource
1167 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1168 (cchEntireNetworkLen * sizeof(WCHAR)));
1169 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1170 ret = WN_SUCCESS;
1172 if (ret == WN_SUCCESS)
1174 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1176 /* "Entire Network" entry enumerated--morph this into a global
1177 * enumerator. enumerator->lpNet continues to be NULL, since it has
1178 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1180 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1181 ret = _enumerateGlobalW(enumerator, lpcCount,
1182 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1183 if (ret == WN_SUCCESS)
1185 /* reflect the fact that we already enumerated "Entire Network" */
1186 (*lpcCount)++;
1187 *lpBufferSize = bufferSize + bytesNeeded;
1189 else
1191 /* the provider enumeration failed, but we already succeeded in
1192 * enumerating "Entire Network"--leave type as global to allow a
1193 * retry, but indicate success with a count of one.
1195 ret = WN_SUCCESS;
1196 *lpcCount = 1;
1197 *lpBufferSize = bytesNeeded;
1200 TRACE("Returning %d\n", ret);
1201 return ret;
1204 /*********************************************************************
1205 * WNetEnumResourceW [MPR.@]
1207 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1208 LPVOID lpBuffer, LPDWORD lpBufferSize )
1210 DWORD ret;
1212 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1214 if (!hEnum)
1215 ret = WN_BAD_POINTER;
1216 else if (!lpcCount)
1217 ret = WN_BAD_POINTER;
1218 else if (!lpBuffer)
1219 ret = WN_BAD_POINTER;
1220 else if (!lpBufferSize)
1221 ret = WN_BAD_POINTER;
1222 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1224 *lpBufferSize = sizeof(NETRESOURCEW);
1225 ret = WN_MORE_DATA;
1227 else
1229 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1231 switch (enumerator->enumType)
1233 case WNET_ENUMERATOR_TYPE_NULL:
1234 ret = WN_NO_MORE_ENTRIES;
1235 break;
1236 case WNET_ENUMERATOR_TYPE_GLOBAL:
1237 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1238 lpBufferSize);
1239 break;
1240 case WNET_ENUMERATOR_TYPE_PROVIDER:
1241 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1242 lpBufferSize);
1243 break;
1244 case WNET_ENUMERATOR_TYPE_CONTEXT:
1245 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1246 lpBufferSize);
1247 break;
1248 default:
1249 WARN("bogus enumerator type!\n");
1250 ret = WN_NO_NETWORK;
1253 if (ret)
1254 SetLastError(ret);
1255 TRACE("Returning %d\n", ret);
1256 return ret;
1259 /*********************************************************************
1260 * WNetCloseEnum [MPR.@]
1262 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1264 DWORD ret;
1266 TRACE( "(%p)\n", hEnum );
1268 if (hEnum)
1270 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1272 switch (enumerator->enumType)
1274 case WNET_ENUMERATOR_TYPE_NULL:
1275 ret = WN_SUCCESS;
1276 break;
1277 case WNET_ENUMERATOR_TYPE_GLOBAL:
1278 if (enumerator->lpNet)
1279 _freeEnumNetResource(enumerator->lpNet);
1280 if (enumerator->handle)
1281 providerTable->table[enumerator->providerIndex].
1282 closeEnum(enumerator->handle);
1283 ret = WN_SUCCESS;
1284 break;
1285 case WNET_ENUMERATOR_TYPE_PROVIDER:
1286 if (enumerator->handle)
1287 providerTable->table[enumerator->providerIndex].
1288 closeEnum(enumerator->handle);
1289 ret = WN_SUCCESS;
1290 break;
1291 default:
1292 WARN("bogus enumerator type!\n");
1293 ret = WN_BAD_HANDLE;
1295 HeapFree(GetProcessHeap(), 0, hEnum);
1297 else
1298 ret = WN_BAD_HANDLE;
1299 if (ret)
1300 SetLastError(ret);
1301 TRACE("Returning %d\n", ret);
1302 return ret;
1305 /*********************************************************************
1306 * WNetGetResourceInformationA [MPR.@]
1308 * See WNetGetResourceInformationW
1310 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1311 LPVOID lpBuffer, LPDWORD cbBuffer,
1312 LPSTR *lplpSystem )
1314 DWORD ret;
1316 TRACE( "(%p, %p, %p, %p)\n",
1317 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1319 if (!providerTable || providerTable->numProviders == 0)
1320 ret = WN_NO_NETWORK;
1321 else if (lpNetResource)
1323 LPNETRESOURCEW lpNetResourceW = NULL;
1324 DWORD size = 1024, count = 1;
1325 DWORD len;
1327 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1328 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1329 if (ret == WN_MORE_DATA)
1331 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1332 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1333 if (lpNetResourceW)
1334 ret = _thunkNetResourceArrayAToW(lpNetResource,
1335 &count, lpNetResourceW, &size);
1336 else
1337 ret = WN_OUT_OF_MEMORY;
1339 if (ret == WN_SUCCESS)
1341 LPWSTR lpSystemW = NULL;
1342 LPVOID lpBufferW;
1343 size = 1024;
1344 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1345 if (lpBufferW)
1347 ret = WNetGetResourceInformationW(lpNetResourceW,
1348 lpBufferW, &size, &lpSystemW);
1349 if (ret == WN_MORE_DATA)
1351 HeapFree(GetProcessHeap(), 0, lpBufferW);
1352 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1353 if (lpBufferW)
1354 ret = WNetGetResourceInformationW(lpNetResourceW,
1355 lpBufferW, &size, &lpSystemW);
1356 else
1357 ret = WN_OUT_OF_MEMORY;
1359 if (ret == WN_SUCCESS)
1361 ret = _thunkNetResourceArrayWToA(lpBufferW,
1362 &count, lpBuffer, cbBuffer);
1363 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1364 lpNetResourceW = lpBufferW;
1365 size = sizeof(NETRESOURCEA);
1366 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1367 -1, NULL, 0, NULL, NULL);
1368 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1369 -1, NULL, 0, NULL, NULL);
1371 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1372 -1, NULL, 0, NULL, NULL);
1373 if ((len) && ( size + len < *cbBuffer))
1375 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1376 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1377 *lplpSystem, len, NULL, NULL);
1378 ret = WN_SUCCESS;
1380 else
1381 ret = WN_MORE_DATA;
1383 else
1384 ret = WN_OUT_OF_MEMORY;
1385 HeapFree(GetProcessHeap(), 0, lpBufferW);
1387 else
1388 ret = WN_OUT_OF_MEMORY;
1389 HeapFree(GetProcessHeap(), 0, lpSystemW);
1391 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1393 else
1394 ret = WN_NO_NETWORK;
1396 if (ret)
1397 SetLastError(ret);
1398 TRACE("Returning %d\n", ret);
1399 return ret;
1402 /*********************************************************************
1403 * WNetGetResourceInformationW [MPR.@]
1405 * WNetGetResourceInformationW function identifies the network provider
1406 * that owns the resource and gets information about the type of the resource.
1408 * PARAMS:
1409 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1410 * defines a network resource.
1411 * lpBuffer [ O] the pointer to buffer, containing result. It
1412 * contains NETRESOURCEW structure and strings to
1413 * which the members of the NETRESOURCEW structure
1414 * point.
1415 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1416 * in bytes.
1417 * lplpSystem [ O] the pointer to string in the output buffer,
1418 * containing the part of the resource name without
1419 * names of the server and share.
1421 * RETURNS:
1422 * NO_ERROR if the function succeeds. System error code if the function fails.
1425 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1426 LPVOID lpBuffer, LPDWORD cbBuffer,
1427 LPWSTR *lplpSystem )
1429 DWORD ret = WN_NO_NETWORK;
1430 DWORD index;
1432 TRACE( "(%p, %p, %p, %p)\n",
1433 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1435 if (!(lpBuffer))
1436 ret = WN_OUT_OF_MEMORY;
1437 else if (providerTable != NULL)
1439 /* FIXME: For function value of a variable is indifferent, it does
1440 * search of all providers in a network.
1442 for (index = 0; index < providerTable->numProviders; index++)
1444 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1445 WNNC_DLG_GETRESOURCEINFORMATION)
1447 if (providerTable->table[index].getResourceInformation)
1448 ret = providerTable->table[index].getResourceInformation(
1449 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1450 else
1451 ret = WN_NO_NETWORK;
1452 if (ret == WN_SUCCESS)
1453 break;
1457 if (ret)
1458 SetLastError(ret);
1459 return ret;
1462 /*********************************************************************
1463 * WNetGetResourceParentA [MPR.@]
1465 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA 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;
1475 /*********************************************************************
1476 * WNetGetResourceParentW [MPR.@]
1478 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1479 LPVOID lpBuffer, LPDWORD lpBufferSize )
1481 FIXME( "(%p, %p, %p): stub\n",
1482 lpNetResource, lpBuffer, lpBufferSize );
1484 SetLastError(WN_NO_NETWORK);
1485 return WN_NO_NETWORK;
1491 * Connection Functions
1494 /*********************************************************************
1495 * WNetAddConnectionA [MPR.@]
1497 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1498 LPCSTR lpLocalName )
1500 NETRESOURCEA resourcesA;
1502 memset(&resourcesA, 0, sizeof(resourcesA));
1503 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1504 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1505 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1508 /*********************************************************************
1509 * WNetAddConnectionW [MPR.@]
1511 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1512 LPCWSTR lpLocalName )
1514 NETRESOURCEW resourcesW;
1516 memset(&resourcesW, 0, sizeof(resourcesW));
1517 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1518 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1519 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1522 /*********************************************************************
1523 * WNetAddConnection2A [MPR.@]
1525 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1526 LPCSTR lpPassword, LPCSTR lpUserID,
1527 DWORD dwFlags )
1529 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1530 NULL, 0, NULL);
1533 /*********************************************************************
1534 * WNetAddConnection2W [MPR.@]
1536 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1537 LPCWSTR lpPassword, LPCWSTR lpUserID,
1538 DWORD dwFlags )
1540 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1541 NULL, 0, NULL);
1544 /*********************************************************************
1545 * WNetAddConnection3A [MPR.@]
1547 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1548 LPCSTR lpPassword, LPCSTR lpUserID,
1549 DWORD dwFlags )
1551 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1552 dwFlags, NULL, 0, NULL);
1555 /*********************************************************************
1556 * WNetAddConnection3W [MPR.@]
1558 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1559 LPCWSTR lpPassword, LPCWSTR lpUserID,
1560 DWORD dwFlags )
1562 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1563 dwFlags, NULL, 0, NULL);
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, NETRESOURCEW *resource, LPCWSTR password,
1586 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
1588 WNetProvider *provider;
1589 DWORD index, ret, caps;
1591 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1592 hwndOwner, resource, password, debugstr_w(userid), flags,
1593 accessname, buffer_size, result );
1595 if (!providerTable || providerTable->numProviders == 0)
1596 return WN_NO_NETWORK;
1598 if (!resource)
1599 return ERROR_INVALID_PARAMETER;
1601 if (!resource->lpProvider)
1603 FIXME("Networking provider selection is not implemented.\n");
1604 return WN_NO_NETWORK;
1607 if (!resource->lpLocalName && (flags & CONNECT_REDIRECT))
1609 FIXME("Locale device selection is not implemented.\n");
1610 return WN_NO_NETWORK;
1613 if (flags & CONNECT_INTERACTIVE)
1614 return ERROR_BAD_NET_NAME;
1616 index = _findProviderIndexW(resource->lpProvider);
1617 if (index == BAD_PROVIDER_INDEX)
1618 return ERROR_BAD_PROVIDER;
1620 provider = &providerTable->table[index];
1621 caps = provider->getCaps(WNNC_CONNECTION);
1622 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1623 return ERROR_BAD_PROVIDER;
1625 if (accessname && buffer_size && *buffer_size)
1627 DWORD len;
1629 if (resource->lpLocalName)
1630 len = strlenW(resource->lpLocalName);
1631 else
1632 len = strlenW(resource->lpRemoteName);
1634 if (++len > *buffer_size)
1636 *buffer_size = len;
1637 return ERROR_MORE_DATA;
1640 else
1641 accessname = NULL;
1643 ret = WN_ACCESS_DENIED;
1644 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1645 ret = provider->addConnection3(hwndOwner, resource, (LPWSTR)password, (LPWSTR)userid, flags);
1646 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1647 ret = provider->addConnection(resource, (LPWSTR)password, (LPWSTR)userid);
1649 if (ret == WN_SUCCESS && accessname)
1651 if (resource->lpLocalName)
1652 strcpyW(accessname, resource->lpLocalName);
1653 else
1654 strcpyW(accessname, resource->lpRemoteName);
1657 return ret;
1660 /*********************************************************************
1661 * WNetCancelConnectionA [MPR.@]
1663 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1665 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1667 return WN_SUCCESS;
1670 /*********************************************************************
1671 * WNetCancelConnectionW [MPR.@]
1673 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1675 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1677 return WN_SUCCESS;
1680 /*********************************************************************
1681 * WNetCancelConnection2A [MPR.@]
1683 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1685 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1687 return WN_SUCCESS;
1690 /*********************************************************************
1691 * WNetCancelConnection2W [MPR.@]
1693 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1695 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1697 return WN_SUCCESS;
1700 /*****************************************************************
1701 * WNetRestoreConnectionA [MPR.@]
1703 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
1705 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1707 SetLastError(WN_NO_NETWORK);
1708 return WN_NO_NETWORK;
1711 /*****************************************************************
1712 * WNetRestoreConnectionW [MPR.@]
1714 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
1716 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1718 SetLastError(WN_NO_NETWORK);
1719 return WN_NO_NETWORK;
1722 /**************************************************************************
1723 * WNetGetConnectionA [MPR.@]
1725 * RETURNS
1726 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1727 * - WN_NOT_CONNECTED drive is a local drive
1728 * - WN_MORE_DATA buffer isn't big enough
1729 * - WN_SUCCESS success (net path in buffer)
1731 * FIXME: need to test return values under different errors
1733 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1734 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1736 DWORD ret;
1738 if (!lpLocalName)
1739 ret = WN_BAD_POINTER;
1740 else if (!lpBufferSize)
1741 ret = WN_BAD_POINTER;
1742 else if (!lpRemoteName && *lpBufferSize)
1743 ret = WN_BAD_POINTER;
1744 else
1746 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1748 if (len)
1750 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1752 if (wideLocalName)
1754 WCHAR wideRemoteStatic[MAX_PATH];
1755 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1757 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1759 /* try once without memory allocation */
1760 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1761 &wideRemoteSize);
1762 if (ret == WN_SUCCESS)
1764 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1765 -1, NULL, 0, NULL, NULL);
1767 if (len <= *lpBufferSize)
1769 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1770 lpRemoteName, *lpBufferSize, NULL, NULL);
1771 ret = WN_SUCCESS;
1773 else
1775 *lpBufferSize = len;
1776 ret = WN_MORE_DATA;
1779 else if (ret == WN_MORE_DATA)
1781 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1782 wideRemoteSize * sizeof(WCHAR));
1784 if (wideRemote)
1786 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1787 &wideRemoteSize);
1788 if (ret == WN_SUCCESS)
1790 if (len <= *lpBufferSize)
1792 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1793 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1794 ret = WN_SUCCESS;
1796 else
1798 *lpBufferSize = len;
1799 ret = WN_MORE_DATA;
1802 HeapFree(GetProcessHeap(), 0, wideRemote);
1804 else
1805 ret = WN_OUT_OF_MEMORY;
1807 HeapFree(GetProcessHeap(), 0, wideLocalName);
1809 else
1810 ret = WN_OUT_OF_MEMORY;
1812 else
1813 ret = WN_BAD_LOCALNAME;
1815 if (ret)
1816 SetLastError(ret);
1817 TRACE("Returning %d\n", ret);
1818 return ret;
1821 /* find the network connection for a given drive; helper for WNetGetConnection */
1822 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
1824 char buffer[1024];
1825 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
1826 HANDLE mgr;
1827 DWORD ret = WN_NOT_CONNECTED;
1828 DWORD bytes_returned;
1830 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
1831 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1832 0, 0 )) == INVALID_HANDLE_VALUE)
1834 ERR( "failed to open mount manager err %u\n", GetLastError() );
1835 return ret;
1837 memset( data, 0, sizeof(*data) );
1838 data->letter = letter;
1839 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
1840 data, sizeof(buffer), &bytes_returned, NULL ))
1842 char *p, *mount_point = buffer + data->mount_point_offset;
1843 DWORD len;
1845 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
1847 mount_point += 2;
1848 mount_point[0] = '\\';
1849 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
1851 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
1852 if (len > *size)
1854 *size = len;
1855 ret = WN_MORE_DATA;
1857 else
1859 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
1860 ret = WN_SUCCESS;
1864 CloseHandle( mgr );
1865 return ret;
1868 /**************************************************************************
1869 * WNetGetConnectionW [MPR.@]
1871 * FIXME: need to test return values under different errors
1873 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
1874 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
1876 DWORD ret;
1878 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
1879 lpBufferSize);
1881 if (!lpLocalName)
1882 ret = WN_BAD_POINTER;
1883 else if (!lpBufferSize)
1884 ret = WN_BAD_POINTER;
1885 else if (!lpRemoteName && *lpBufferSize)
1886 ret = WN_BAD_POINTER;
1887 else if (!lpLocalName[0])
1888 ret = WN_BAD_LOCALNAME;
1889 else
1891 if (lpLocalName[1] == ':')
1893 switch(GetDriveTypeW(lpLocalName))
1895 case DRIVE_REMOTE:
1896 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
1897 break;
1898 case DRIVE_REMOVABLE:
1899 case DRIVE_FIXED:
1900 case DRIVE_CDROM:
1901 TRACE("file is local\n");
1902 ret = WN_NOT_CONNECTED;
1903 break;
1904 default:
1905 ret = WN_BAD_LOCALNAME;
1908 else
1909 ret = WN_BAD_LOCALNAME;
1911 if (ret)
1912 SetLastError(ret);
1913 TRACE("Returning %d\n", ret);
1914 return ret;
1917 /**************************************************************************
1918 * WNetSetConnectionA [MPR.@]
1920 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
1921 LPVOID pvValue )
1923 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
1925 SetLastError(WN_NO_NETWORK);
1926 return WN_NO_NETWORK;
1929 /**************************************************************************
1930 * WNetSetConnectionW [MPR.@]
1932 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
1933 LPVOID pvValue )
1935 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
1937 SetLastError(WN_NO_NETWORK);
1938 return WN_NO_NETWORK;
1941 /*****************************************************************
1942 * WNetGetUniversalNameA [MPR.@]
1944 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
1945 LPVOID lpBuffer, LPDWORD lpBufferSize )
1947 DWORD err, size;
1949 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1950 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1952 switch (dwInfoLevel)
1954 case UNIVERSAL_NAME_INFO_LEVEL:
1956 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
1958 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
1960 err = ERROR_NOT_CONNECTED;
1961 break;
1964 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
1965 if (*lpBufferSize < size)
1967 err = WN_MORE_DATA;
1968 break;
1970 info->lpUniversalName = (char *)info + sizeof(*info);
1971 lstrcpyA(info->lpUniversalName, lpLocalPath);
1972 err = WN_NO_ERROR;
1973 break;
1975 case REMOTE_NAME_INFO_LEVEL:
1976 err = WN_NO_NETWORK;
1977 break;
1979 default:
1980 err = WN_BAD_VALUE;
1981 break;
1984 SetLastError(err);
1985 return err;
1988 /*****************************************************************
1989 * WNetGetUniversalNameW [MPR.@]
1991 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
1992 LPVOID lpBuffer, LPDWORD lpBufferSize )
1994 DWORD err, size;
1996 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1997 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1999 switch (dwInfoLevel)
2001 case UNIVERSAL_NAME_INFO_LEVEL:
2003 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2005 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2007 err = ERROR_NOT_CONNECTED;
2008 break;
2011 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2012 if (*lpBufferSize < size)
2014 err = WN_MORE_DATA;
2015 break;
2017 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2018 lstrcpyW(info->lpUniversalName, lpLocalPath);
2019 err = WN_NO_ERROR;
2020 break;
2022 case REMOTE_NAME_INFO_LEVEL:
2023 err = WN_NO_NETWORK;
2024 break;
2026 default:
2027 err = WN_BAD_VALUE;
2028 break;
2031 if (err != WN_NO_ERROR) SetLastError(err);
2032 return err;
2038 * Other Functions
2041 /**************************************************************************
2042 * WNetGetUserA [MPR.@]
2044 * FIXME: we should not return ourselves, but the owner of the drive lpName
2046 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2048 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2049 return GetLastError();
2052 /*****************************************************************
2053 * WNetGetUserW [MPR.@]
2055 * FIXME: we should not return ourselves, but the owner of the drive lpName
2057 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2059 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2060 return GetLastError();
2063 /*********************************************************************
2064 * WNetConnectionDialog [MPR.@]
2066 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2068 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2070 SetLastError(WN_NO_NETWORK);
2071 return WN_NO_NETWORK;
2074 /*********************************************************************
2075 * WNetConnectionDialog1A [MPR.@]
2077 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2079 FIXME( "(%p): stub\n", lpConnDlgStruct );
2081 SetLastError(WN_NO_NETWORK);
2082 return WN_NO_NETWORK;
2085 /*********************************************************************
2086 * WNetConnectionDialog1W [MPR.@]
2088 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2090 FIXME( "(%p): stub\n", lpConnDlgStruct );
2092 SetLastError(WN_NO_NETWORK);
2093 return WN_NO_NETWORK;
2096 /*********************************************************************
2097 * WNetDisconnectDialog [MPR.@]
2099 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2101 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2103 SetLastError(WN_NO_NETWORK);
2104 return WN_NO_NETWORK;
2107 /*********************************************************************
2108 * WNetDisconnectDialog1A [MPR.@]
2110 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2112 FIXME( "(%p): stub\n", lpConnDlgStruct );
2114 SetLastError(WN_NO_NETWORK);
2115 return WN_NO_NETWORK;
2118 /*********************************************************************
2119 * WNetDisconnectDialog1W [MPR.@]
2121 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2123 FIXME( "(%p): stub\n", lpConnDlgStruct );
2125 SetLastError(WN_NO_NETWORK);
2126 return WN_NO_NETWORK;
2129 /*********************************************************************
2130 * WNetGetLastErrorA [MPR.@]
2132 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2133 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2134 LPSTR lpNameBuf, DWORD nNameBufSize )
2136 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2137 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2139 SetLastError(WN_NO_NETWORK);
2140 return WN_NO_NETWORK;
2143 /*********************************************************************
2144 * WNetGetLastErrorW [MPR.@]
2146 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2147 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2148 LPWSTR lpNameBuf, DWORD nNameBufSize )
2150 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2151 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2153 SetLastError(WN_NO_NETWORK);
2154 return WN_NO_NETWORK;
2157 /*********************************************************************
2158 * WNetGetNetworkInformationA [MPR.@]
2160 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2161 LPNETINFOSTRUCT lpNetInfoStruct )
2163 DWORD ret;
2165 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2167 if (!lpProvider)
2168 ret = WN_BAD_POINTER;
2169 else
2171 int len;
2173 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2174 if (len)
2176 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2178 if (wideProvider)
2180 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2181 len);
2182 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2183 HeapFree(GetProcessHeap(), 0, wideProvider);
2185 else
2186 ret = WN_OUT_OF_MEMORY;
2188 else
2189 ret = GetLastError();
2191 if (ret)
2192 SetLastError(ret);
2193 TRACE("Returning %d\n", ret);
2194 return ret;
2197 /*********************************************************************
2198 * WNetGetNetworkInformationW [MPR.@]
2200 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2201 LPNETINFOSTRUCT lpNetInfoStruct )
2203 DWORD ret;
2205 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2207 if (!lpProvider)
2208 ret = WN_BAD_POINTER;
2209 else if (!lpNetInfoStruct)
2210 ret = WN_BAD_POINTER;
2211 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2212 ret = WN_BAD_VALUE;
2213 else
2215 if (providerTable && providerTable->numProviders)
2217 DWORD providerIndex = _findProviderIndexW(lpProvider);
2219 if (providerIndex != BAD_PROVIDER_INDEX)
2221 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2222 lpNetInfoStruct->dwProviderVersion =
2223 providerTable->table[providerIndex].dwSpecVersion;
2224 lpNetInfoStruct->dwStatus = NO_ERROR;
2225 lpNetInfoStruct->dwCharacteristics = 0;
2226 lpNetInfoStruct->dwHandle = 0;
2227 lpNetInfoStruct->wNetType =
2228 HIWORD(providerTable->table[providerIndex].dwNetType);
2229 lpNetInfoStruct->dwPrinters = -1;
2230 lpNetInfoStruct->dwDrives = -1;
2231 ret = WN_SUCCESS;
2233 else
2234 ret = WN_BAD_PROVIDER;
2236 else
2237 ret = WN_NO_NETWORK;
2239 if (ret)
2240 SetLastError(ret);
2241 TRACE("Returning %d\n", ret);
2242 return ret;
2245 /*****************************************************************
2246 * WNetGetProviderNameA [MPR.@]
2248 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2249 LPSTR lpProvider, LPDWORD lpBufferSize )
2251 DWORD ret;
2253 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2254 lpBufferSize);
2256 if (!lpProvider)
2257 ret = WN_BAD_POINTER;
2258 else if (!lpBufferSize)
2259 ret = WN_BAD_POINTER;
2260 else
2262 if (providerTable)
2264 DWORD i;
2266 ret = WN_NO_NETWORK;
2267 for (i = 0; i < providerTable->numProviders &&
2268 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2269 i++)
2271 if (i < providerTable->numProviders)
2273 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2274 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2276 if (*lpBufferSize < sizeNeeded)
2278 *lpBufferSize = sizeNeeded;
2279 ret = WN_MORE_DATA;
2281 else
2283 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2284 -1, lpProvider, *lpBufferSize, NULL, NULL);
2285 ret = WN_SUCCESS;
2286 /* FIXME: is *lpBufferSize set to the number of characters
2287 * copied? */
2291 else
2292 ret = WN_NO_NETWORK;
2294 if (ret)
2295 SetLastError(ret);
2296 TRACE("Returning %d\n", ret);
2297 return ret;
2300 /*****************************************************************
2301 * WNetGetProviderNameW [MPR.@]
2303 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2304 LPWSTR lpProvider, LPDWORD lpBufferSize )
2306 DWORD ret;
2308 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2309 lpBufferSize);
2311 if (!lpProvider)
2312 ret = WN_BAD_POINTER;
2313 else if (!lpBufferSize)
2314 ret = WN_BAD_POINTER;
2315 else
2317 if (providerTable)
2319 DWORD i;
2321 ret = WN_NO_NETWORK;
2322 for (i = 0; i < providerTable->numProviders &&
2323 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2324 i++)
2326 if (i < providerTable->numProviders)
2328 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2330 if (*lpBufferSize < sizeNeeded)
2332 *lpBufferSize = sizeNeeded;
2333 ret = WN_MORE_DATA;
2335 else
2337 strcpyW(lpProvider, providerTable->table[i].name);
2338 ret = WN_SUCCESS;
2339 /* FIXME: is *lpBufferSize set to the number of characters
2340 * copied? */
2344 else
2345 ret = WN_NO_NETWORK;
2347 if (ret)
2348 SetLastError(ret);
2349 TRACE("Returning %d\n", ret);
2350 return ret;