mpr: Enumerate connections capability before looking for functions entry points.
[wine.git] / dlls / mpr / wnet.c
blobcbbc1bdfb04ada43c330e0f82264e8cf6f19339b
1 /*
2 * MPR WNet functions
4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
7 * Copyright 2016 Pierre Schweitzer
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnls.h"
28 #include "winioctl.h"
29 #include "winnetwk.h"
30 #include "npapi.h"
31 #include "winreg.h"
32 #include "winuser.h"
33 #define WINE_MOUNTMGR_EXTENSIONS
34 #include "ddk/mountmgr.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "mprres.h"
38 #include "wnetpriv.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(mpr);
42 /* Data structures representing network service providers. Assumes only one
43 * thread creates them, and that they are constant for the life of the process
44 * (and therefore doesn't synchronize access).
45 * FIXME: only basic provider data and enumeration-related data are implemented
46 * so far, need to implement the rest too.
48 typedef struct _WNetProvider
50 HMODULE hLib;
51 PWSTR name;
52 PF_NPGetCaps getCaps;
53 DWORD dwSpecVersion;
54 DWORD dwNetType;
55 DWORD dwEnumScopes;
56 PF_NPOpenEnum openEnum;
57 PF_NPEnumResource enumResource;
58 PF_NPCloseEnum closeEnum;
59 PF_NPGetResourceInformation getResourceInformation;
60 PF_NPAddConnection addConnection;
61 PF_NPAddConnection3 addConnection3;
62 PF_NPCancelConnection cancelConnection;
63 } WNetProvider, *PWNetProvider;
65 typedef struct _WNetProviderTable
67 LPWSTR entireNetwork;
68 DWORD numAllocated;
69 DWORD numProviders;
70 WNetProvider table[1];
71 } WNetProviderTable, *PWNetProviderTable;
73 #define WNET_ENUMERATOR_TYPE_NULL 0
74 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
75 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
76 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
77 #define WNET_ENUMERATOR_TYPE_CONNECTED 4
79 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
80 * the enumeration; it represents one of the following types:
81 * - a 'null' enumeration, one that contains no members
82 * - a global enumeration, one that's executed across all providers
83 * - a provider-specific enumeration, one that's only executed by a single
84 * provider
85 * - a context enumeration. I know this contradicts what I just said about
86 * there being no correspondence between the scope and the type, but it's
87 * necessary for the special case that a "Entire Network" entry needs to
88 * be enumerated in an enumeration of the context scope. Thus an enumeration
89 * of the context scope results in a context type enumerator, which morphs
90 * into a global enumeration (so the enumeration continues across all
91 * providers).
93 typedef struct _WNetEnumerator
95 DWORD enumType;
96 DWORD providerIndex;
97 HANDLE handle;
98 BOOL providerDone;
99 DWORD dwScope;
100 DWORD dwType;
101 DWORD dwUsage;
102 union
104 NETRESOURCEW* net;
105 HANDLE* handles;
106 } specific;
107 } WNetEnumerator, *PWNetEnumerator;
109 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
111 /* Returns an index (into the global WNetProviderTable) of the provider with
112 * the given name, or BAD_PROVIDER_INDEX if not found.
114 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
116 static PWNetProviderTable providerTable;
119 * Global provider table functions
122 static void _tryLoadProvider(PCWSTR provider)
124 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
125 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
126 'S','e','r','v','i','c','e','s','\\',0 };
127 static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
128 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
129 WCHAR serviceName[MAX_PATH];
130 HKEY hKey;
132 TRACE("%s\n", debugstr_w(provider));
133 snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt,
134 servicePrefix, provider);
135 serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0';
136 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
137 ERROR_SUCCESS)
139 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
140 'P','a','t','h',0 };
141 WCHAR providerPath[MAX_PATH];
142 DWORD type, size = sizeof(providerPath);
144 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
145 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && (type == REG_SZ || type == REG_EXPAND_SZ))
147 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
148 PWSTR name = NULL;
150 if (type == REG_EXPAND_SZ)
152 WCHAR path[MAX_PATH];
153 if (ExpandEnvironmentStringsW(providerPath, path, MAX_PATH)) lstrcpyW( providerPath, path );
156 size = 0;
157 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
158 if (size)
160 name = HeapAlloc(GetProcessHeap(), 0, size);
161 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
162 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
164 HeapFree(GetProcessHeap(), 0, name);
165 name = NULL;
168 if (name)
170 HMODULE hLib = LoadLibraryW(providerPath);
172 if (hLib)
174 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
176 PF_NPGetCaps getCaps = MPR_GETPROC(NPGetCaps);
178 TRACE("loaded lib %p\n", hLib);
179 if (getCaps)
181 DWORD connectCap;
182 PWNetProvider provider =
183 &providerTable->table[providerTable->numProviders];
185 provider->hLib = hLib;
186 provider->name = name;
187 TRACE("name is %s\n", debugstr_w(name));
188 provider->getCaps = getCaps;
189 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
190 provider->dwNetType = getCaps(WNNC_NET_TYPE);
191 TRACE("net type is 0x%08x\n", provider->dwNetType);
192 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
193 if (provider->dwEnumScopes)
195 TRACE("supports enumeration\n");
196 provider->openEnum = MPR_GETPROC(NPOpenEnum);
197 TRACE("NPOpenEnum %p\n", provider->openEnum);
198 provider->enumResource = MPR_GETPROC(NPEnumResource);
199 TRACE("NPEnumResource %p\n", provider->enumResource);
200 provider->closeEnum = MPR_GETPROC(NPCloseEnum);
201 TRACE("NPCloseEnum %p\n", provider->closeEnum);
202 provider->getResourceInformation = MPR_GETPROC(NPGetResourceInformation);
203 TRACE("NPGetResourceInformation %p\n", provider->getResourceInformation);
204 if (!provider->openEnum ||
205 !provider->enumResource ||
206 !provider->closeEnum)
208 provider->openEnum = NULL;
209 provider->enumResource = NULL;
210 provider->closeEnum = NULL;
211 provider->dwEnumScopes = 0;
212 WARN("Couldn't load enumeration functions\n");
215 connectCap = getCaps(WNNC_CONNECTION);
216 if (connectCap & WNNC_CON_ADDCONNECTION)
217 provider->addConnection = MPR_GETPROC(NPAddConnection);
218 if (connectCap & WNNC_CON_ADDCONNECTION3)
219 provider->addConnection3 = MPR_GETPROC(NPAddConnection3);
220 if (connectCap & WNNC_CON_CANCELCONNECTION)
221 provider->cancelConnection = MPR_GETPROC(NPCancelConnection);
222 TRACE("NPAddConnection %p\n", provider->addConnection);
223 TRACE("NPAddConnection3 %p\n", provider->addConnection3);
224 TRACE("NPCancelConnection %p\n", provider->cancelConnection);
225 providerTable->numProviders++;
227 else
229 WARN("Provider %s didn't export NPGetCaps\n",
230 debugstr_w(provider));
231 HeapFree(GetProcessHeap(), 0, name);
232 FreeLibrary(hLib);
235 #undef MPR_GETPROC
237 else
239 WARN("Couldn't load library %s for provider %s\n",
240 debugstr_w(providerPath), debugstr_w(provider));
241 HeapFree(GetProcessHeap(), 0, name);
244 else
246 WARN("Couldn't get provider name for provider %s\n",
247 debugstr_w(provider));
250 else
251 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
252 RegCloseKey(hKey);
254 else
255 WARN("Couldn't open service key for provider %s\n",
256 debugstr_w(provider));
259 void wnetInit(HINSTANCE hInstDll)
261 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
262 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
263 'C','o','n','t','r','o','l','\\',
264 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
265 'O','r','d','e','r',0 };
266 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
267 'O','r','d','e','r',0 };
268 HKEY hKey;
270 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
271 == ERROR_SUCCESS)
273 DWORD size = 0;
275 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
276 if (size)
278 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
280 if (providers)
282 DWORD type;
284 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
285 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
287 PWSTR ptr;
288 DWORD numToAllocate;
290 TRACE("provider order is %s\n", debugstr_w(providers));
291 /* first count commas as a heuristic for how many to
292 * allocate space for */
293 for (ptr = providers, numToAllocate = 1; ptr; )
295 ptr = strchrW(ptr, ',');
296 if (ptr) {
297 numToAllocate++;
298 ptr++;
301 providerTable =
302 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
303 sizeof(WNetProviderTable)
304 + (numToAllocate - 1) * sizeof(WNetProvider));
305 if (providerTable)
307 PWSTR ptrPrev;
308 int entireNetworkLen;
309 LPCWSTR stringresource;
311 entireNetworkLen = LoadStringW(hInstDll,
312 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
313 providerTable->entireNetwork = HeapAlloc(
314 GetProcessHeap(), 0, (entireNetworkLen + 1) *
315 sizeof(WCHAR));
316 if (providerTable->entireNetwork)
318 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
319 providerTable->entireNetwork[entireNetworkLen] = 0;
321 providerTable->numAllocated = numToAllocate;
322 for (ptr = providers; ptr; )
324 ptrPrev = ptr;
325 ptr = strchrW(ptr, ',');
326 if (ptr)
327 *ptr++ = '\0';
328 _tryLoadProvider(ptrPrev);
332 HeapFree(GetProcessHeap(), 0, providers);
335 RegCloseKey(hKey);
339 void wnetFree(void)
341 if (providerTable)
343 DWORD i;
345 for (i = 0; i < providerTable->numProviders; i++)
347 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
348 FreeModule(providerTable->table[i].hLib);
350 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
351 HeapFree(GetProcessHeap(), 0, providerTable);
352 providerTable = NULL;
356 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
358 DWORD ret = BAD_PROVIDER_INDEX;
360 if (providerTable && providerTable->numProviders)
362 DWORD i;
364 for (i = 0; i < providerTable->numProviders &&
365 ret == BAD_PROVIDER_INDEX; i++)
366 if (!strcmpW(lpProvider, providerTable->table[i].name))
367 ret = i;
369 return ret;
373 * Browsing Functions
376 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
378 LPNETRESOURCEW ret;
380 if (lpNet)
382 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
383 if (ret)
385 size_t len;
387 *ret = *lpNet;
388 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
389 if (lpNet->lpRemoteName)
391 len = strlenW(lpNet->lpRemoteName) + 1;
392 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
393 if (ret->lpRemoteName)
394 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
398 else
399 ret = NULL;
400 return ret;
403 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
405 if (lpNet)
407 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
408 HeapFree(GetProcessHeap(), 0, lpNet);
412 static PWNetEnumerator _createNullEnumerator(void)
414 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
415 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
417 if (ret)
418 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
419 return ret;
422 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
423 DWORD dwUsage, LPNETRESOURCEW lpNet)
425 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
426 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
428 if (ret)
430 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
431 ret->dwScope = dwScope;
432 ret->dwType = dwType;
433 ret->dwUsage = dwUsage;
434 ret->specific.net = _copyNetResourceForEnumW(lpNet);
436 return ret;
439 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
440 DWORD dwUsage, DWORD index, HANDLE handle)
442 PWNetEnumerator ret;
444 if (!providerTable || index >= providerTable->numProviders)
445 ret = NULL;
446 else
448 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
449 if (ret)
451 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
452 ret->providerIndex = index;
453 ret->dwScope = dwScope;
454 ret->dwType = dwType;
455 ret->dwUsage = dwUsage;
456 ret->handle = handle;
459 return ret;
462 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
463 DWORD dwUsage)
465 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
466 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
468 if (ret)
470 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
471 ret->dwScope = dwScope;
472 ret->dwType = dwType;
473 ret->dwUsage = dwUsage;
475 return ret;
478 static PWNetEnumerator _createConnectedEnumerator(DWORD dwScope, DWORD dwType,
479 DWORD dwUsage)
481 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
482 if (ret)
484 ret->enumType = WNET_ENUMERATOR_TYPE_CONNECTED;
485 ret->dwScope = dwScope;
486 ret->dwType = dwType;
487 ret->dwUsage = dwUsage;
488 ret->specific.handles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HANDLE) * providerTable->numProviders);
489 if (!ret->specific.handles)
491 HeapFree(GetProcessHeap(), 0, ret);
492 ret = NULL;
495 return ret;
498 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
499 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
500 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
501 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
502 * if not all members of the array could be thunked, and something else on
503 * failure.
505 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
506 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
508 DWORD i, numToThunk, totalBytes, ret;
509 LPSTR strNext;
511 if (!lpNetArrayIn)
512 return WN_BAD_POINTER;
513 if (!lpcCount)
514 return WN_BAD_POINTER;
515 if (*lpcCount == -1)
516 return WN_BAD_VALUE;
517 if (!lpBuffer)
518 return WN_BAD_POINTER;
519 if (!lpBufferSize)
520 return WN_BAD_POINTER;
522 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
524 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
526 totalBytes += sizeof(NETRESOURCEA);
527 if (lpNet->lpLocalName)
528 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
529 -1, NULL, 0, NULL, NULL);
530 if (lpNet->lpRemoteName)
531 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
532 -1, NULL, 0, NULL, NULL);
533 if (lpNet->lpComment)
534 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
535 -1, NULL, 0, NULL, NULL);
536 if (lpNet->lpProvider)
537 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
538 -1, NULL, 0, NULL, NULL);
539 if (totalBytes < *lpBufferSize)
540 numToThunk = i + 1;
542 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
543 for (i = 0; i < numToThunk; i++)
545 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
546 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
548 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
549 /* lie about string lengths, we already verified how many
550 * we have space for above
552 if (lpNetIn->lpLocalName)
554 lpNetOut->lpLocalName = strNext;
555 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
556 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
558 if (lpNetIn->lpRemoteName)
560 lpNetOut->lpRemoteName = strNext;
561 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
562 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
564 if (lpNetIn->lpComment)
566 lpNetOut->lpComment = strNext;
567 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
568 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
570 if (lpNetIn->lpProvider)
572 lpNetOut->lpProvider = strNext;
573 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
574 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
577 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
578 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
579 *lpcCount, ret);
580 return ret;
583 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
584 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
585 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
586 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
587 * if not all members of the array could be thunked, and something else on
588 * failure.
590 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
591 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
593 DWORD i, numToThunk, totalBytes, ret;
594 LPWSTR strNext;
596 if (!lpNetArrayIn)
597 return WN_BAD_POINTER;
598 if (!lpcCount)
599 return WN_BAD_POINTER;
600 if (*lpcCount == -1)
601 return WN_BAD_VALUE;
602 if (!lpBuffer)
603 return WN_BAD_POINTER;
604 if (!lpBufferSize)
605 return WN_BAD_POINTER;
607 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
609 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
611 totalBytes += sizeof(NETRESOURCEW);
612 if (lpNet->lpLocalName)
613 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
614 -1, NULL, 0) * sizeof(WCHAR);
615 if (lpNet->lpRemoteName)
616 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
617 -1, NULL, 0) * sizeof(WCHAR);
618 if (lpNet->lpComment)
619 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
620 -1, NULL, 0) * sizeof(WCHAR);
621 if (lpNet->lpProvider)
622 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
623 -1, NULL, 0) * sizeof(WCHAR);
624 if (totalBytes < *lpBufferSize)
625 numToThunk = i + 1;
627 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
628 for (i = 0; i < numToThunk; i++)
630 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
631 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
633 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
634 /* lie about string lengths, we already verified how many
635 * we have space for above
637 if (lpNetIn->lpLocalName)
639 lpNetOut->lpLocalName = strNext;
640 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
641 -1, lpNetOut->lpLocalName, *lpBufferSize);
643 if (lpNetIn->lpRemoteName)
645 lpNetOut->lpRemoteName = strNext;
646 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
647 -1, lpNetOut->lpRemoteName, *lpBufferSize);
649 if (lpNetIn->lpComment)
651 lpNetOut->lpComment = strNext;
652 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
653 -1, lpNetOut->lpComment, *lpBufferSize);
655 if (lpNetIn->lpProvider)
657 lpNetOut->lpProvider = strNext;
658 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
659 -1, lpNetOut->lpProvider, *lpBufferSize);
662 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
663 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
664 *lpcCount, ret);
665 return ret;
668 /*********************************************************************
669 * WNetOpenEnumA [MPR.@]
671 * See comments for WNetOpenEnumW.
673 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
674 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
676 DWORD ret;
678 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
679 dwScope, dwType, dwUsage, lpNet, lphEnum );
681 if (!lphEnum)
682 ret = WN_BAD_POINTER;
683 else if (!providerTable || providerTable->numProviders == 0)
685 *lphEnum = NULL;
686 ret = WN_NO_NETWORK;
688 else
690 if (lpNet)
692 LPNETRESOURCEW lpNetWide = NULL;
693 BYTE buf[1024];
694 DWORD size = sizeof(buf), count = 1;
695 BOOL allocated = FALSE;
697 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
698 if (ret == WN_MORE_DATA)
700 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
701 size);
702 if (lpNetWide)
704 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
705 &size);
706 allocated = TRUE;
708 else
709 ret = WN_OUT_OF_MEMORY;
711 else if (ret == WN_SUCCESS)
712 lpNetWide = (LPNETRESOURCEW)buf;
713 if (ret == WN_SUCCESS)
714 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
715 lphEnum);
716 if (allocated)
717 HeapFree(GetProcessHeap(), 0, lpNetWide);
719 else
720 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
722 if (ret)
723 SetLastError(ret);
724 TRACE("Returning %d\n", ret);
725 return ret;
728 /*********************************************************************
729 * WNetOpenEnumW [MPR.@]
731 * Network enumeration has way too many parameters, so I'm not positive I got
732 * them right. What I've got so far:
734 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
735 * all the network providers should be enumerated.
737 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
738 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
739 * lpProvider is set, all the network providers should be enumerated.
740 * (This means the enumeration is a list of network providers, not that the
741 * enumeration is passed on to the providers.)
743 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
744 * resource matches the "Entire Network" resource (no remote name, no
745 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
746 * enumeration is done on every network provider.
748 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
749 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
750 * only to the given network provider.
752 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
753 * no lpProvider is set, enumeration will be tried on every network provider,
754 * in the order in which they're loaded.
756 * - The LPNETRESOURCE should be disregarded for scopes besides
757 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
758 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
760 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
761 * resource in the enumerated list, as well as any machines in your
762 * workgroup. The machines in your workgroup come from doing a
763 * RESOURCE_CONTEXT enumeration of every Network Provider.
765 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
766 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
768 DWORD ret;
770 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
771 dwScope, dwType, dwUsage, lpNet, lphEnum );
773 if (!lphEnum)
774 ret = WN_BAD_POINTER;
775 else if (!providerTable || providerTable->numProviders == 0)
777 *lphEnum = NULL;
778 ret = WN_NO_NETWORK;
780 else
782 switch (dwScope)
784 case RESOURCE_GLOBALNET:
785 if (lpNet)
787 if (lpNet->lpProvider)
789 DWORD index = _findProviderIndexW(lpNet->lpProvider);
791 if (index != BAD_PROVIDER_INDEX)
793 if (providerTable->table[index].openEnum &&
794 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
796 HANDLE handle;
797 PWSTR RemoteName = lpNet->lpRemoteName;
799 if ((lpNet->dwUsage & RESOURCEUSAGE_CONTAINER) &&
800 RemoteName && !strcmpW(RemoteName, lpNet->lpProvider))
801 lpNet->lpRemoteName = NULL;
803 ret = providerTable->table[index].openEnum(
804 dwScope, dwType, dwUsage, lpNet, &handle);
805 if (ret == WN_SUCCESS)
807 *lphEnum = _createProviderEnumerator(
808 dwScope, dwType, dwUsage, index, handle);
809 ret = *lphEnum ? WN_SUCCESS :
810 WN_OUT_OF_MEMORY;
813 lpNet->lpRemoteName = RemoteName;
815 else
816 ret = WN_NOT_SUPPORTED;
818 else
819 ret = WN_BAD_PROVIDER;
821 else if (lpNet->lpRemoteName)
823 *lphEnum = _createGlobalEnumeratorW(dwScope,
824 dwType, dwUsage, lpNet);
825 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
827 else
829 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
830 providerTable->entireNetwork))
832 /* comment matches the "Entire Network", enumerate
833 * global scope of every provider
835 *lphEnum = _createGlobalEnumeratorW(dwScope,
836 dwType, dwUsage, lpNet);
838 else
840 /* this is the same as not having passed lpNet */
841 *lphEnum = _createGlobalEnumeratorW(dwScope,
842 dwType, dwUsage, NULL);
844 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
847 else
849 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
850 dwUsage, lpNet);
851 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
853 break;
854 case RESOURCE_CONTEXT:
855 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
856 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
857 break;
858 case RESOURCE_CONNECTED:
859 *lphEnum = _createConnectedEnumerator(dwScope, dwType, dwUsage);
860 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
861 break;
862 case RESOURCE_REMEMBERED:
863 *lphEnum = _createNullEnumerator();
864 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
865 break;
866 default:
867 WARN("unknown scope 0x%08x\n", dwScope);
868 ret = WN_BAD_VALUE;
871 if (ret)
872 SetLastError(ret);
873 TRACE("Returning %d\n", ret);
874 return ret;
877 /*********************************************************************
878 * WNetEnumResourceA [MPR.@]
880 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
881 LPVOID lpBuffer, LPDWORD lpBufferSize )
883 DWORD ret;
885 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
887 if (!hEnum)
888 ret = WN_BAD_POINTER;
889 else if (!lpcCount)
890 ret = WN_BAD_POINTER;
891 else if (!lpBuffer)
892 ret = WN_BAD_POINTER;
893 else if (!lpBufferSize)
894 ret = WN_BAD_POINTER;
895 else if (*lpBufferSize < sizeof(NETRESOURCEA))
897 *lpBufferSize = sizeof(NETRESOURCEA);
898 ret = WN_MORE_DATA;
900 else
902 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
903 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
905 if (localBuffer)
907 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
908 &localSize);
909 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
911 /* FIXME: this isn't necessarily going to work in the case of
912 * WN_MORE_DATA, because our enumerator may have moved on to
913 * the next provider. MSDN states that a large (16KB) buffer
914 * size is the appropriate usage of this function, so
915 * hopefully it won't be an issue.
917 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
918 lpBuffer, lpBufferSize);
919 *lpcCount = localCount;
921 HeapFree(GetProcessHeap(), 0, localBuffer);
923 else
924 ret = WN_OUT_OF_MEMORY;
926 if (ret)
927 SetLastError(ret);
928 TRACE("Returning %d\n", ret);
929 return ret;
932 static DWORD _countProviderBytesW(PWNetProvider provider)
934 DWORD ret;
936 if (provider)
938 ret = sizeof(NETRESOURCEW);
939 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
941 else
942 ret = 0;
943 return ret;
946 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
947 LPVOID lpBuffer, const DWORD *lpBufferSize)
949 DWORD ret;
951 if (!enumerator)
952 return WN_BAD_POINTER;
953 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
954 return WN_BAD_VALUE;
955 if (!lpcCount)
956 return WN_BAD_POINTER;
957 if (!lpBuffer)
958 return WN_BAD_POINTER;
959 if (!lpBufferSize)
960 return WN_BAD_POINTER;
961 if (*lpBufferSize < sizeof(NETRESOURCEA))
962 return WN_MORE_DATA;
964 if (!providerTable || enumerator->providerIndex >=
965 providerTable->numProviders)
966 ret = WN_NO_MORE_ENTRIES;
967 else
969 DWORD bytes = 0, count = 0, countLimit, i;
970 LPNETRESOURCEW resource;
971 LPWSTR strNext;
973 countLimit = *lpcCount == -1 ?
974 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
975 while (count < countLimit && bytes < *lpBufferSize)
977 DWORD bytesNext = _countProviderBytesW(
978 &providerTable->table[count + enumerator->providerIndex]);
980 if (bytes + bytesNext < *lpBufferSize)
982 bytes += bytesNext;
983 count++;
986 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
987 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
989 resource->dwScope = RESOURCE_GLOBALNET;
990 resource->dwType = RESOURCETYPE_ANY;
991 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
992 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
993 RESOURCEUSAGE_RESERVED;
994 resource->lpLocalName = NULL;
995 resource->lpRemoteName = strNext;
996 strcpyW(resource->lpRemoteName,
997 providerTable->table[i + enumerator->providerIndex].name);
998 strNext += strlenW(resource->lpRemoteName) + 1;
999 resource->lpComment = NULL;
1000 resource->lpProvider = strNext;
1001 strcpyW(resource->lpProvider,
1002 providerTable->table[i + enumerator->providerIndex].name);
1003 strNext += strlenW(resource->lpProvider) + 1;
1005 enumerator->providerIndex += count;
1006 *lpcCount = count;
1007 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
1009 TRACE("Returning %d\n", ret);
1010 return ret;
1013 /* Advances the enumerator (assumed to be a global enumerator) to the next
1014 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1015 * not open a handle with the next provider.
1016 * If the existing handle is NULL, may leave the enumerator unchanged, since
1017 * the current provider may support the desired scope.
1018 * If the existing handle is not NULL, closes it before moving on.
1019 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1020 * provider, and another error on failure.
1022 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
1024 if (!enumerator)
1025 return WN_BAD_POINTER;
1026 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1027 return WN_BAD_VALUE;
1028 if (!providerTable || enumerator->providerIndex >=
1029 providerTable->numProviders)
1030 return WN_NO_MORE_ENTRIES;
1032 if (enumerator->providerDone)
1034 DWORD dwEnum = 0;
1035 enumerator->providerDone = FALSE;
1036 if (enumerator->handle)
1038 providerTable->table[enumerator->providerIndex].closeEnum(
1039 enumerator->handle);
1040 enumerator->handle = NULL;
1041 enumerator->providerIndex++;
1043 if (enumerator->dwScope == RESOURCE_CONNECTED)
1044 dwEnum = WNNC_ENUM_LOCAL;
1045 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
1046 dwEnum = WNNC_ENUM_GLOBAL;
1047 else if (enumerator->dwScope == RESOURCE_CONTEXT)
1048 dwEnum = WNNC_ENUM_CONTEXT;
1049 for (; enumerator->providerIndex < providerTable->numProviders &&
1050 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
1051 & dwEnum); enumerator->providerIndex++)
1054 return enumerator->providerIndex < providerTable->numProviders ?
1055 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1058 /* "Passes through" call to the next provider that supports the enumeration
1059 * type.
1060 * FIXME: if one call to a provider's enumerator succeeds while there's still
1061 * space in lpBuffer, I don't call to the next provider. The caller may not
1062 * expect that it should call EnumResourceW again with a return value of
1063 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1064 * may have to be moved around a bit, ick.
1066 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1067 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1069 DWORD ret;
1071 if (!enumerator)
1072 return WN_BAD_POINTER;
1073 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1074 return WN_BAD_VALUE;
1075 if (!lpcCount)
1076 return WN_BAD_POINTER;
1077 if (!lpBuffer)
1078 return WN_BAD_POINTER;
1079 if (!lpBufferSize)
1080 return WN_BAD_POINTER;
1081 if (*lpBufferSize < sizeof(NETRESOURCEW))
1082 return WN_MORE_DATA;
1084 ret = _globalEnumeratorAdvance(enumerator);
1085 if (ret == WN_SUCCESS)
1087 ret = providerTable->table[enumerator->providerIndex].
1088 openEnum(enumerator->dwScope, enumerator->dwType,
1089 enumerator->dwUsage, enumerator->specific.net,
1090 &enumerator->handle);
1091 if (ret == WN_SUCCESS)
1093 ret = providerTable->table[enumerator->providerIndex].
1094 enumResource(enumerator->handle, lpcCount, lpBuffer,
1095 lpBufferSize);
1096 if (ret != WN_MORE_DATA)
1097 enumerator->providerDone = TRUE;
1100 TRACE("Returning %d\n", ret);
1101 return ret;
1104 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1105 LPVOID lpBuffer, LPDWORD lpBufferSize)
1107 DWORD ret;
1109 if (!enumerator)
1110 return WN_BAD_POINTER;
1111 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1112 return WN_BAD_VALUE;
1113 if (!lpcCount)
1114 return WN_BAD_POINTER;
1115 if (!lpBuffer)
1116 return WN_BAD_POINTER;
1117 if (!lpBufferSize)
1118 return WN_BAD_POINTER;
1119 if (*lpBufferSize < sizeof(NETRESOURCEW))
1120 return WN_MORE_DATA;
1121 if (!providerTable)
1122 return WN_NO_NETWORK;
1124 switch (enumerator->dwScope)
1126 case RESOURCE_GLOBALNET:
1127 if (enumerator->specific.net)
1128 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1129 lpBuffer, lpBufferSize);
1130 else
1131 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1132 lpBufferSize);
1133 break;
1134 case RESOURCE_CONTEXT:
1135 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1136 lpBufferSize);
1137 break;
1138 default:
1139 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1140 ret = WN_NO_MORE_ENTRIES;
1142 TRACE("Returning %d\n", ret);
1143 return ret;
1146 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1147 LPVOID lpBuffer, LPDWORD lpBufferSize)
1149 if (!enumerator)
1150 return WN_BAD_POINTER;
1151 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1152 return WN_BAD_VALUE;
1153 if (!enumerator->handle)
1154 return WN_BAD_VALUE;
1155 if (!lpcCount)
1156 return WN_BAD_POINTER;
1157 if (!lpBuffer)
1158 return WN_BAD_POINTER;
1159 if (!lpBufferSize)
1160 return WN_BAD_POINTER;
1161 if (!providerTable)
1162 return WN_NO_NETWORK;
1163 if (enumerator->providerIndex >= providerTable->numProviders)
1164 return WN_NO_MORE_ENTRIES;
1165 if (!providerTable->table[enumerator->providerIndex].enumResource)
1166 return WN_BAD_VALUE;
1167 return providerTable->table[enumerator->providerIndex].enumResource(
1168 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1171 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1172 LPVOID lpBuffer, LPDWORD lpBufferSize)
1174 DWORD ret;
1175 size_t cchEntireNetworkLen, bytesNeeded;
1177 if (!enumerator)
1178 return WN_BAD_POINTER;
1179 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1180 return WN_BAD_VALUE;
1181 if (!lpcCount)
1182 return WN_BAD_POINTER;
1183 if (!lpBuffer)
1184 return WN_BAD_POINTER;
1185 if (!lpBufferSize)
1186 return WN_BAD_POINTER;
1187 if (!providerTable)
1188 return WN_NO_NETWORK;
1190 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1191 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1192 if (*lpBufferSize < bytesNeeded)
1194 *lpBufferSize = bytesNeeded;
1195 ret = WN_MORE_DATA;
1197 else
1199 LPNETRESOURCEW lpNet = lpBuffer;
1201 lpNet->dwScope = RESOURCE_GLOBALNET;
1202 lpNet->dwType = enumerator->dwType;
1203 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1204 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1205 lpNet->lpLocalName = NULL;
1206 lpNet->lpRemoteName = NULL;
1207 lpNet->lpProvider = NULL;
1208 /* odd, but correct: put comment at end of buffer, so it won't get
1209 * overwritten by subsequent calls to a provider's enumResource
1211 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1212 (cchEntireNetworkLen * sizeof(WCHAR)));
1213 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1214 ret = WN_SUCCESS;
1216 if (ret == WN_SUCCESS)
1218 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1220 /* "Entire Network" entry enumerated--morph this into a global
1221 * enumerator. enumerator->lpNet continues to be NULL, since it has
1222 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1224 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1225 ret = _enumerateGlobalW(enumerator, lpcCount,
1226 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1227 if (ret == WN_SUCCESS)
1229 /* reflect the fact that we already enumerated "Entire Network" */
1230 (*lpcCount)++;
1231 *lpBufferSize = bufferSize + bytesNeeded;
1233 else
1235 /* the provider enumeration failed, but we already succeeded in
1236 * enumerating "Entire Network"--leave type as global to allow a
1237 * retry, but indicate success with a count of one.
1239 ret = WN_SUCCESS;
1240 *lpcCount = 1;
1241 *lpBufferSize = bytesNeeded;
1244 TRACE("Returning %d\n", ret);
1245 return ret;
1248 static DWORD _copyStringToEnumW(const WCHAR *source, DWORD* left, void** end)
1250 DWORD len;
1251 WCHAR* local = *end;
1253 len = strlenW(source) + 1;
1254 len *= sizeof(WCHAR);
1255 if (*left < len)
1256 return WN_MORE_DATA;
1258 local -= (len / sizeof(WCHAR));
1259 memcpy(local, source, len);
1260 *left -= len;
1261 *end = local;
1263 return WN_SUCCESS;
1266 static DWORD _enumerateConnectedW(PWNetEnumerator enumerator, DWORD* user_count,
1267 void* user_buffer, DWORD* user_size)
1269 DWORD ret, index, count, size, i, left;
1270 void* end;
1271 NETRESOURCEW* curr, * buffer;
1272 HANDLE* handles;
1274 if (!enumerator)
1275 return WN_BAD_POINTER;
1276 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONNECTED)
1277 return WN_BAD_VALUE;
1278 if (!user_count || !user_buffer || !user_size)
1279 return WN_BAD_POINTER;
1280 if (!providerTable)
1281 return WN_NO_NETWORK;
1283 handles = enumerator->specific.handles;
1284 left = *user_size;
1285 size = *user_size;
1286 buffer = HeapAlloc(GetProcessHeap(), 0, *user_size);
1287 if (!buffer)
1288 return WN_NO_NETWORK;
1290 curr = user_buffer;
1291 end = (char *)user_buffer + size;
1292 count = *user_count;
1294 ret = WN_NO_MORE_ENTRIES;
1295 for (index = 0; index < providerTable->numProviders; index++)
1297 if (providerTable->table[index].dwEnumScopes)
1299 if (handles[index] == 0)
1301 ret = providerTable->table[index].openEnum(enumerator->dwScope,
1302 enumerator->dwType,
1303 enumerator->dwUsage,
1304 NULL, &handles[index]);
1305 if (ret != WN_SUCCESS)
1306 continue;
1309 ret = providerTable->table[index].enumResource(handles[index],
1310 &count, buffer,
1311 &size);
1312 if (ret == WN_MORE_DATA)
1313 break;
1315 if (ret == WN_SUCCESS)
1317 for (i = 0; i < count; ++i)
1319 if (left < sizeof(NETRESOURCEW))
1321 ret = WN_MORE_DATA;
1322 break;
1325 memcpy(curr, &buffer[i], sizeof(NETRESOURCEW));
1326 left -= sizeof(NETRESOURCEW);
1328 ret = _copyStringToEnumW(buffer[i].lpLocalName, &left, &end);
1329 if (ret == WN_MORE_DATA)
1330 break;
1331 curr->lpLocalName = end;
1333 ret = _copyStringToEnumW(buffer[i].lpRemoteName, &left, &end);
1334 if (ret == WN_MORE_DATA)
1335 break;
1336 curr->lpRemoteName = end;
1338 ret = _copyStringToEnumW(buffer[i].lpProvider, &left, &end);
1339 if (ret == WN_MORE_DATA)
1340 break;
1341 curr->lpProvider = end;
1343 ++curr;
1346 count = *user_count - count;
1347 size = left;
1350 if (ret != WN_SUCCESS || count == 0)
1351 break;
1355 if (count == 0)
1356 ret = WN_NO_MORE_ENTRIES;
1358 *user_count = *user_count - count;
1359 if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
1360 ret = WN_SUCCESS;
1362 HeapFree(GetProcessHeap(), 0, buffer);
1364 TRACE("Returning %d\n", ret);
1365 return ret;
1368 /*********************************************************************
1369 * WNetEnumResourceW [MPR.@]
1371 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1372 LPVOID lpBuffer, LPDWORD lpBufferSize )
1374 DWORD ret;
1376 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1378 if (!hEnum)
1379 ret = WN_BAD_POINTER;
1380 else if (!lpcCount)
1381 ret = WN_BAD_POINTER;
1382 else if (!lpBuffer)
1383 ret = WN_BAD_POINTER;
1384 else if (!lpBufferSize)
1385 ret = WN_BAD_POINTER;
1386 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1388 *lpBufferSize = sizeof(NETRESOURCEW);
1389 ret = WN_MORE_DATA;
1391 else
1393 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1395 switch (enumerator->enumType)
1397 case WNET_ENUMERATOR_TYPE_NULL:
1398 ret = WN_NO_MORE_ENTRIES;
1399 break;
1400 case WNET_ENUMERATOR_TYPE_GLOBAL:
1401 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1402 lpBufferSize);
1403 break;
1404 case WNET_ENUMERATOR_TYPE_PROVIDER:
1405 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1406 lpBufferSize);
1407 break;
1408 case WNET_ENUMERATOR_TYPE_CONTEXT:
1409 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1410 lpBufferSize);
1411 break;
1412 case WNET_ENUMERATOR_TYPE_CONNECTED:
1413 ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer,
1414 lpBufferSize);
1415 break;
1416 default:
1417 WARN("bogus enumerator type!\n");
1418 ret = WN_NO_NETWORK;
1421 if (ret)
1422 SetLastError(ret);
1423 TRACE("Returning %d\n", ret);
1424 return ret;
1427 /*********************************************************************
1428 * WNetCloseEnum [MPR.@]
1430 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1432 DWORD ret, index;
1433 HANDLE *handles;
1435 TRACE( "(%p)\n", hEnum );
1437 if (hEnum)
1439 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1441 switch (enumerator->enumType)
1443 case WNET_ENUMERATOR_TYPE_NULL:
1444 ret = WN_SUCCESS;
1445 break;
1446 case WNET_ENUMERATOR_TYPE_GLOBAL:
1447 if (enumerator->specific.net)
1448 _freeEnumNetResource(enumerator->specific.net);
1449 if (enumerator->handle)
1450 providerTable->table[enumerator->providerIndex].
1451 closeEnum(enumerator->handle);
1452 ret = WN_SUCCESS;
1453 break;
1454 case WNET_ENUMERATOR_TYPE_PROVIDER:
1455 if (enumerator->handle)
1456 providerTable->table[enumerator->providerIndex].
1457 closeEnum(enumerator->handle);
1458 ret = WN_SUCCESS;
1459 break;
1460 case WNET_ENUMERATOR_TYPE_CONNECTED:
1461 handles = enumerator->specific.handles;
1462 for (index = 0; index < providerTable->numProviders; index++)
1464 if (providerTable->table[index].dwEnumScopes && handles[index])
1465 providerTable->table[index].closeEnum(handles[index]);
1467 HeapFree(GetProcessHeap(), 0, handles);
1468 ret = WN_SUCCESS;
1469 break;
1470 default:
1471 WARN("bogus enumerator type!\n");
1472 ret = WN_BAD_HANDLE;
1474 HeapFree(GetProcessHeap(), 0, hEnum);
1476 else
1477 ret = WN_BAD_HANDLE;
1478 if (ret)
1479 SetLastError(ret);
1480 TRACE("Returning %d\n", ret);
1481 return ret;
1484 /*********************************************************************
1485 * WNetGetResourceInformationA [MPR.@]
1487 * See WNetGetResourceInformationW
1489 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1490 LPVOID lpBuffer, LPDWORD cbBuffer,
1491 LPSTR *lplpSystem )
1493 DWORD ret;
1495 TRACE( "(%p, %p, %p, %p)\n",
1496 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1498 if (!providerTable || providerTable->numProviders == 0)
1499 ret = WN_NO_NETWORK;
1500 else if (lpNetResource)
1502 LPNETRESOURCEW lpNetResourceW = NULL;
1503 DWORD size = 1024, count = 1;
1504 DWORD len;
1506 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1507 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1508 if (ret == WN_MORE_DATA)
1510 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1511 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1512 if (lpNetResourceW)
1513 ret = _thunkNetResourceArrayAToW(lpNetResource,
1514 &count, lpNetResourceW, &size);
1515 else
1516 ret = WN_OUT_OF_MEMORY;
1518 if (ret == WN_SUCCESS)
1520 LPWSTR lpSystemW = NULL;
1521 LPVOID lpBufferW;
1522 size = 1024;
1523 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1524 if (lpBufferW)
1526 ret = WNetGetResourceInformationW(lpNetResourceW,
1527 lpBufferW, &size, &lpSystemW);
1528 if (ret == WN_MORE_DATA)
1530 HeapFree(GetProcessHeap(), 0, lpBufferW);
1531 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1532 if (lpBufferW)
1533 ret = WNetGetResourceInformationW(lpNetResourceW,
1534 lpBufferW, &size, &lpSystemW);
1535 else
1536 ret = WN_OUT_OF_MEMORY;
1538 if (ret == WN_SUCCESS)
1540 ret = _thunkNetResourceArrayWToA(lpBufferW,
1541 &count, lpBuffer, cbBuffer);
1542 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1543 lpNetResourceW = lpBufferW;
1544 size = sizeof(NETRESOURCEA);
1545 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1546 -1, NULL, 0, NULL, NULL);
1547 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1548 -1, NULL, 0, NULL, NULL);
1550 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1551 -1, NULL, 0, NULL, NULL);
1552 if ((len) && ( size + len < *cbBuffer))
1554 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1555 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1556 *lplpSystem, len, NULL, NULL);
1557 ret = WN_SUCCESS;
1559 else
1560 ret = WN_MORE_DATA;
1562 else
1563 ret = WN_OUT_OF_MEMORY;
1564 HeapFree(GetProcessHeap(), 0, lpBufferW);
1566 else
1567 ret = WN_OUT_OF_MEMORY;
1568 HeapFree(GetProcessHeap(), 0, lpSystemW);
1570 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1572 else
1573 ret = WN_NO_NETWORK;
1575 if (ret)
1576 SetLastError(ret);
1577 TRACE("Returning %d\n", ret);
1578 return ret;
1581 /*********************************************************************
1582 * WNetGetResourceInformationW [MPR.@]
1584 * WNetGetResourceInformationW function identifies the network provider
1585 * that owns the resource and gets information about the type of the resource.
1587 * PARAMS:
1588 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1589 * defines a network resource.
1590 * lpBuffer [ O] the pointer to buffer, containing result. It
1591 * contains NETRESOURCEW structure and strings to
1592 * which the members of the NETRESOURCEW structure
1593 * point.
1594 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1595 * in bytes.
1596 * lplpSystem [ O] the pointer to string in the output buffer,
1597 * containing the part of the resource name without
1598 * names of the server and share.
1600 * RETURNS:
1601 * NO_ERROR if the function succeeds. System error code if the function fails.
1604 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1605 LPVOID lpBuffer, LPDWORD cbBuffer,
1606 LPWSTR *lplpSystem )
1608 DWORD ret = WN_NO_NETWORK;
1609 DWORD index;
1611 TRACE( "(%p, %p, %p, %p)\n",
1612 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1614 if (!(lpBuffer))
1615 ret = WN_OUT_OF_MEMORY;
1616 else if (providerTable != NULL)
1618 /* FIXME: For function value of a variable is indifferent, it does
1619 * search of all providers in a network.
1621 for (index = 0; index < providerTable->numProviders; index++)
1623 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1624 WNNC_DLG_GETRESOURCEINFORMATION)
1626 if (providerTable->table[index].getResourceInformation)
1627 ret = providerTable->table[index].getResourceInformation(
1628 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1629 else
1630 ret = WN_NO_NETWORK;
1631 if (ret == WN_SUCCESS)
1632 break;
1636 if (ret)
1637 SetLastError(ret);
1638 return ret;
1641 /*********************************************************************
1642 * WNetGetResourceParentA [MPR.@]
1644 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1645 LPVOID lpBuffer, LPDWORD lpBufferSize )
1647 FIXME( "(%p, %p, %p): stub\n",
1648 lpNetResource, lpBuffer, lpBufferSize );
1650 SetLastError(WN_NO_NETWORK);
1651 return WN_NO_NETWORK;
1654 /*********************************************************************
1655 * WNetGetResourceParentW [MPR.@]
1657 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1658 LPVOID lpBuffer, LPDWORD lpBufferSize )
1660 FIXME( "(%p, %p, %p): stub\n",
1661 lpNetResource, lpBuffer, lpBufferSize );
1663 SetLastError(WN_NO_NETWORK);
1664 return WN_NO_NETWORK;
1670 * Connection Functions
1673 /*********************************************************************
1674 * WNetAddConnectionA [MPR.@]
1676 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1677 LPCSTR lpLocalName )
1679 NETRESOURCEA resourcesA;
1681 memset(&resourcesA, 0, sizeof(resourcesA));
1682 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1683 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1684 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1687 /*********************************************************************
1688 * WNetAddConnectionW [MPR.@]
1690 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1691 LPCWSTR lpLocalName )
1693 NETRESOURCEW resourcesW;
1695 memset(&resourcesW, 0, sizeof(resourcesW));
1696 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1697 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1698 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1701 /*********************************************************************
1702 * WNetAddConnection2A [MPR.@]
1704 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1705 LPCSTR lpPassword, LPCSTR lpUserID,
1706 DWORD dwFlags )
1708 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1709 NULL, 0, NULL);
1712 /*********************************************************************
1713 * WNetAddConnection2W [MPR.@]
1715 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1716 LPCWSTR lpPassword, LPCWSTR lpUserID,
1717 DWORD dwFlags )
1719 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1720 NULL, 0, NULL);
1723 /*********************************************************************
1724 * WNetAddConnection3A [MPR.@]
1726 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1727 LPCSTR lpPassword, LPCSTR lpUserID,
1728 DWORD dwFlags )
1730 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1731 dwFlags, NULL, 0, NULL);
1734 /*********************************************************************
1735 * WNetAddConnection3W [MPR.@]
1737 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1738 LPCWSTR lpPassword, LPCWSTR lpUserID,
1739 DWORD dwFlags )
1741 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1742 dwFlags, NULL, 0, NULL);
1745 struct use_connection_context
1747 HWND hwndOwner;
1748 NETRESOURCEW *resource;
1749 NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */
1750 WCHAR *password;
1751 WCHAR *userid;
1752 DWORD flags;
1753 void *accessname;
1754 DWORD *buffer_size;
1755 DWORD *result;
1756 DWORD (*pre_set_accessname)(struct use_connection_context*, WCHAR *);
1757 void (*set_accessname)(struct use_connection_context*, WCHAR *);
1760 static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1762 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1764 DWORD len;
1766 if (local_name)
1767 len = strlenW(local_name);
1768 else
1769 len = strlenW(ctxt->resource->lpRemoteName);
1771 if (++len > *ctxt->buffer_size)
1773 *ctxt->buffer_size = len;
1774 return ERROR_MORE_DATA;
1777 else
1778 ctxt->accessname = NULL;
1780 return ERROR_SUCCESS;
1783 static void use_connection_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1785 WCHAR *accessname = ctxt->accessname;
1786 if (local_name)
1788 strcpyW(accessname, local_name);
1789 if (ctxt->result)
1790 *ctxt->result = CONNECT_LOCALDRIVE;
1792 else
1793 strcpyW(accessname, ctxt->resource->lpRemoteName);
1796 static DWORD wnet_use_provider( struct use_connection_context *ctxt, NETRESOURCEW * netres, WNetProvider *provider, BOOLEAN redirect )
1798 DWORD caps, ret;
1800 caps = provider->getCaps(WNNC_CONNECTION);
1801 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1802 return ERROR_BAD_PROVIDER;
1804 ret = WN_ACCESS_DENIED;
1807 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1808 ret = provider->addConnection3(ctxt->hwndOwner, netres, ctxt->password, ctxt->userid, ctxt->flags);
1809 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1810 ret = provider->addConnection(netres, ctxt->password, ctxt->userid);
1812 if (ret == WN_ALREADY_CONNECTED && redirect)
1813 netres->lpLocalName[0] -= 1;
1814 } while (redirect && ret == WN_ALREADY_CONNECTED && netres->lpLocalName[0] >= 'C');
1816 if (ret == WN_SUCCESS && ctxt->accessname)
1817 ctxt->set_accessname(ctxt, netres->lpLocalName);
1819 return ret;
1822 static DWORD wnet_use_connection( struct use_connection_context *ctxt )
1824 WNetProvider *provider;
1825 DWORD index, ret = WN_NO_NETWORK;
1826 BOOL redirect = FALSE;
1827 WCHAR letter[3] = {'Z', ':', 0};
1828 NETRESOURCEW netres;
1830 if (!providerTable || providerTable->numProviders == 0)
1831 return WN_NO_NETWORK;
1833 if (!ctxt->resource)
1834 return ERROR_INVALID_PARAMETER;
1835 netres = *ctxt->resource;
1837 if (!netres.lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
1839 if (netres.dwType != RESOURCETYPE_DISK && netres.dwType != RESOURCETYPE_PRINT)
1840 return ERROR_BAD_DEV_TYPE;
1842 if (netres.dwType == RESOURCETYPE_PRINT)
1844 FIXME("Local device selection is not implemented for printers.\n");
1845 return WN_NO_NETWORK;
1848 redirect = TRUE;
1849 netres.lpLocalName = letter;
1852 if (ctxt->flags & CONNECT_INTERACTIVE)
1853 return ERROR_BAD_NET_NAME;
1855 if ((ret = ctxt->pre_set_accessname(ctxt, netres.lpLocalName)))
1856 return ret;
1858 if (netres.lpProvider)
1860 index = _findProviderIndexW(netres.lpProvider);
1861 if (index == BAD_PROVIDER_INDEX)
1862 return ERROR_BAD_PROVIDER;
1864 provider = &providerTable->table[index];
1865 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
1867 else
1869 for (index = 0; index < providerTable->numProviders; index++)
1871 provider = &providerTable->table[index];
1872 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
1873 if (ret == WN_SUCCESS || ret == WN_ALREADY_CONNECTED)
1874 break;
1878 return ret;
1881 /*****************************************************************
1882 * WNetUseConnectionW [MPR.@]
1884 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
1885 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
1887 struct use_connection_context ctxt;
1889 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1890 hwndOwner, resource, password, debugstr_w(userid), flags,
1891 accessname, buffer_size, result );
1893 ctxt.hwndOwner = hwndOwner;
1894 ctxt.resource = resource;
1895 ctxt.resourceA = NULL;
1896 ctxt.password = (WCHAR*)password;
1897 ctxt.userid = (WCHAR*)userid;
1898 ctxt.flags = flags;
1899 ctxt.accessname = accessname;
1900 ctxt.buffer_size = buffer_size;
1901 ctxt.result = result;
1902 ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
1903 ctxt.set_accessname = use_connection_set_accessnameW;
1905 return wnet_use_connection(&ctxt);
1908 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
1910 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1912 DWORD len;
1914 if (local_name)
1915 len = WideCharToMultiByte(CP_ACP, 0, local_name, -1, NULL, 0, NULL, NULL) - 1;
1916 else
1917 len = strlen(ctxt->resourceA->lpRemoteName);
1919 if (++len > *ctxt->buffer_size)
1921 *ctxt->buffer_size = len;
1922 return ERROR_MORE_DATA;
1925 else
1926 ctxt->accessname = NULL;
1928 return ERROR_SUCCESS;
1931 static void use_connection_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
1933 char *accessname = ctxt->accessname;
1934 if (local_name)
1936 WideCharToMultiByte(CP_ACP, 0, local_name, -1, accessname, *ctxt->buffer_size, NULL, NULL);
1937 if (ctxt->result)
1938 *ctxt->result = CONNECT_LOCALDRIVE;
1940 else
1941 strcpy(accessname, ctxt->resourceA->lpRemoteName);
1944 static LPWSTR strdupAtoW( LPCSTR str )
1946 LPWSTR ret;
1947 INT len;
1949 if (!str) return NULL;
1950 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
1951 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1952 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
1953 return ret;
1956 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
1958 resourceW->dwScope = resourceA->dwScope;
1959 resourceW->dwType = resourceA->dwType;
1960 resourceW->dwDisplayType = resourceA->dwDisplayType;
1961 resourceW->dwUsage = resourceA->dwUsage;
1962 resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
1963 resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
1964 resourceW->lpComment = strdupAtoW(resourceA->lpComment);
1965 resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
1968 static void free_netresourceW( NETRESOURCEW *resource )
1970 HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
1971 HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
1972 HeapFree(GetProcessHeap(), 0, resource->lpComment);
1973 HeapFree(GetProcessHeap(), 0, resource->lpProvider);
1976 /*****************************************************************
1977 * WNetUseConnectionA [MPR.@]
1979 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
1980 LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
1981 DWORD *buffer_size, DWORD *result )
1983 struct use_connection_context ctxt;
1984 NETRESOURCEW resourceW;
1985 DWORD ret;
1987 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
1988 accessname, buffer_size, result );
1990 netresource_a_to_w(resource, &resourceW);
1992 ctxt.hwndOwner = hwndOwner;
1993 ctxt.resource = &resourceW;
1994 ctxt.resourceA = resource;
1995 ctxt.password = strdupAtoW(password);
1996 ctxt.userid = strdupAtoW(userid);
1997 ctxt.flags = flags;
1998 ctxt.accessname = accessname;
1999 ctxt.buffer_size = buffer_size;
2000 ctxt.result = result;
2001 ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
2002 ctxt.set_accessname = use_connection_set_accessnameA;
2004 ret = wnet_use_connection(&ctxt);
2006 free_netresourceW(&resourceW);
2007 HeapFree(GetProcessHeap(), 0, ctxt.password);
2008 HeapFree(GetProcessHeap(), 0, ctxt.userid);
2010 return ret;
2013 /*********************************************************************
2014 * WNetCancelConnectionA [MPR.@]
2016 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
2018 return WNetCancelConnection2A(lpName, 0, fForce);
2021 /*********************************************************************
2022 * WNetCancelConnectionW [MPR.@]
2024 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
2026 return WNetCancelConnection2W(lpName, 0, fForce);
2029 /*********************************************************************
2030 * WNetCancelConnection2A [MPR.@]
2032 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
2034 DWORD ret;
2035 WCHAR * name = strdupAtoW(lpName);
2036 if (!name)
2037 return ERROR_NOT_CONNECTED;
2039 ret = WNetCancelConnection2W(name, dwFlags, fForce);
2040 HeapFree(GetProcessHeap(), 0, name);
2042 return ret;
2045 /*********************************************************************
2046 * WNetCancelConnection2W [MPR.@]
2048 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
2050 DWORD ret = WN_NO_NETWORK;
2051 DWORD index;
2053 if (providerTable != NULL)
2055 for (index = 0; index < providerTable->numProviders; index++)
2057 if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2058 WNNC_CON_CANCELCONNECTION)
2060 if (providerTable->table[index].cancelConnection)
2061 ret = providerTable->table[index].cancelConnection((LPWSTR)lpName, fForce);
2062 else
2063 ret = WN_NO_NETWORK;
2064 if (ret == WN_SUCCESS || ret == WN_OPEN_FILES)
2065 break;
2069 return ret;
2072 /*****************************************************************
2073 * WNetRestoreConnectionA [MPR.@]
2075 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
2077 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
2079 SetLastError(WN_NO_NETWORK);
2080 return WN_NO_NETWORK;
2083 /*****************************************************************
2084 * WNetRestoreConnectionW [MPR.@]
2086 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
2088 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
2090 SetLastError(WN_NO_NETWORK);
2091 return WN_NO_NETWORK;
2094 /**************************************************************************
2095 * WNetGetConnectionA [MPR.@]
2097 * RETURNS
2098 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2099 * - WN_NOT_CONNECTED drive is a local drive
2100 * - WN_MORE_DATA buffer isn't big enough
2101 * - WN_SUCCESS success (net path in buffer)
2103 * FIXME: need to test return values under different errors
2105 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
2106 LPSTR lpRemoteName, LPDWORD lpBufferSize )
2108 DWORD ret;
2110 if (!lpLocalName)
2111 ret = WN_BAD_POINTER;
2112 else if (!lpBufferSize)
2113 ret = WN_BAD_POINTER;
2114 else if (!lpRemoteName && *lpBufferSize)
2115 ret = WN_BAD_POINTER;
2116 else
2118 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
2120 if (len)
2122 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2124 if (wideLocalName)
2126 WCHAR wideRemoteStatic[MAX_PATH];
2127 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
2129 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
2131 /* try once without memory allocation */
2132 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
2133 &wideRemoteSize);
2134 if (ret == WN_SUCCESS)
2136 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2137 -1, NULL, 0, NULL, NULL);
2139 if (len <= *lpBufferSize)
2141 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
2142 lpRemoteName, *lpBufferSize, NULL, NULL);
2143 ret = WN_SUCCESS;
2145 else
2147 *lpBufferSize = len;
2148 ret = WN_MORE_DATA;
2151 else if (ret == WN_MORE_DATA)
2153 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
2154 wideRemoteSize * sizeof(WCHAR));
2156 if (wideRemote)
2158 ret = WNetGetConnectionW(wideLocalName, wideRemote,
2159 &wideRemoteSize);
2160 if (ret == WN_SUCCESS)
2162 if (len <= *lpBufferSize)
2164 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2165 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
2166 ret = WN_SUCCESS;
2168 else
2170 *lpBufferSize = len;
2171 ret = WN_MORE_DATA;
2174 HeapFree(GetProcessHeap(), 0, wideRemote);
2176 else
2177 ret = WN_OUT_OF_MEMORY;
2179 HeapFree(GetProcessHeap(), 0, wideLocalName);
2181 else
2182 ret = WN_OUT_OF_MEMORY;
2184 else
2185 ret = WN_BAD_LOCALNAME;
2187 if (ret)
2188 SetLastError(ret);
2189 TRACE("Returning %d\n", ret);
2190 return ret;
2193 /* find the network connection for a given drive; helper for WNetGetConnection */
2194 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
2196 char buffer[1024];
2197 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
2198 HANDLE mgr;
2199 DWORD ret = WN_NOT_CONNECTED;
2200 DWORD bytes_returned;
2202 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
2203 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
2204 0, 0 )) == INVALID_HANDLE_VALUE)
2206 ERR( "failed to open mount manager err %u\n", GetLastError() );
2207 return ret;
2209 memset( data, 0, sizeof(*data) );
2210 data->letter = letter;
2211 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
2212 data, sizeof(buffer), &bytes_returned, NULL ))
2214 char *p, *mount_point = buffer + data->mount_point_offset;
2215 DWORD len;
2217 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
2219 mount_point += 2;
2220 mount_point[0] = '\\';
2221 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
2223 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
2224 if (len > *size)
2226 *size = len;
2227 ret = WN_MORE_DATA;
2229 else
2231 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
2232 ret = WN_SUCCESS;
2236 CloseHandle( mgr );
2237 return ret;
2240 /**************************************************************************
2241 * WNetGetConnectionW [MPR.@]
2243 * FIXME: need to test return values under different errors
2245 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
2246 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
2248 DWORD ret;
2250 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
2251 lpBufferSize);
2253 if (!lpLocalName)
2254 ret = WN_BAD_POINTER;
2255 else if (!lpBufferSize)
2256 ret = WN_BAD_POINTER;
2257 else if (!lpRemoteName && *lpBufferSize)
2258 ret = WN_BAD_POINTER;
2259 else if (!lpLocalName[0])
2260 ret = WN_BAD_LOCALNAME;
2261 else
2263 if (lpLocalName[1] == ':')
2265 switch(GetDriveTypeW(lpLocalName))
2267 case DRIVE_REMOTE:
2268 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
2269 break;
2270 case DRIVE_REMOVABLE:
2271 case DRIVE_FIXED:
2272 case DRIVE_CDROM:
2273 TRACE("file is local\n");
2274 ret = WN_NOT_CONNECTED;
2275 break;
2276 default:
2277 ret = WN_BAD_LOCALNAME;
2280 else
2281 ret = WN_BAD_LOCALNAME;
2283 if (ret)
2284 SetLastError(ret);
2285 TRACE("Returning %d\n", ret);
2286 return ret;
2289 /**************************************************************************
2290 * WNetSetConnectionA [MPR.@]
2292 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
2293 LPVOID pvValue )
2295 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
2297 SetLastError(WN_NO_NETWORK);
2298 return WN_NO_NETWORK;
2301 /**************************************************************************
2302 * WNetSetConnectionW [MPR.@]
2304 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2305 LPVOID pvValue )
2307 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2309 SetLastError(WN_NO_NETWORK);
2310 return WN_NO_NETWORK;
2313 /*****************************************************************
2314 * WNetGetUniversalNameA [MPR.@]
2316 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2317 LPVOID lpBuffer, LPDWORD lpBufferSize )
2319 DWORD err, size;
2321 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2322 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2324 switch (dwInfoLevel)
2326 case UNIVERSAL_NAME_INFO_LEVEL:
2328 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2330 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2332 err = ERROR_NOT_CONNECTED;
2333 break;
2336 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2337 if (*lpBufferSize < size)
2339 err = WN_MORE_DATA;
2340 break;
2342 info->lpUniversalName = (char *)info + sizeof(*info);
2343 lstrcpyA(info->lpUniversalName, lpLocalPath);
2344 err = WN_NO_ERROR;
2345 break;
2347 case REMOTE_NAME_INFO_LEVEL:
2348 err = WN_NO_NETWORK;
2349 break;
2351 default:
2352 err = WN_BAD_VALUE;
2353 break;
2356 SetLastError(err);
2357 return err;
2360 /*****************************************************************
2361 * WNetGetUniversalNameW [MPR.@]
2363 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2364 LPVOID lpBuffer, LPDWORD lpBufferSize )
2366 DWORD err, size;
2368 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2369 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2371 switch (dwInfoLevel)
2373 case UNIVERSAL_NAME_INFO_LEVEL:
2375 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2377 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2379 err = ERROR_NOT_CONNECTED;
2380 break;
2383 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2384 if (*lpBufferSize < size)
2386 err = WN_MORE_DATA;
2387 break;
2389 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2390 lstrcpyW(info->lpUniversalName, lpLocalPath);
2391 err = WN_NO_ERROR;
2392 break;
2394 case REMOTE_NAME_INFO_LEVEL:
2395 err = WN_NO_NETWORK;
2396 break;
2398 default:
2399 err = WN_BAD_VALUE;
2400 break;
2403 if (err != WN_NO_ERROR) SetLastError(err);
2404 return err;
2410 * Other Functions
2413 /**************************************************************************
2414 * WNetGetUserA [MPR.@]
2416 * FIXME: we should not return ourselves, but the owner of the drive lpName
2418 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2420 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2421 return GetLastError();
2424 /*****************************************************************
2425 * WNetGetUserW [MPR.@]
2427 * FIXME: we should not return ourselves, but the owner of the drive lpName
2429 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2431 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2432 return GetLastError();
2435 /*********************************************************************
2436 * WNetConnectionDialog [MPR.@]
2438 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2440 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2442 SetLastError(WN_NO_NETWORK);
2443 return WN_NO_NETWORK;
2446 /*********************************************************************
2447 * WNetConnectionDialog1A [MPR.@]
2449 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2451 FIXME( "(%p): stub\n", lpConnDlgStruct );
2453 SetLastError(WN_NO_NETWORK);
2454 return WN_NO_NETWORK;
2457 /*********************************************************************
2458 * WNetConnectionDialog1W [MPR.@]
2460 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2462 FIXME( "(%p): stub\n", lpConnDlgStruct );
2464 SetLastError(WN_NO_NETWORK);
2465 return WN_NO_NETWORK;
2468 /*********************************************************************
2469 * WNetDisconnectDialog [MPR.@]
2471 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2473 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2475 SetLastError(WN_NO_NETWORK);
2476 return WN_NO_NETWORK;
2479 /*********************************************************************
2480 * WNetDisconnectDialog1A [MPR.@]
2482 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2484 FIXME( "(%p): stub\n", lpConnDlgStruct );
2486 SetLastError(WN_NO_NETWORK);
2487 return WN_NO_NETWORK;
2490 /*********************************************************************
2491 * WNetDisconnectDialog1W [MPR.@]
2493 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2495 FIXME( "(%p): stub\n", lpConnDlgStruct );
2497 SetLastError(WN_NO_NETWORK);
2498 return WN_NO_NETWORK;
2501 /*********************************************************************
2502 * WNetGetLastErrorA [MPR.@]
2504 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2505 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2506 LPSTR lpNameBuf, DWORD nNameBufSize )
2508 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2509 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2511 SetLastError(WN_NO_NETWORK);
2512 return WN_NO_NETWORK;
2515 /*********************************************************************
2516 * WNetGetLastErrorW [MPR.@]
2518 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2519 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2520 LPWSTR lpNameBuf, DWORD nNameBufSize )
2522 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2523 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2525 SetLastError(WN_NO_NETWORK);
2526 return WN_NO_NETWORK;
2529 /*********************************************************************
2530 * WNetGetNetworkInformationA [MPR.@]
2532 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2533 LPNETINFOSTRUCT lpNetInfoStruct )
2535 DWORD ret;
2537 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2539 if (!lpProvider)
2540 ret = WN_BAD_POINTER;
2541 else
2543 int len;
2545 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2546 if (len)
2548 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2550 if (wideProvider)
2552 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2553 len);
2554 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2555 HeapFree(GetProcessHeap(), 0, wideProvider);
2557 else
2558 ret = WN_OUT_OF_MEMORY;
2560 else
2561 ret = GetLastError();
2563 if (ret)
2564 SetLastError(ret);
2565 TRACE("Returning %d\n", ret);
2566 return ret;
2569 /*********************************************************************
2570 * WNetGetNetworkInformationW [MPR.@]
2572 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2573 LPNETINFOSTRUCT lpNetInfoStruct )
2575 DWORD ret;
2577 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2579 if (!lpProvider)
2580 ret = WN_BAD_POINTER;
2581 else if (!lpNetInfoStruct)
2582 ret = WN_BAD_POINTER;
2583 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2584 ret = WN_BAD_VALUE;
2585 else
2587 if (providerTable && providerTable->numProviders)
2589 DWORD providerIndex = _findProviderIndexW(lpProvider);
2591 if (providerIndex != BAD_PROVIDER_INDEX)
2593 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2594 lpNetInfoStruct->dwProviderVersion =
2595 providerTable->table[providerIndex].dwSpecVersion;
2596 lpNetInfoStruct->dwStatus = NO_ERROR;
2597 lpNetInfoStruct->dwCharacteristics = 0;
2598 lpNetInfoStruct->dwHandle = 0;
2599 lpNetInfoStruct->wNetType =
2600 HIWORD(providerTable->table[providerIndex].dwNetType);
2601 lpNetInfoStruct->dwPrinters = -1;
2602 lpNetInfoStruct->dwDrives = -1;
2603 ret = WN_SUCCESS;
2605 else
2606 ret = WN_BAD_PROVIDER;
2608 else
2609 ret = WN_NO_NETWORK;
2611 if (ret)
2612 SetLastError(ret);
2613 TRACE("Returning %d\n", ret);
2614 return ret;
2617 /*****************************************************************
2618 * WNetGetProviderNameA [MPR.@]
2620 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2621 LPSTR lpProvider, LPDWORD lpBufferSize )
2623 DWORD ret;
2625 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2626 lpBufferSize);
2628 if (!lpProvider)
2629 ret = WN_BAD_POINTER;
2630 else if (!lpBufferSize)
2631 ret = WN_BAD_POINTER;
2632 else
2634 if (providerTable)
2636 DWORD i;
2638 ret = WN_NO_NETWORK;
2639 for (i = 0; i < providerTable->numProviders &&
2640 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2641 i++)
2643 if (i < providerTable->numProviders)
2645 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2646 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2648 if (*lpBufferSize < sizeNeeded)
2650 *lpBufferSize = sizeNeeded;
2651 ret = WN_MORE_DATA;
2653 else
2655 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2656 -1, lpProvider, *lpBufferSize, NULL, NULL);
2657 ret = WN_SUCCESS;
2658 /* FIXME: is *lpBufferSize set to the number of characters
2659 * copied? */
2663 else
2664 ret = WN_NO_NETWORK;
2666 if (ret)
2667 SetLastError(ret);
2668 TRACE("Returning %d\n", ret);
2669 return ret;
2672 /*****************************************************************
2673 * WNetGetProviderNameW [MPR.@]
2675 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2676 LPWSTR lpProvider, LPDWORD lpBufferSize )
2678 DWORD ret;
2680 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2681 lpBufferSize);
2683 if (!lpProvider)
2684 ret = WN_BAD_POINTER;
2685 else if (!lpBufferSize)
2686 ret = WN_BAD_POINTER;
2687 else
2689 if (providerTable)
2691 DWORD i;
2693 ret = WN_NO_NETWORK;
2694 for (i = 0; i < providerTable->numProviders &&
2695 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2696 i++)
2698 if (i < providerTable->numProviders)
2700 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2702 if (*lpBufferSize < sizeNeeded)
2704 *lpBufferSize = sizeNeeded;
2705 ret = WN_MORE_DATA;
2707 else
2709 strcpyW(lpProvider, providerTable->table[i].name);
2710 ret = WN_SUCCESS;
2711 /* FIXME: is *lpBufferSize set to the number of characters
2712 * copied? */
2716 else
2717 ret = WN_NO_NETWORK;
2719 if (ret)
2720 SetLastError(ret);
2721 TRACE("Returning %d\n", ret);
2722 return ret;