netapi32: Implement NetScheduleJobEnum.
[wine.git] / dlls / mpr / wnet.c
blob78759ecb1524c18921dd1da2a9db159f89a865d8
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, total_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;
1293 total_count = 0;
1295 ret = WN_NO_MORE_ENTRIES;
1296 for (index = 0; index < providerTable->numProviders; index++)
1298 if (providerTable->table[index].dwEnumScopes)
1300 if (handles[index] == 0)
1302 ret = providerTable->table[index].openEnum(enumerator->dwScope,
1303 enumerator->dwType,
1304 enumerator->dwUsage,
1305 NULL, &handles[index]);
1306 if (ret != WN_SUCCESS)
1307 continue;
1310 ret = providerTable->table[index].enumResource(handles[index],
1311 &count, buffer,
1312 &size);
1313 total_count += count;
1314 if (ret == WN_MORE_DATA)
1315 break;
1317 if (ret == WN_SUCCESS)
1319 for (i = 0; i < count; ++i)
1321 if (left < sizeof(NETRESOURCEW))
1323 ret = WN_MORE_DATA;
1324 break;
1327 memcpy(curr, &buffer[i], sizeof(NETRESOURCEW));
1328 left -= sizeof(NETRESOURCEW);
1330 ret = _copyStringToEnumW(buffer[i].lpLocalName, &left, &end);
1331 if (ret == WN_MORE_DATA)
1332 break;
1333 curr->lpLocalName = end;
1335 ret = _copyStringToEnumW(buffer[i].lpRemoteName, &left, &end);
1336 if (ret == WN_MORE_DATA)
1337 break;
1338 curr->lpRemoteName = end;
1340 ret = _copyStringToEnumW(buffer[i].lpProvider, &left, &end);
1341 if (ret == WN_MORE_DATA)
1342 break;
1343 curr->lpProvider = end;
1345 ++curr;
1348 size = left;
1351 if (*user_count != -1)
1352 count = *user_count - total_count;
1353 else
1354 count = *user_count;
1358 if (total_count == 0)
1359 ret = WN_NO_MORE_ENTRIES;
1361 *user_count = total_count;
1362 if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
1363 ret = WN_SUCCESS;
1365 HeapFree(GetProcessHeap(), 0, buffer);
1367 TRACE("Returning %d\n", ret);
1368 return ret;
1371 /*********************************************************************
1372 * WNetEnumResourceW [MPR.@]
1374 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1375 LPVOID lpBuffer, LPDWORD lpBufferSize )
1377 DWORD ret;
1379 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1381 if (!hEnum)
1382 ret = WN_BAD_POINTER;
1383 else if (!lpcCount)
1384 ret = WN_BAD_POINTER;
1385 else if (!lpBuffer)
1386 ret = WN_BAD_POINTER;
1387 else if (!lpBufferSize)
1388 ret = WN_BAD_POINTER;
1389 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1391 *lpBufferSize = sizeof(NETRESOURCEW);
1392 ret = WN_MORE_DATA;
1394 else
1396 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1398 switch (enumerator->enumType)
1400 case WNET_ENUMERATOR_TYPE_NULL:
1401 ret = WN_NO_MORE_ENTRIES;
1402 break;
1403 case WNET_ENUMERATOR_TYPE_GLOBAL:
1404 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1405 lpBufferSize);
1406 break;
1407 case WNET_ENUMERATOR_TYPE_PROVIDER:
1408 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1409 lpBufferSize);
1410 break;
1411 case WNET_ENUMERATOR_TYPE_CONTEXT:
1412 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1413 lpBufferSize);
1414 break;
1415 case WNET_ENUMERATOR_TYPE_CONNECTED:
1416 ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer,
1417 lpBufferSize);
1418 break;
1419 default:
1420 WARN("bogus enumerator type!\n");
1421 ret = WN_NO_NETWORK;
1424 if (ret)
1425 SetLastError(ret);
1426 TRACE("Returning %d\n", ret);
1427 return ret;
1430 /*********************************************************************
1431 * WNetCloseEnum [MPR.@]
1433 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1435 DWORD ret, index;
1436 HANDLE *handles;
1438 TRACE( "(%p)\n", hEnum );
1440 if (hEnum)
1442 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1444 switch (enumerator->enumType)
1446 case WNET_ENUMERATOR_TYPE_NULL:
1447 ret = WN_SUCCESS;
1448 break;
1449 case WNET_ENUMERATOR_TYPE_GLOBAL:
1450 if (enumerator->specific.net)
1451 _freeEnumNetResource(enumerator->specific.net);
1452 if (enumerator->handle)
1453 providerTable->table[enumerator->providerIndex].
1454 closeEnum(enumerator->handle);
1455 ret = WN_SUCCESS;
1456 break;
1457 case WNET_ENUMERATOR_TYPE_PROVIDER:
1458 if (enumerator->handle)
1459 providerTable->table[enumerator->providerIndex].
1460 closeEnum(enumerator->handle);
1461 ret = WN_SUCCESS;
1462 break;
1463 case WNET_ENUMERATOR_TYPE_CONNECTED:
1464 handles = enumerator->specific.handles;
1465 for (index = 0; index < providerTable->numProviders; index++)
1467 if (providerTable->table[index].dwEnumScopes && handles[index])
1468 providerTable->table[index].closeEnum(handles[index]);
1470 HeapFree(GetProcessHeap(), 0, handles);
1471 ret = WN_SUCCESS;
1472 break;
1473 default:
1474 WARN("bogus enumerator type!\n");
1475 ret = WN_BAD_HANDLE;
1477 HeapFree(GetProcessHeap(), 0, hEnum);
1479 else
1480 ret = WN_BAD_HANDLE;
1481 if (ret)
1482 SetLastError(ret);
1483 TRACE("Returning %d\n", ret);
1484 return ret;
1487 /*********************************************************************
1488 * WNetGetResourceInformationA [MPR.@]
1490 * See WNetGetResourceInformationW
1492 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1493 LPVOID lpBuffer, LPDWORD cbBuffer,
1494 LPSTR *lplpSystem )
1496 DWORD ret;
1498 TRACE( "(%p, %p, %p, %p)\n",
1499 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1501 if (!providerTable || providerTable->numProviders == 0)
1502 ret = WN_NO_NETWORK;
1503 else if (lpNetResource)
1505 LPNETRESOURCEW lpNetResourceW = NULL;
1506 DWORD size = 1024, count = 1;
1507 DWORD len;
1509 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1510 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1511 if (ret == WN_MORE_DATA)
1513 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1514 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1515 if (lpNetResourceW)
1516 ret = _thunkNetResourceArrayAToW(lpNetResource,
1517 &count, lpNetResourceW, &size);
1518 else
1519 ret = WN_OUT_OF_MEMORY;
1521 if (ret == WN_SUCCESS)
1523 LPWSTR lpSystemW = NULL;
1524 LPVOID lpBufferW;
1525 size = 1024;
1526 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1527 if (lpBufferW)
1529 ret = WNetGetResourceInformationW(lpNetResourceW,
1530 lpBufferW, &size, &lpSystemW);
1531 if (ret == WN_MORE_DATA)
1533 HeapFree(GetProcessHeap(), 0, lpBufferW);
1534 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1535 if (lpBufferW)
1536 ret = WNetGetResourceInformationW(lpNetResourceW,
1537 lpBufferW, &size, &lpSystemW);
1538 else
1539 ret = WN_OUT_OF_MEMORY;
1541 if (ret == WN_SUCCESS)
1543 ret = _thunkNetResourceArrayWToA(lpBufferW,
1544 &count, lpBuffer, cbBuffer);
1545 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1546 lpNetResourceW = lpBufferW;
1547 size = sizeof(NETRESOURCEA);
1548 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1549 -1, NULL, 0, NULL, NULL);
1550 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1551 -1, NULL, 0, NULL, NULL);
1553 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1554 -1, NULL, 0, NULL, NULL);
1555 if ((len) && ( size + len < *cbBuffer))
1557 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1558 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1559 *lplpSystem, len, NULL, NULL);
1560 ret = WN_SUCCESS;
1562 else
1563 ret = WN_MORE_DATA;
1565 else
1566 ret = WN_OUT_OF_MEMORY;
1567 HeapFree(GetProcessHeap(), 0, lpBufferW);
1569 else
1570 ret = WN_OUT_OF_MEMORY;
1571 HeapFree(GetProcessHeap(), 0, lpSystemW);
1573 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1575 else
1576 ret = WN_NO_NETWORK;
1578 if (ret)
1579 SetLastError(ret);
1580 TRACE("Returning %d\n", ret);
1581 return ret;
1584 /*********************************************************************
1585 * WNetGetResourceInformationW [MPR.@]
1587 * WNetGetResourceInformationW function identifies the network provider
1588 * that owns the resource and gets information about the type of the resource.
1590 * PARAMS:
1591 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1592 * defines a network resource.
1593 * lpBuffer [ O] the pointer to buffer, containing result. It
1594 * contains NETRESOURCEW structure and strings to
1595 * which the members of the NETRESOURCEW structure
1596 * point.
1597 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1598 * in bytes.
1599 * lplpSystem [ O] the pointer to string in the output buffer,
1600 * containing the part of the resource name without
1601 * names of the server and share.
1603 * RETURNS:
1604 * NO_ERROR if the function succeeds. System error code if the function fails.
1607 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1608 LPVOID lpBuffer, LPDWORD cbBuffer,
1609 LPWSTR *lplpSystem )
1611 DWORD ret = WN_NO_NETWORK;
1612 DWORD index;
1614 TRACE( "(%p, %p, %p, %p)\n",
1615 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1617 if (!(lpBuffer))
1618 ret = WN_OUT_OF_MEMORY;
1619 else if (providerTable != NULL)
1621 /* FIXME: For function value of a variable is indifferent, it does
1622 * search of all providers in a network.
1624 for (index = 0; index < providerTable->numProviders; index++)
1626 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1627 WNNC_DLG_GETRESOURCEINFORMATION)
1629 if (providerTable->table[index].getResourceInformation)
1630 ret = providerTable->table[index].getResourceInformation(
1631 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1632 else
1633 ret = WN_NO_NETWORK;
1634 if (ret == WN_SUCCESS)
1635 break;
1639 if (ret)
1640 SetLastError(ret);
1641 return ret;
1644 /*********************************************************************
1645 * WNetGetResourceParentA [MPR.@]
1647 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1648 LPVOID lpBuffer, LPDWORD lpBufferSize )
1650 FIXME( "(%p, %p, %p): stub\n",
1651 lpNetResource, lpBuffer, lpBufferSize );
1653 SetLastError(WN_NO_NETWORK);
1654 return WN_NO_NETWORK;
1657 /*********************************************************************
1658 * WNetGetResourceParentW [MPR.@]
1660 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1661 LPVOID lpBuffer, LPDWORD lpBufferSize )
1663 FIXME( "(%p, %p, %p): stub\n",
1664 lpNetResource, lpBuffer, lpBufferSize );
1666 SetLastError(WN_NO_NETWORK);
1667 return WN_NO_NETWORK;
1673 * Connection Functions
1676 /*********************************************************************
1677 * WNetAddConnectionA [MPR.@]
1679 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1680 LPCSTR lpLocalName )
1682 NETRESOURCEA resourcesA;
1684 memset(&resourcesA, 0, sizeof(resourcesA));
1685 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1686 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1687 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1690 /*********************************************************************
1691 * WNetAddConnectionW [MPR.@]
1693 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1694 LPCWSTR lpLocalName )
1696 NETRESOURCEW resourcesW;
1698 memset(&resourcesW, 0, sizeof(resourcesW));
1699 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1700 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1701 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1704 /*********************************************************************
1705 * WNetAddConnection2A [MPR.@]
1707 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1708 LPCSTR lpPassword, LPCSTR lpUserID,
1709 DWORD dwFlags )
1711 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1712 NULL, 0, NULL);
1715 /*********************************************************************
1716 * WNetAddConnection2W [MPR.@]
1718 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1719 LPCWSTR lpPassword, LPCWSTR lpUserID,
1720 DWORD dwFlags )
1722 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1723 NULL, 0, NULL);
1726 /*********************************************************************
1727 * WNetAddConnection3A [MPR.@]
1729 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1730 LPCSTR lpPassword, LPCSTR lpUserID,
1731 DWORD dwFlags )
1733 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1734 dwFlags, NULL, 0, NULL);
1737 /*********************************************************************
1738 * WNetAddConnection3W [MPR.@]
1740 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1741 LPCWSTR lpPassword, LPCWSTR lpUserID,
1742 DWORD dwFlags )
1744 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1745 dwFlags, NULL, 0, NULL);
1748 struct use_connection_context
1750 HWND hwndOwner;
1751 NETRESOURCEW *resource;
1752 NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */
1753 WCHAR *password;
1754 WCHAR *userid;
1755 DWORD flags;
1756 void *accessname;
1757 DWORD *buffer_size;
1758 DWORD *result;
1759 DWORD (*pre_set_accessname)(struct use_connection_context*, WCHAR *);
1760 void (*set_accessname)(struct use_connection_context*, WCHAR *);
1763 static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1765 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1767 DWORD len;
1769 if (local_name)
1770 len = strlenW(local_name);
1771 else
1772 len = strlenW(ctxt->resource->lpRemoteName);
1774 if (++len > *ctxt->buffer_size)
1776 *ctxt->buffer_size = len;
1777 return ERROR_MORE_DATA;
1780 else
1781 ctxt->accessname = NULL;
1783 return ERROR_SUCCESS;
1786 static void use_connection_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1788 WCHAR *accessname = ctxt->accessname;
1789 if (local_name)
1791 strcpyW(accessname, local_name);
1792 if (ctxt->result)
1793 *ctxt->result = CONNECT_LOCALDRIVE;
1795 else
1796 strcpyW(accessname, ctxt->resource->lpRemoteName);
1799 static DWORD wnet_use_provider( struct use_connection_context *ctxt, NETRESOURCEW * netres, WNetProvider *provider, BOOLEAN redirect )
1801 DWORD caps, ret;
1803 caps = provider->getCaps(WNNC_CONNECTION);
1804 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1805 return ERROR_BAD_PROVIDER;
1807 ret = WN_ACCESS_DENIED;
1810 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1811 ret = provider->addConnection3(ctxt->hwndOwner, netres, ctxt->password, ctxt->userid, ctxt->flags);
1812 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1813 ret = provider->addConnection(netres, ctxt->password, ctxt->userid);
1815 if (ret == WN_ALREADY_CONNECTED && redirect)
1816 netres->lpLocalName[0] -= 1;
1817 } while (redirect && ret == WN_ALREADY_CONNECTED && netres->lpLocalName[0] >= 'C');
1819 if (ret == WN_SUCCESS && ctxt->accessname)
1820 ctxt->set_accessname(ctxt, netres->lpLocalName);
1822 return ret;
1825 static DWORD wnet_use_connection( struct use_connection_context *ctxt )
1827 WNetProvider *provider;
1828 DWORD index, ret = WN_NO_NETWORK;
1829 BOOL redirect = FALSE;
1830 WCHAR letter[3] = {'Z', ':', 0};
1831 NETRESOURCEW netres;
1833 if (!providerTable || providerTable->numProviders == 0)
1834 return WN_NO_NETWORK;
1836 if (!ctxt->resource)
1837 return ERROR_INVALID_PARAMETER;
1838 netres = *ctxt->resource;
1840 if (!netres.lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
1842 if (netres.dwType != RESOURCETYPE_DISK && netres.dwType != RESOURCETYPE_PRINT)
1843 return ERROR_BAD_DEV_TYPE;
1845 if (netres.dwType == RESOURCETYPE_PRINT)
1847 FIXME("Local device selection is not implemented for printers.\n");
1848 return WN_NO_NETWORK;
1851 redirect = TRUE;
1852 netres.lpLocalName = letter;
1855 if (ctxt->flags & CONNECT_INTERACTIVE)
1856 return ERROR_BAD_NET_NAME;
1858 if ((ret = ctxt->pre_set_accessname(ctxt, netres.lpLocalName)))
1859 return ret;
1861 if (netres.lpProvider)
1863 index = _findProviderIndexW(netres.lpProvider);
1864 if (index == BAD_PROVIDER_INDEX)
1865 return ERROR_BAD_PROVIDER;
1867 provider = &providerTable->table[index];
1868 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
1870 else
1872 for (index = 0; index < providerTable->numProviders; index++)
1874 provider = &providerTable->table[index];
1875 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
1876 if (ret == WN_SUCCESS || ret == WN_ALREADY_CONNECTED)
1877 break;
1881 return ret;
1884 /*****************************************************************
1885 * WNetUseConnectionW [MPR.@]
1887 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
1888 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
1890 struct use_connection_context ctxt;
1892 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1893 hwndOwner, resource, password, debugstr_w(userid), flags,
1894 accessname, buffer_size, result );
1896 ctxt.hwndOwner = hwndOwner;
1897 ctxt.resource = resource;
1898 ctxt.resourceA = NULL;
1899 ctxt.password = (WCHAR*)password;
1900 ctxt.userid = (WCHAR*)userid;
1901 ctxt.flags = flags;
1902 ctxt.accessname = accessname;
1903 ctxt.buffer_size = buffer_size;
1904 ctxt.result = result;
1905 ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
1906 ctxt.set_accessname = use_connection_set_accessnameW;
1908 return wnet_use_connection(&ctxt);
1911 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
1913 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1915 DWORD len;
1917 if (local_name)
1918 len = WideCharToMultiByte(CP_ACP, 0, local_name, -1, NULL, 0, NULL, NULL) - 1;
1919 else
1920 len = strlen(ctxt->resourceA->lpRemoteName);
1922 if (++len > *ctxt->buffer_size)
1924 *ctxt->buffer_size = len;
1925 return ERROR_MORE_DATA;
1928 else
1929 ctxt->accessname = NULL;
1931 return ERROR_SUCCESS;
1934 static void use_connection_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
1936 char *accessname = ctxt->accessname;
1937 if (local_name)
1939 WideCharToMultiByte(CP_ACP, 0, local_name, -1, accessname, *ctxt->buffer_size, NULL, NULL);
1940 if (ctxt->result)
1941 *ctxt->result = CONNECT_LOCALDRIVE;
1943 else
1944 strcpy(accessname, ctxt->resourceA->lpRemoteName);
1947 static LPWSTR strdupAtoW( LPCSTR str )
1949 LPWSTR ret;
1950 INT len;
1952 if (!str) return NULL;
1953 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
1954 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1955 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
1956 return ret;
1959 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
1961 resourceW->dwScope = resourceA->dwScope;
1962 resourceW->dwType = resourceA->dwType;
1963 resourceW->dwDisplayType = resourceA->dwDisplayType;
1964 resourceW->dwUsage = resourceA->dwUsage;
1965 resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
1966 resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
1967 resourceW->lpComment = strdupAtoW(resourceA->lpComment);
1968 resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
1971 static void free_netresourceW( NETRESOURCEW *resource )
1973 HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
1974 HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
1975 HeapFree(GetProcessHeap(), 0, resource->lpComment);
1976 HeapFree(GetProcessHeap(), 0, resource->lpProvider);
1979 /*****************************************************************
1980 * WNetUseConnectionA [MPR.@]
1982 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
1983 LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
1984 DWORD *buffer_size, DWORD *result )
1986 struct use_connection_context ctxt;
1987 NETRESOURCEW resourceW;
1988 DWORD ret;
1990 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
1991 accessname, buffer_size, result );
1993 netresource_a_to_w(resource, &resourceW);
1995 ctxt.hwndOwner = hwndOwner;
1996 ctxt.resource = &resourceW;
1997 ctxt.resourceA = resource;
1998 ctxt.password = strdupAtoW(password);
1999 ctxt.userid = strdupAtoW(userid);
2000 ctxt.flags = flags;
2001 ctxt.accessname = accessname;
2002 ctxt.buffer_size = buffer_size;
2003 ctxt.result = result;
2004 ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
2005 ctxt.set_accessname = use_connection_set_accessnameA;
2007 ret = wnet_use_connection(&ctxt);
2009 free_netresourceW(&resourceW);
2010 HeapFree(GetProcessHeap(), 0, ctxt.password);
2011 HeapFree(GetProcessHeap(), 0, ctxt.userid);
2013 return ret;
2016 /*********************************************************************
2017 * WNetCancelConnectionA [MPR.@]
2019 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
2021 return WNetCancelConnection2A(lpName, 0, fForce);
2024 /*********************************************************************
2025 * WNetCancelConnectionW [MPR.@]
2027 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
2029 return WNetCancelConnection2W(lpName, 0, fForce);
2032 /*********************************************************************
2033 * WNetCancelConnection2A [MPR.@]
2035 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
2037 DWORD ret;
2038 WCHAR * name = strdupAtoW(lpName);
2039 if (!name)
2040 return ERROR_NOT_CONNECTED;
2042 ret = WNetCancelConnection2W(name, dwFlags, fForce);
2043 HeapFree(GetProcessHeap(), 0, name);
2045 return ret;
2048 /*********************************************************************
2049 * WNetCancelConnection2W [MPR.@]
2051 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
2053 DWORD ret = WN_NO_NETWORK;
2054 DWORD index;
2056 if (providerTable != NULL)
2058 for (index = 0; index < providerTable->numProviders; index++)
2060 if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2061 WNNC_CON_CANCELCONNECTION)
2063 if (providerTable->table[index].cancelConnection)
2064 ret = providerTable->table[index].cancelConnection((LPWSTR)lpName, fForce);
2065 else
2066 ret = WN_NO_NETWORK;
2067 if (ret == WN_SUCCESS || ret == WN_OPEN_FILES)
2068 break;
2072 return ret;
2075 /*****************************************************************
2076 * WNetRestoreConnectionA [MPR.@]
2078 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
2080 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
2082 SetLastError(WN_NO_NETWORK);
2083 return WN_NO_NETWORK;
2086 /*****************************************************************
2087 * WNetRestoreConnectionW [MPR.@]
2089 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
2091 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
2093 SetLastError(WN_NO_NETWORK);
2094 return WN_NO_NETWORK;
2097 /**************************************************************************
2098 * WNetGetConnectionA [MPR.@]
2100 * RETURNS
2101 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2102 * - WN_NOT_CONNECTED drive is a local drive
2103 * - WN_MORE_DATA buffer isn't big enough
2104 * - WN_SUCCESS success (net path in buffer)
2106 * FIXME: need to test return values under different errors
2108 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
2109 LPSTR lpRemoteName, LPDWORD lpBufferSize )
2111 DWORD ret;
2113 if (!lpLocalName)
2114 ret = WN_BAD_POINTER;
2115 else if (!lpBufferSize)
2116 ret = WN_BAD_POINTER;
2117 else if (!lpRemoteName && *lpBufferSize)
2118 ret = WN_BAD_POINTER;
2119 else
2121 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
2123 if (len)
2125 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2127 if (wideLocalName)
2129 WCHAR wideRemoteStatic[MAX_PATH];
2130 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
2132 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
2134 /* try once without memory allocation */
2135 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
2136 &wideRemoteSize);
2137 if (ret == WN_SUCCESS)
2139 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2140 -1, NULL, 0, NULL, NULL);
2142 if (len <= *lpBufferSize)
2144 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
2145 lpRemoteName, *lpBufferSize, NULL, NULL);
2146 ret = WN_SUCCESS;
2148 else
2150 *lpBufferSize = len;
2151 ret = WN_MORE_DATA;
2154 else if (ret == WN_MORE_DATA)
2156 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
2157 wideRemoteSize * sizeof(WCHAR));
2159 if (wideRemote)
2161 ret = WNetGetConnectionW(wideLocalName, wideRemote,
2162 &wideRemoteSize);
2163 if (ret == WN_SUCCESS)
2165 if (len <= *lpBufferSize)
2167 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2168 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
2169 ret = WN_SUCCESS;
2171 else
2173 *lpBufferSize = len;
2174 ret = WN_MORE_DATA;
2177 HeapFree(GetProcessHeap(), 0, wideRemote);
2179 else
2180 ret = WN_OUT_OF_MEMORY;
2182 HeapFree(GetProcessHeap(), 0, wideLocalName);
2184 else
2185 ret = WN_OUT_OF_MEMORY;
2187 else
2188 ret = WN_BAD_LOCALNAME;
2190 if (ret)
2191 SetLastError(ret);
2192 TRACE("Returning %d\n", ret);
2193 return ret;
2196 /* find the network connection for a given drive; helper for WNetGetConnection */
2197 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
2199 char buffer[1024];
2200 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
2201 HANDLE mgr;
2202 DWORD ret = WN_NOT_CONNECTED;
2203 DWORD bytes_returned;
2205 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
2206 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
2207 0, 0 )) == INVALID_HANDLE_VALUE)
2209 ERR( "failed to open mount manager err %u\n", GetLastError() );
2210 return ret;
2212 memset( data, 0, sizeof(*data) );
2213 data->letter = letter;
2214 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
2215 data, sizeof(buffer), &bytes_returned, NULL ))
2217 char *p, *mount_point = buffer + data->mount_point_offset;
2218 DWORD len;
2220 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
2222 mount_point += 2;
2223 mount_point[0] = '\\';
2224 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
2226 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
2227 if (len > *size)
2229 *size = len;
2230 ret = WN_MORE_DATA;
2232 else
2234 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
2235 ret = WN_SUCCESS;
2239 CloseHandle( mgr );
2240 return ret;
2243 /**************************************************************************
2244 * WNetGetConnectionW [MPR.@]
2246 * FIXME: need to test return values under different errors
2248 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
2249 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
2251 DWORD ret;
2253 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
2254 lpBufferSize);
2256 if (!lpLocalName)
2257 ret = WN_BAD_POINTER;
2258 else if (!lpBufferSize)
2259 ret = WN_BAD_POINTER;
2260 else if (!lpRemoteName && *lpBufferSize)
2261 ret = WN_BAD_POINTER;
2262 else if (!lpLocalName[0])
2263 ret = WN_BAD_LOCALNAME;
2264 else
2266 if (lpLocalName[1] == ':')
2268 switch(GetDriveTypeW(lpLocalName))
2270 case DRIVE_REMOTE:
2271 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
2272 break;
2273 case DRIVE_REMOVABLE:
2274 case DRIVE_FIXED:
2275 case DRIVE_CDROM:
2276 TRACE("file is local\n");
2277 ret = WN_NOT_CONNECTED;
2278 break;
2279 default:
2280 ret = WN_BAD_LOCALNAME;
2283 else
2284 ret = WN_BAD_LOCALNAME;
2286 if (ret)
2287 SetLastError(ret);
2288 TRACE("Returning %d\n", ret);
2289 return ret;
2292 /**************************************************************************
2293 * WNetSetConnectionA [MPR.@]
2295 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
2296 LPVOID pvValue )
2298 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
2300 SetLastError(WN_NO_NETWORK);
2301 return WN_NO_NETWORK;
2304 /**************************************************************************
2305 * WNetSetConnectionW [MPR.@]
2307 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2308 LPVOID pvValue )
2310 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2312 SetLastError(WN_NO_NETWORK);
2313 return WN_NO_NETWORK;
2316 /*****************************************************************
2317 * WNetGetUniversalNameA [MPR.@]
2319 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2320 LPVOID lpBuffer, LPDWORD lpBufferSize )
2322 DWORD err, size;
2324 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2325 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2327 switch (dwInfoLevel)
2329 case UNIVERSAL_NAME_INFO_LEVEL:
2331 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2333 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2335 err = ERROR_NOT_CONNECTED;
2336 break;
2339 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2340 if (*lpBufferSize < size)
2342 err = WN_MORE_DATA;
2343 break;
2345 info->lpUniversalName = (char *)info + sizeof(*info);
2346 lstrcpyA(info->lpUniversalName, lpLocalPath);
2347 err = WN_NO_ERROR;
2348 break;
2350 case REMOTE_NAME_INFO_LEVEL:
2351 err = WN_NOT_CONNECTED;
2352 break;
2354 default:
2355 err = WN_BAD_VALUE;
2356 break;
2359 SetLastError(err);
2360 return err;
2363 /*****************************************************************
2364 * WNetGetUniversalNameW [MPR.@]
2366 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2367 LPVOID lpBuffer, LPDWORD lpBufferSize )
2369 DWORD err, size;
2371 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2372 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2374 switch (dwInfoLevel)
2376 case UNIVERSAL_NAME_INFO_LEVEL:
2378 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2380 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2382 err = ERROR_NOT_CONNECTED;
2383 break;
2386 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2387 if (*lpBufferSize < size)
2389 err = WN_MORE_DATA;
2390 break;
2392 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2393 lstrcpyW(info->lpUniversalName, lpLocalPath);
2394 err = WN_NO_ERROR;
2395 break;
2397 case REMOTE_NAME_INFO_LEVEL:
2398 err = WN_NO_NETWORK;
2399 break;
2401 default:
2402 err = WN_BAD_VALUE;
2403 break;
2406 if (err != WN_NO_ERROR) SetLastError(err);
2407 return err;
2413 * Other Functions
2416 /**************************************************************************
2417 * WNetGetUserA [MPR.@]
2419 * FIXME: we should not return ourselves, but the owner of the drive lpName
2421 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2423 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2424 return GetLastError();
2427 /*****************************************************************
2428 * WNetGetUserW [MPR.@]
2430 * FIXME: we should not return ourselves, but the owner of the drive lpName
2432 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2434 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2435 return GetLastError();
2438 /*********************************************************************
2439 * WNetConnectionDialog [MPR.@]
2441 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2443 CONNECTDLGSTRUCTW conn_dlg;
2444 NETRESOURCEW net_res;
2446 ZeroMemory(&conn_dlg, sizeof(conn_dlg));
2447 ZeroMemory(&net_res, sizeof(net_res));
2449 conn_dlg.cbStructure = sizeof(conn_dlg);
2450 conn_dlg.lpConnRes = &net_res;
2451 conn_dlg.hwndOwner = hwnd;
2452 net_res.dwType = dwType;
2454 return WNetConnectionDialog1W(&conn_dlg);
2457 /*********************************************************************
2458 * WNetConnectionDialog1A [MPR.@]
2460 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2462 FIXME( "(%p): stub\n", lpConnDlgStruct );
2464 SetLastError(WN_NO_NETWORK);
2465 return WN_NO_NETWORK;
2468 /*********************************************************************
2469 * WNetConnectionDialog1W [MPR.@]
2471 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2473 FIXME( "(%p): stub\n", lpConnDlgStruct );
2475 SetLastError(WN_NO_NETWORK);
2476 return WN_NO_NETWORK;
2479 /*********************************************************************
2480 * WNetDisconnectDialog [MPR.@]
2482 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2484 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2486 SetLastError(WN_NO_NETWORK);
2487 return WN_NO_NETWORK;
2490 /*********************************************************************
2491 * WNetDisconnectDialog1A [MPR.@]
2493 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2495 FIXME( "(%p): stub\n", lpConnDlgStruct );
2497 SetLastError(WN_NO_NETWORK);
2498 return WN_NO_NETWORK;
2501 /*********************************************************************
2502 * WNetDisconnectDialog1W [MPR.@]
2504 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2506 FIXME( "(%p): stub\n", lpConnDlgStruct );
2508 SetLastError(WN_NO_NETWORK);
2509 return WN_NO_NETWORK;
2512 /*********************************************************************
2513 * WNetGetLastErrorA [MPR.@]
2515 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2516 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2517 LPSTR lpNameBuf, DWORD nNameBufSize )
2519 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2520 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2522 SetLastError(WN_NO_NETWORK);
2523 return WN_NO_NETWORK;
2526 /*********************************************************************
2527 * WNetGetLastErrorW [MPR.@]
2529 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2530 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2531 LPWSTR lpNameBuf, DWORD nNameBufSize )
2533 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2534 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2536 SetLastError(WN_NO_NETWORK);
2537 return WN_NO_NETWORK;
2540 /*********************************************************************
2541 * WNetGetNetworkInformationA [MPR.@]
2543 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2544 LPNETINFOSTRUCT lpNetInfoStruct )
2546 DWORD ret;
2548 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2550 if (!lpProvider)
2551 ret = WN_BAD_POINTER;
2552 else
2554 int len;
2556 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2557 if (len)
2559 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2561 if (wideProvider)
2563 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2564 len);
2565 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2566 HeapFree(GetProcessHeap(), 0, wideProvider);
2568 else
2569 ret = WN_OUT_OF_MEMORY;
2571 else
2572 ret = GetLastError();
2574 if (ret)
2575 SetLastError(ret);
2576 TRACE("Returning %d\n", ret);
2577 return ret;
2580 /*********************************************************************
2581 * WNetGetNetworkInformationW [MPR.@]
2583 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2584 LPNETINFOSTRUCT lpNetInfoStruct )
2586 DWORD ret;
2588 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2590 if (!lpProvider)
2591 ret = WN_BAD_POINTER;
2592 else if (!lpNetInfoStruct)
2593 ret = WN_BAD_POINTER;
2594 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2595 ret = WN_BAD_VALUE;
2596 else
2598 if (providerTable && providerTable->numProviders)
2600 DWORD providerIndex = _findProviderIndexW(lpProvider);
2602 if (providerIndex != BAD_PROVIDER_INDEX)
2604 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2605 lpNetInfoStruct->dwProviderVersion =
2606 providerTable->table[providerIndex].dwSpecVersion;
2607 lpNetInfoStruct->dwStatus = NO_ERROR;
2608 lpNetInfoStruct->dwCharacteristics = 0;
2609 lpNetInfoStruct->dwHandle = 0;
2610 lpNetInfoStruct->wNetType =
2611 HIWORD(providerTable->table[providerIndex].dwNetType);
2612 lpNetInfoStruct->dwPrinters = -1;
2613 lpNetInfoStruct->dwDrives = -1;
2614 ret = WN_SUCCESS;
2616 else
2617 ret = WN_BAD_PROVIDER;
2619 else
2620 ret = WN_NO_NETWORK;
2622 if (ret)
2623 SetLastError(ret);
2624 TRACE("Returning %d\n", ret);
2625 return ret;
2628 /*****************************************************************
2629 * WNetGetProviderNameA [MPR.@]
2631 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2632 LPSTR lpProvider, LPDWORD lpBufferSize )
2634 DWORD ret;
2636 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2637 lpBufferSize);
2639 if (!lpProvider)
2640 ret = WN_BAD_POINTER;
2641 else if (!lpBufferSize)
2642 ret = WN_BAD_POINTER;
2643 else
2645 if (providerTable)
2647 DWORD i;
2649 ret = WN_NO_NETWORK;
2650 for (i = 0; i < providerTable->numProviders &&
2651 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2652 i++)
2654 if (i < providerTable->numProviders)
2656 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2657 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2659 if (*lpBufferSize < sizeNeeded)
2661 *lpBufferSize = sizeNeeded;
2662 ret = WN_MORE_DATA;
2664 else
2666 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2667 -1, lpProvider, *lpBufferSize, NULL, NULL);
2668 ret = WN_SUCCESS;
2669 /* FIXME: is *lpBufferSize set to the number of characters
2670 * copied? */
2674 else
2675 ret = WN_NO_NETWORK;
2677 if (ret)
2678 SetLastError(ret);
2679 TRACE("Returning %d\n", ret);
2680 return ret;
2683 /*****************************************************************
2684 * WNetGetProviderNameW [MPR.@]
2686 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2687 LPWSTR lpProvider, LPDWORD lpBufferSize )
2689 DWORD ret;
2691 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2692 lpBufferSize);
2694 if (!lpProvider)
2695 ret = WN_BAD_POINTER;
2696 else if (!lpBufferSize)
2697 ret = WN_BAD_POINTER;
2698 else
2700 if (providerTable)
2702 DWORD i;
2704 ret = WN_NO_NETWORK;
2705 for (i = 0; i < providerTable->numProviders &&
2706 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2707 i++)
2709 if (i < providerTable->numProviders)
2711 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2713 if (*lpBufferSize < sizeNeeded)
2715 *lpBufferSize = sizeNeeded;
2716 ret = WN_MORE_DATA;
2718 else
2720 strcpyW(lpProvider, providerTable->table[i].name);
2721 ret = WN_SUCCESS;
2722 /* FIXME: is *lpBufferSize set to the number of characters
2723 * copied? */
2727 else
2728 ret = WN_NO_NETWORK;
2730 if (ret)
2731 SetLastError(ret);
2732 TRACE("Returning %d\n", ret);
2733 return ret;