wined3d: Add support for WINED3DFMT_R8G8_SINT format.
[wine.git] / dlls / mpr / wnet.c
blob50f71d2440c81e3246fc93c17484b44aaa40298c
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 PWNetProvider provider =
182 &providerTable->table[providerTable->numProviders];
184 provider->hLib = hLib;
185 provider->name = name;
186 TRACE("name is %s\n", debugstr_w(name));
187 provider->getCaps = getCaps;
188 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
189 provider->dwNetType = getCaps(WNNC_NET_TYPE);
190 TRACE("net type is 0x%08x\n", provider->dwNetType);
191 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
192 if (provider->dwEnumScopes)
194 TRACE("supports enumeration\n");
195 provider->openEnum = MPR_GETPROC(NPOpenEnum);
196 TRACE("NPOpenEnum %p\n", provider->openEnum);
197 provider->enumResource = MPR_GETPROC(NPEnumResource);
198 TRACE("NPEnumResource %p\n", provider->enumResource);
199 provider->closeEnum = MPR_GETPROC(NPCloseEnum);
200 TRACE("NPCloseEnum %p\n", provider->closeEnum);
201 provider->getResourceInformation = MPR_GETPROC(NPGetResourceInformation);
202 TRACE("NPGetResourceInformation %p\n", provider->getResourceInformation);
203 if (!provider->openEnum ||
204 !provider->enumResource ||
205 !provider->closeEnum)
207 provider->openEnum = NULL;
208 provider->enumResource = NULL;
209 provider->closeEnum = NULL;
210 provider->dwEnumScopes = 0;
211 WARN("Couldn't load enumeration functions\n");
214 provider->addConnection = MPR_GETPROC(NPAddConnection);
215 provider->addConnection3 = MPR_GETPROC(NPAddConnection3);
216 provider->cancelConnection = MPR_GETPROC(NPCancelConnection);
217 TRACE("NPAddConnection %p\n", provider->addConnection);
218 TRACE("NPAddConnection3 %p\n", provider->addConnection3);
219 TRACE("NPCancelConnection %p\n", provider->cancelConnection);
220 providerTable->numProviders++;
222 else
224 WARN("Provider %s didn't export NPGetCaps\n",
225 debugstr_w(provider));
226 HeapFree(GetProcessHeap(), 0, name);
227 FreeLibrary(hLib);
230 #undef MPR_GETPROC
232 else
234 WARN("Couldn't load library %s for provider %s\n",
235 debugstr_w(providerPath), debugstr_w(provider));
236 HeapFree(GetProcessHeap(), 0, name);
239 else
241 WARN("Couldn't get provider name for provider %s\n",
242 debugstr_w(provider));
245 else
246 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
247 RegCloseKey(hKey);
249 else
250 WARN("Couldn't open service key for provider %s\n",
251 debugstr_w(provider));
254 void wnetInit(HINSTANCE hInstDll)
256 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
257 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
258 'C','o','n','t','r','o','l','\\',
259 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
260 'O','r','d','e','r',0 };
261 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
262 'O','r','d','e','r',0 };
263 HKEY hKey;
265 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
266 == ERROR_SUCCESS)
268 DWORD size = 0;
270 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
271 if (size)
273 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
275 if (providers)
277 DWORD type;
279 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
280 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
282 PWSTR ptr;
283 DWORD numToAllocate;
285 TRACE("provider order is %s\n", debugstr_w(providers));
286 /* first count commas as a heuristic for how many to
287 * allocate space for */
288 for (ptr = providers, numToAllocate = 1; ptr; )
290 ptr = strchrW(ptr, ',');
291 if (ptr) {
292 numToAllocate++;
293 ptr++;
296 providerTable =
297 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
298 sizeof(WNetProviderTable)
299 + (numToAllocate - 1) * sizeof(WNetProvider));
300 if (providerTable)
302 PWSTR ptrPrev;
303 int entireNetworkLen;
304 LPCWSTR stringresource;
306 entireNetworkLen = LoadStringW(hInstDll,
307 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
308 providerTable->entireNetwork = HeapAlloc(
309 GetProcessHeap(), 0, (entireNetworkLen + 1) *
310 sizeof(WCHAR));
311 if (providerTable->entireNetwork)
313 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
314 providerTable->entireNetwork[entireNetworkLen] = 0;
316 providerTable->numAllocated = numToAllocate;
317 for (ptr = providers; ptr; )
319 ptrPrev = ptr;
320 ptr = strchrW(ptr, ',');
321 if (ptr)
322 *ptr++ = '\0';
323 _tryLoadProvider(ptrPrev);
327 HeapFree(GetProcessHeap(), 0, providers);
330 RegCloseKey(hKey);
334 void wnetFree(void)
336 if (providerTable)
338 DWORD i;
340 for (i = 0; i < providerTable->numProviders; i++)
342 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
343 FreeModule(providerTable->table[i].hLib);
345 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
346 HeapFree(GetProcessHeap(), 0, providerTable);
347 providerTable = NULL;
351 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
353 DWORD ret = BAD_PROVIDER_INDEX;
355 if (providerTable && providerTable->numProviders)
357 DWORD i;
359 for (i = 0; i < providerTable->numProviders &&
360 ret == BAD_PROVIDER_INDEX; i++)
361 if (!strcmpW(lpProvider, providerTable->table[i].name))
362 ret = i;
364 return ret;
368 * Browsing Functions
371 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
373 LPNETRESOURCEW ret;
375 if (lpNet)
377 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
378 if (ret)
380 size_t len;
382 *ret = *lpNet;
383 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
384 if (lpNet->lpRemoteName)
386 len = strlenW(lpNet->lpRemoteName) + 1;
387 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
388 if (ret->lpRemoteName)
389 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
393 else
394 ret = NULL;
395 return ret;
398 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
400 if (lpNet)
402 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
403 HeapFree(GetProcessHeap(), 0, lpNet);
407 static PWNetEnumerator _createNullEnumerator(void)
409 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
410 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
412 if (ret)
413 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
414 return ret;
417 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
418 DWORD dwUsage, LPNETRESOURCEW lpNet)
420 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
421 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
423 if (ret)
425 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
426 ret->dwScope = dwScope;
427 ret->dwType = dwType;
428 ret->dwUsage = dwUsage;
429 ret->specific.net = _copyNetResourceForEnumW(lpNet);
431 return ret;
434 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
435 DWORD dwUsage, DWORD index, HANDLE handle)
437 PWNetEnumerator ret;
439 if (!providerTable || index >= providerTable->numProviders)
440 ret = NULL;
441 else
443 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
444 if (ret)
446 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
447 ret->providerIndex = index;
448 ret->dwScope = dwScope;
449 ret->dwType = dwType;
450 ret->dwUsage = dwUsage;
451 ret->handle = handle;
454 return ret;
457 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
458 DWORD dwUsage)
460 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
461 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
463 if (ret)
465 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
466 ret->dwScope = dwScope;
467 ret->dwType = dwType;
468 ret->dwUsage = dwUsage;
470 return ret;
473 static PWNetEnumerator _createConnectedEnumerator(DWORD dwScope, DWORD dwType,
474 DWORD dwUsage)
476 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
477 if (ret)
479 ret->enumType = WNET_ENUMERATOR_TYPE_CONNECTED;
480 ret->dwScope = dwScope;
481 ret->dwType = dwType;
482 ret->dwUsage = dwUsage;
483 ret->specific.handles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HANDLE) * providerTable->numProviders);
484 if (!ret->specific.handles)
486 HeapFree(GetProcessHeap(), 0, ret);
487 ret = NULL;
490 return ret;
493 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
494 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
495 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
496 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
497 * if not all members of the array could be thunked, and something else on
498 * failure.
500 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
501 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
503 DWORD i, numToThunk, totalBytes, ret;
504 LPSTR strNext;
506 if (!lpNetArrayIn)
507 return WN_BAD_POINTER;
508 if (!lpcCount)
509 return WN_BAD_POINTER;
510 if (*lpcCount == -1)
511 return WN_BAD_VALUE;
512 if (!lpBuffer)
513 return WN_BAD_POINTER;
514 if (!lpBufferSize)
515 return WN_BAD_POINTER;
517 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
519 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
521 totalBytes += sizeof(NETRESOURCEA);
522 if (lpNet->lpLocalName)
523 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
524 -1, NULL, 0, NULL, NULL);
525 if (lpNet->lpRemoteName)
526 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
527 -1, NULL, 0, NULL, NULL);
528 if (lpNet->lpComment)
529 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
530 -1, NULL, 0, NULL, NULL);
531 if (lpNet->lpProvider)
532 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
533 -1, NULL, 0, NULL, NULL);
534 if (totalBytes < *lpBufferSize)
535 numToThunk = i + 1;
537 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
538 for (i = 0; i < numToThunk; i++)
540 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
541 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
543 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
544 /* lie about string lengths, we already verified how many
545 * we have space for above
547 if (lpNetIn->lpLocalName)
549 lpNetOut->lpLocalName = strNext;
550 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
551 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
553 if (lpNetIn->lpRemoteName)
555 lpNetOut->lpRemoteName = strNext;
556 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
557 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
559 if (lpNetIn->lpComment)
561 lpNetOut->lpComment = strNext;
562 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
563 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
565 if (lpNetIn->lpProvider)
567 lpNetOut->lpProvider = strNext;
568 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
569 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
572 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
573 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
574 *lpcCount, ret);
575 return ret;
578 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
579 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
580 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
581 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
582 * if not all members of the array could be thunked, and something else on
583 * failure.
585 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
586 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
588 DWORD i, numToThunk, totalBytes, ret;
589 LPWSTR strNext;
591 if (!lpNetArrayIn)
592 return WN_BAD_POINTER;
593 if (!lpcCount)
594 return WN_BAD_POINTER;
595 if (*lpcCount == -1)
596 return WN_BAD_VALUE;
597 if (!lpBuffer)
598 return WN_BAD_POINTER;
599 if (!lpBufferSize)
600 return WN_BAD_POINTER;
602 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
604 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
606 totalBytes += sizeof(NETRESOURCEW);
607 if (lpNet->lpLocalName)
608 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
609 -1, NULL, 0) * sizeof(WCHAR);
610 if (lpNet->lpRemoteName)
611 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
612 -1, NULL, 0) * sizeof(WCHAR);
613 if (lpNet->lpComment)
614 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
615 -1, NULL, 0) * sizeof(WCHAR);
616 if (lpNet->lpProvider)
617 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
618 -1, NULL, 0) * sizeof(WCHAR);
619 if (totalBytes < *lpBufferSize)
620 numToThunk = i + 1;
622 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
623 for (i = 0; i < numToThunk; i++)
625 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
626 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
628 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
629 /* lie about string lengths, we already verified how many
630 * we have space for above
632 if (lpNetIn->lpLocalName)
634 lpNetOut->lpLocalName = strNext;
635 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
636 -1, lpNetOut->lpLocalName, *lpBufferSize);
638 if (lpNetIn->lpRemoteName)
640 lpNetOut->lpRemoteName = strNext;
641 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
642 -1, lpNetOut->lpRemoteName, *lpBufferSize);
644 if (lpNetIn->lpComment)
646 lpNetOut->lpComment = strNext;
647 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
648 -1, lpNetOut->lpComment, *lpBufferSize);
650 if (lpNetIn->lpProvider)
652 lpNetOut->lpProvider = strNext;
653 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
654 -1, lpNetOut->lpProvider, *lpBufferSize);
657 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
658 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
659 *lpcCount, ret);
660 return ret;
663 /*********************************************************************
664 * WNetOpenEnumA [MPR.@]
666 * See comments for WNetOpenEnumW.
668 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
669 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
671 DWORD ret;
673 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
674 dwScope, dwType, dwUsage, lpNet, lphEnum );
676 if (!lphEnum)
677 ret = WN_BAD_POINTER;
678 else if (!providerTable || providerTable->numProviders == 0)
680 *lphEnum = NULL;
681 ret = WN_NO_NETWORK;
683 else
685 if (lpNet)
687 LPNETRESOURCEW lpNetWide = NULL;
688 BYTE buf[1024];
689 DWORD size = sizeof(buf), count = 1;
690 BOOL allocated = FALSE;
692 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
693 if (ret == WN_MORE_DATA)
695 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
696 size);
697 if (lpNetWide)
699 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
700 &size);
701 allocated = TRUE;
703 else
704 ret = WN_OUT_OF_MEMORY;
706 else if (ret == WN_SUCCESS)
707 lpNetWide = (LPNETRESOURCEW)buf;
708 if (ret == WN_SUCCESS)
709 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
710 lphEnum);
711 if (allocated)
712 HeapFree(GetProcessHeap(), 0, lpNetWide);
714 else
715 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
717 if (ret)
718 SetLastError(ret);
719 TRACE("Returning %d\n", ret);
720 return ret;
723 /*********************************************************************
724 * WNetOpenEnumW [MPR.@]
726 * Network enumeration has way too many parameters, so I'm not positive I got
727 * them right. What I've got so far:
729 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
730 * all the network providers should be enumerated.
732 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
733 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
734 * lpProvider is set, all the network providers should be enumerated.
735 * (This means the enumeration is a list of network providers, not that the
736 * enumeration is passed on to the providers.)
738 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
739 * resource matches the "Entire Network" resource (no remote name, no
740 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
741 * enumeration is done on every network provider.
743 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
744 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
745 * only to the given network provider.
747 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
748 * no lpProvider is set, enumeration will be tried on every network provider,
749 * in the order in which they're loaded.
751 * - The LPNETRESOURCE should be disregarded for scopes besides
752 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
753 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
755 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
756 * resource in the enumerated list, as well as any machines in your
757 * workgroup. The machines in your workgroup come from doing a
758 * RESOURCE_CONTEXT enumeration of every Network Provider.
760 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
761 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
763 DWORD ret;
765 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
766 dwScope, dwType, dwUsage, lpNet, lphEnum );
768 if (!lphEnum)
769 ret = WN_BAD_POINTER;
770 else if (!providerTable || providerTable->numProviders == 0)
772 *lphEnum = NULL;
773 ret = WN_NO_NETWORK;
775 else
777 switch (dwScope)
779 case RESOURCE_GLOBALNET:
780 if (lpNet)
782 if (lpNet->lpProvider)
784 DWORD index = _findProviderIndexW(lpNet->lpProvider);
786 if (index != BAD_PROVIDER_INDEX)
788 if (providerTable->table[index].openEnum &&
789 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
791 HANDLE handle;
792 PWSTR RemoteName = lpNet->lpRemoteName;
794 if ((lpNet->dwUsage & RESOURCEUSAGE_CONTAINER) &&
795 RemoteName && !strcmpW(RemoteName, lpNet->lpProvider))
796 lpNet->lpRemoteName = NULL;
798 ret = providerTable->table[index].openEnum(
799 dwScope, dwType, dwUsage, lpNet, &handle);
800 if (ret == WN_SUCCESS)
802 *lphEnum = _createProviderEnumerator(
803 dwScope, dwType, dwUsage, index, handle);
804 ret = *lphEnum ? WN_SUCCESS :
805 WN_OUT_OF_MEMORY;
808 lpNet->lpRemoteName = RemoteName;
810 else
811 ret = WN_NOT_SUPPORTED;
813 else
814 ret = WN_BAD_PROVIDER;
816 else if (lpNet->lpRemoteName)
818 *lphEnum = _createGlobalEnumeratorW(dwScope,
819 dwType, dwUsage, lpNet);
820 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
822 else
824 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
825 providerTable->entireNetwork))
827 /* comment matches the "Entire Network", enumerate
828 * global scope of every provider
830 *lphEnum = _createGlobalEnumeratorW(dwScope,
831 dwType, dwUsage, lpNet);
833 else
835 /* this is the same as not having passed lpNet */
836 *lphEnum = _createGlobalEnumeratorW(dwScope,
837 dwType, dwUsage, NULL);
839 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
842 else
844 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
845 dwUsage, lpNet);
846 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
848 break;
849 case RESOURCE_CONTEXT:
850 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
851 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
852 break;
853 case RESOURCE_CONNECTED:
854 *lphEnum = _createConnectedEnumerator(dwScope, dwType, dwUsage);
855 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
856 break;
857 case RESOURCE_REMEMBERED:
858 *lphEnum = _createNullEnumerator();
859 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
860 break;
861 default:
862 WARN("unknown scope 0x%08x\n", dwScope);
863 ret = WN_BAD_VALUE;
866 if (ret)
867 SetLastError(ret);
868 TRACE("Returning %d\n", ret);
869 return ret;
872 /*********************************************************************
873 * WNetEnumResourceA [MPR.@]
875 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
876 LPVOID lpBuffer, LPDWORD lpBufferSize )
878 DWORD ret;
880 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
882 if (!hEnum)
883 ret = WN_BAD_POINTER;
884 else if (!lpcCount)
885 ret = WN_BAD_POINTER;
886 else if (!lpBuffer)
887 ret = WN_BAD_POINTER;
888 else if (!lpBufferSize)
889 ret = WN_BAD_POINTER;
890 else if (*lpBufferSize < sizeof(NETRESOURCEA))
892 *lpBufferSize = sizeof(NETRESOURCEA);
893 ret = WN_MORE_DATA;
895 else
897 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
898 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
900 if (localBuffer)
902 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
903 &localSize);
904 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
906 /* FIXME: this isn't necessarily going to work in the case of
907 * WN_MORE_DATA, because our enumerator may have moved on to
908 * the next provider. MSDN states that a large (16KB) buffer
909 * size is the appropriate usage of this function, so
910 * hopefully it won't be an issue.
912 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
913 lpBuffer, lpBufferSize);
914 *lpcCount = localCount;
916 HeapFree(GetProcessHeap(), 0, localBuffer);
918 else
919 ret = WN_OUT_OF_MEMORY;
921 if (ret)
922 SetLastError(ret);
923 TRACE("Returning %d\n", ret);
924 return ret;
927 static DWORD _countProviderBytesW(PWNetProvider provider)
929 DWORD ret;
931 if (provider)
933 ret = sizeof(NETRESOURCEW);
934 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
936 else
937 ret = 0;
938 return ret;
941 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
942 LPVOID lpBuffer, const DWORD *lpBufferSize)
944 DWORD ret;
946 if (!enumerator)
947 return WN_BAD_POINTER;
948 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
949 return WN_BAD_VALUE;
950 if (!lpcCount)
951 return WN_BAD_POINTER;
952 if (!lpBuffer)
953 return WN_BAD_POINTER;
954 if (!lpBufferSize)
955 return WN_BAD_POINTER;
956 if (*lpBufferSize < sizeof(NETRESOURCEA))
957 return WN_MORE_DATA;
959 if (!providerTable || enumerator->providerIndex >=
960 providerTable->numProviders)
961 ret = WN_NO_MORE_ENTRIES;
962 else
964 DWORD bytes = 0, count = 0, countLimit, i;
965 LPNETRESOURCEW resource;
966 LPWSTR strNext;
968 countLimit = *lpcCount == -1 ?
969 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
970 while (count < countLimit && bytes < *lpBufferSize)
972 DWORD bytesNext = _countProviderBytesW(
973 &providerTable->table[count + enumerator->providerIndex]);
975 if (bytes + bytesNext < *lpBufferSize)
977 bytes += bytesNext;
978 count++;
981 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
982 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
984 resource->dwScope = RESOURCE_GLOBALNET;
985 resource->dwType = RESOURCETYPE_ANY;
986 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
987 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
988 RESOURCEUSAGE_RESERVED;
989 resource->lpLocalName = NULL;
990 resource->lpRemoteName = strNext;
991 strcpyW(resource->lpRemoteName,
992 providerTable->table[i + enumerator->providerIndex].name);
993 strNext += strlenW(resource->lpRemoteName) + 1;
994 resource->lpComment = NULL;
995 resource->lpProvider = strNext;
996 strcpyW(resource->lpProvider,
997 providerTable->table[i + enumerator->providerIndex].name);
998 strNext += strlenW(resource->lpProvider) + 1;
1000 enumerator->providerIndex += count;
1001 *lpcCount = count;
1002 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
1004 TRACE("Returning %d\n", ret);
1005 return ret;
1008 /* Advances the enumerator (assumed to be a global enumerator) to the next
1009 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1010 * not open a handle with the next provider.
1011 * If the existing handle is NULL, may leave the enumerator unchanged, since
1012 * the current provider may support the desired scope.
1013 * If the existing handle is not NULL, closes it before moving on.
1014 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1015 * provider, and another error on failure.
1017 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
1019 if (!enumerator)
1020 return WN_BAD_POINTER;
1021 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1022 return WN_BAD_VALUE;
1023 if (!providerTable || enumerator->providerIndex >=
1024 providerTable->numProviders)
1025 return WN_NO_MORE_ENTRIES;
1027 if (enumerator->providerDone)
1029 DWORD dwEnum = 0;
1030 enumerator->providerDone = FALSE;
1031 if (enumerator->handle)
1033 providerTable->table[enumerator->providerIndex].closeEnum(
1034 enumerator->handle);
1035 enumerator->handle = NULL;
1036 enumerator->providerIndex++;
1038 if (enumerator->dwScope == RESOURCE_CONNECTED)
1039 dwEnum = WNNC_ENUM_LOCAL;
1040 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
1041 dwEnum = WNNC_ENUM_GLOBAL;
1042 else if (enumerator->dwScope == RESOURCE_CONTEXT)
1043 dwEnum = WNNC_ENUM_CONTEXT;
1044 for (; enumerator->providerIndex < providerTable->numProviders &&
1045 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
1046 & dwEnum); enumerator->providerIndex++)
1049 return enumerator->providerIndex < providerTable->numProviders ?
1050 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1053 /* "Passes through" call to the next provider that supports the enumeration
1054 * type.
1055 * FIXME: if one call to a provider's enumerator succeeds while there's still
1056 * space in lpBuffer, I don't call to the next provider. The caller may not
1057 * expect that it should call EnumResourceW again with a return value of
1058 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1059 * may have to be moved around a bit, ick.
1061 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1062 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1064 DWORD ret;
1066 if (!enumerator)
1067 return WN_BAD_POINTER;
1068 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1069 return WN_BAD_VALUE;
1070 if (!lpcCount)
1071 return WN_BAD_POINTER;
1072 if (!lpBuffer)
1073 return WN_BAD_POINTER;
1074 if (!lpBufferSize)
1075 return WN_BAD_POINTER;
1076 if (*lpBufferSize < sizeof(NETRESOURCEW))
1077 return WN_MORE_DATA;
1079 ret = _globalEnumeratorAdvance(enumerator);
1080 if (ret == WN_SUCCESS)
1082 ret = providerTable->table[enumerator->providerIndex].
1083 openEnum(enumerator->dwScope, enumerator->dwType,
1084 enumerator->dwUsage, enumerator->specific.net,
1085 &enumerator->handle);
1086 if (ret == WN_SUCCESS)
1088 ret = providerTable->table[enumerator->providerIndex].
1089 enumResource(enumerator->handle, lpcCount, lpBuffer,
1090 lpBufferSize);
1091 if (ret != WN_MORE_DATA)
1092 enumerator->providerDone = TRUE;
1095 TRACE("Returning %d\n", ret);
1096 return ret;
1099 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1100 LPVOID lpBuffer, LPDWORD lpBufferSize)
1102 DWORD ret;
1104 if (!enumerator)
1105 return WN_BAD_POINTER;
1106 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1107 return WN_BAD_VALUE;
1108 if (!lpcCount)
1109 return WN_BAD_POINTER;
1110 if (!lpBuffer)
1111 return WN_BAD_POINTER;
1112 if (!lpBufferSize)
1113 return WN_BAD_POINTER;
1114 if (*lpBufferSize < sizeof(NETRESOURCEW))
1115 return WN_MORE_DATA;
1116 if (!providerTable)
1117 return WN_NO_NETWORK;
1119 switch (enumerator->dwScope)
1121 case RESOURCE_GLOBALNET:
1122 if (enumerator->specific.net)
1123 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1124 lpBuffer, lpBufferSize);
1125 else
1126 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1127 lpBufferSize);
1128 break;
1129 case RESOURCE_CONTEXT:
1130 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1131 lpBufferSize);
1132 break;
1133 default:
1134 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1135 ret = WN_NO_MORE_ENTRIES;
1137 TRACE("Returning %d\n", ret);
1138 return ret;
1141 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1142 LPVOID lpBuffer, LPDWORD lpBufferSize)
1144 if (!enumerator)
1145 return WN_BAD_POINTER;
1146 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1147 return WN_BAD_VALUE;
1148 if (!enumerator->handle)
1149 return WN_BAD_VALUE;
1150 if (!lpcCount)
1151 return WN_BAD_POINTER;
1152 if (!lpBuffer)
1153 return WN_BAD_POINTER;
1154 if (!lpBufferSize)
1155 return WN_BAD_POINTER;
1156 if (!providerTable)
1157 return WN_NO_NETWORK;
1158 if (enumerator->providerIndex >= providerTable->numProviders)
1159 return WN_NO_MORE_ENTRIES;
1160 if (!providerTable->table[enumerator->providerIndex].enumResource)
1161 return WN_BAD_VALUE;
1162 return providerTable->table[enumerator->providerIndex].enumResource(
1163 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1166 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1167 LPVOID lpBuffer, LPDWORD lpBufferSize)
1169 DWORD ret;
1170 size_t cchEntireNetworkLen, bytesNeeded;
1172 if (!enumerator)
1173 return WN_BAD_POINTER;
1174 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1175 return WN_BAD_VALUE;
1176 if (!lpcCount)
1177 return WN_BAD_POINTER;
1178 if (!lpBuffer)
1179 return WN_BAD_POINTER;
1180 if (!lpBufferSize)
1181 return WN_BAD_POINTER;
1182 if (!providerTable)
1183 return WN_NO_NETWORK;
1185 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1186 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1187 if (*lpBufferSize < bytesNeeded)
1189 *lpBufferSize = bytesNeeded;
1190 ret = WN_MORE_DATA;
1192 else
1194 LPNETRESOURCEW lpNet = lpBuffer;
1196 lpNet->dwScope = RESOURCE_GLOBALNET;
1197 lpNet->dwType = enumerator->dwType;
1198 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1199 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1200 lpNet->lpLocalName = NULL;
1201 lpNet->lpRemoteName = NULL;
1202 lpNet->lpProvider = NULL;
1203 /* odd, but correct: put comment at end of buffer, so it won't get
1204 * overwritten by subsequent calls to a provider's enumResource
1206 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1207 (cchEntireNetworkLen * sizeof(WCHAR)));
1208 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1209 ret = WN_SUCCESS;
1211 if (ret == WN_SUCCESS)
1213 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1215 /* "Entire Network" entry enumerated--morph this into a global
1216 * enumerator. enumerator->lpNet continues to be NULL, since it has
1217 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1219 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1220 ret = _enumerateGlobalW(enumerator, lpcCount,
1221 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1222 if (ret == WN_SUCCESS)
1224 /* reflect the fact that we already enumerated "Entire Network" */
1225 (*lpcCount)++;
1226 *lpBufferSize = bufferSize + bytesNeeded;
1228 else
1230 /* the provider enumeration failed, but we already succeeded in
1231 * enumerating "Entire Network"--leave type as global to allow a
1232 * retry, but indicate success with a count of one.
1234 ret = WN_SUCCESS;
1235 *lpcCount = 1;
1236 *lpBufferSize = bytesNeeded;
1239 TRACE("Returning %d\n", ret);
1240 return ret;
1243 static DWORD _copyStringToEnumW(const WCHAR *source, DWORD* left, void** end)
1245 DWORD len;
1246 WCHAR* local = *end;
1248 len = strlenW(source) + 1;
1249 len *= sizeof(WCHAR);
1250 if (*left < len)
1251 return WN_MORE_DATA;
1253 local -= (len / sizeof(WCHAR));
1254 memcpy(local, source, len);
1255 *left -= len;
1256 *end = local;
1258 return WN_SUCCESS;
1261 static DWORD _enumerateConnectedW(PWNetEnumerator enumerator, DWORD* user_count,
1262 void* user_buffer, DWORD* user_size)
1264 DWORD ret, index, count, size, i, left;
1265 void* end;
1266 NETRESOURCEW* curr, * buffer;
1267 HANDLE* handles;
1269 if (!enumerator)
1270 return WN_BAD_POINTER;
1271 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONNECTED)
1272 return WN_BAD_VALUE;
1273 if (!user_count || !user_buffer || !user_size)
1274 return WN_BAD_POINTER;
1275 if (!providerTable)
1276 return WN_NO_NETWORK;
1278 handles = enumerator->specific.handles;
1279 left = *user_size;
1280 size = *user_size;
1281 buffer = HeapAlloc(GetProcessHeap(), 0, *user_size);
1282 if (!buffer)
1283 return WN_NO_NETWORK;
1285 curr = user_buffer;
1286 end = (char *)user_buffer + size;
1287 count = *user_count;
1289 ret = WN_NO_MORE_ENTRIES;
1290 for (index = 0; index < providerTable->numProviders; index++)
1292 if (providerTable->table[index].dwEnumScopes)
1294 if (handles[index] == 0)
1296 ret = providerTable->table[index].openEnum(enumerator->dwScope,
1297 enumerator->dwType,
1298 enumerator->dwUsage,
1299 NULL, &handles[index]);
1300 if (ret != WN_SUCCESS)
1301 continue;
1304 ret = providerTable->table[index].enumResource(handles[index],
1305 &count, buffer,
1306 &size);
1307 if (ret == WN_MORE_DATA)
1308 break;
1310 if (ret == WN_SUCCESS)
1312 for (i = 0; i < count; ++i)
1314 if (left < sizeof(NETRESOURCEW))
1316 ret = WN_MORE_DATA;
1317 break;
1320 memcpy(curr, &buffer[i], sizeof(NETRESOURCEW));
1321 left -= sizeof(NETRESOURCEW);
1323 ret = _copyStringToEnumW(buffer[i].lpLocalName, &left, &end);
1324 if (ret == WN_MORE_DATA)
1325 break;
1326 curr->lpLocalName = end;
1328 ret = _copyStringToEnumW(buffer[i].lpRemoteName, &left, &end);
1329 if (ret == WN_MORE_DATA)
1330 break;
1331 curr->lpRemoteName = end;
1333 ret = _copyStringToEnumW(buffer[i].lpProvider, &left, &end);
1334 if (ret == WN_MORE_DATA)
1335 break;
1336 curr->lpProvider = end;
1338 ++curr;
1341 count = *user_count - count;
1342 size = left;
1345 if (ret != WN_SUCCESS || count == 0)
1346 break;
1350 if (count == 0)
1351 ret = WN_NO_MORE_ENTRIES;
1353 *user_count = *user_count - count;
1354 if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
1355 ret = WN_SUCCESS;
1357 HeapFree(GetProcessHeap(), 0, buffer);
1359 TRACE("Returning %d\n", ret);
1360 return ret;
1363 /*********************************************************************
1364 * WNetEnumResourceW [MPR.@]
1366 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1367 LPVOID lpBuffer, LPDWORD lpBufferSize )
1369 DWORD ret;
1371 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1373 if (!hEnum)
1374 ret = WN_BAD_POINTER;
1375 else if (!lpcCount)
1376 ret = WN_BAD_POINTER;
1377 else if (!lpBuffer)
1378 ret = WN_BAD_POINTER;
1379 else if (!lpBufferSize)
1380 ret = WN_BAD_POINTER;
1381 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1383 *lpBufferSize = sizeof(NETRESOURCEW);
1384 ret = WN_MORE_DATA;
1386 else
1388 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1390 switch (enumerator->enumType)
1392 case WNET_ENUMERATOR_TYPE_NULL:
1393 ret = WN_NO_MORE_ENTRIES;
1394 break;
1395 case WNET_ENUMERATOR_TYPE_GLOBAL:
1396 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1397 lpBufferSize);
1398 break;
1399 case WNET_ENUMERATOR_TYPE_PROVIDER:
1400 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1401 lpBufferSize);
1402 break;
1403 case WNET_ENUMERATOR_TYPE_CONTEXT:
1404 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1405 lpBufferSize);
1406 break;
1407 case WNET_ENUMERATOR_TYPE_CONNECTED:
1408 ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer,
1409 lpBufferSize);
1410 break;
1411 default:
1412 WARN("bogus enumerator type!\n");
1413 ret = WN_NO_NETWORK;
1416 if (ret)
1417 SetLastError(ret);
1418 TRACE("Returning %d\n", ret);
1419 return ret;
1422 /*********************************************************************
1423 * WNetCloseEnum [MPR.@]
1425 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1427 DWORD ret, index;
1428 HANDLE *handles;
1430 TRACE( "(%p)\n", hEnum );
1432 if (hEnum)
1434 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1436 switch (enumerator->enumType)
1438 case WNET_ENUMERATOR_TYPE_NULL:
1439 ret = WN_SUCCESS;
1440 break;
1441 case WNET_ENUMERATOR_TYPE_GLOBAL:
1442 if (enumerator->specific.net)
1443 _freeEnumNetResource(enumerator->specific.net);
1444 if (enumerator->handle)
1445 providerTable->table[enumerator->providerIndex].
1446 closeEnum(enumerator->handle);
1447 ret = WN_SUCCESS;
1448 break;
1449 case WNET_ENUMERATOR_TYPE_PROVIDER:
1450 if (enumerator->handle)
1451 providerTable->table[enumerator->providerIndex].
1452 closeEnum(enumerator->handle);
1453 ret = WN_SUCCESS;
1454 break;
1455 case WNET_ENUMERATOR_TYPE_CONNECTED:
1456 handles = enumerator->specific.handles;
1457 for (index = 0; index < providerTable->numProviders; index++)
1459 if (providerTable->table[index].dwEnumScopes && handles[index])
1460 providerTable->table[index].closeEnum(handles[index]);
1462 HeapFree(GetProcessHeap(), 0, handles);
1463 ret = WN_SUCCESS;
1464 break;
1465 default:
1466 WARN("bogus enumerator type!\n");
1467 ret = WN_BAD_HANDLE;
1469 HeapFree(GetProcessHeap(), 0, hEnum);
1471 else
1472 ret = WN_BAD_HANDLE;
1473 if (ret)
1474 SetLastError(ret);
1475 TRACE("Returning %d\n", ret);
1476 return ret;
1479 /*********************************************************************
1480 * WNetGetResourceInformationA [MPR.@]
1482 * See WNetGetResourceInformationW
1484 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1485 LPVOID lpBuffer, LPDWORD cbBuffer,
1486 LPSTR *lplpSystem )
1488 DWORD ret;
1490 TRACE( "(%p, %p, %p, %p)\n",
1491 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1493 if (!providerTable || providerTable->numProviders == 0)
1494 ret = WN_NO_NETWORK;
1495 else if (lpNetResource)
1497 LPNETRESOURCEW lpNetResourceW = NULL;
1498 DWORD size = 1024, count = 1;
1499 DWORD len;
1501 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1502 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1503 if (ret == WN_MORE_DATA)
1505 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1506 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1507 if (lpNetResourceW)
1508 ret = _thunkNetResourceArrayAToW(lpNetResource,
1509 &count, lpNetResourceW, &size);
1510 else
1511 ret = WN_OUT_OF_MEMORY;
1513 if (ret == WN_SUCCESS)
1515 LPWSTR lpSystemW = NULL;
1516 LPVOID lpBufferW;
1517 size = 1024;
1518 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1519 if (lpBufferW)
1521 ret = WNetGetResourceInformationW(lpNetResourceW,
1522 lpBufferW, &size, &lpSystemW);
1523 if (ret == WN_MORE_DATA)
1525 HeapFree(GetProcessHeap(), 0, lpBufferW);
1526 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1527 if (lpBufferW)
1528 ret = WNetGetResourceInformationW(lpNetResourceW,
1529 lpBufferW, &size, &lpSystemW);
1530 else
1531 ret = WN_OUT_OF_MEMORY;
1533 if (ret == WN_SUCCESS)
1535 ret = _thunkNetResourceArrayWToA(lpBufferW,
1536 &count, lpBuffer, cbBuffer);
1537 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1538 lpNetResourceW = lpBufferW;
1539 size = sizeof(NETRESOURCEA);
1540 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1541 -1, NULL, 0, NULL, NULL);
1542 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1543 -1, NULL, 0, NULL, NULL);
1545 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1546 -1, NULL, 0, NULL, NULL);
1547 if ((len) && ( size + len < *cbBuffer))
1549 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1550 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1551 *lplpSystem, len, NULL, NULL);
1552 ret = WN_SUCCESS;
1554 else
1555 ret = WN_MORE_DATA;
1557 else
1558 ret = WN_OUT_OF_MEMORY;
1559 HeapFree(GetProcessHeap(), 0, lpBufferW);
1561 else
1562 ret = WN_OUT_OF_MEMORY;
1563 HeapFree(GetProcessHeap(), 0, lpSystemW);
1565 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1567 else
1568 ret = WN_NO_NETWORK;
1570 if (ret)
1571 SetLastError(ret);
1572 TRACE("Returning %d\n", ret);
1573 return ret;
1576 /*********************************************************************
1577 * WNetGetResourceInformationW [MPR.@]
1579 * WNetGetResourceInformationW function identifies the network provider
1580 * that owns the resource and gets information about the type of the resource.
1582 * PARAMS:
1583 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1584 * defines a network resource.
1585 * lpBuffer [ O] the pointer to buffer, containing result. It
1586 * contains NETRESOURCEW structure and strings to
1587 * which the members of the NETRESOURCEW structure
1588 * point.
1589 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1590 * in bytes.
1591 * lplpSystem [ O] the pointer to string in the output buffer,
1592 * containing the part of the resource name without
1593 * names of the server and share.
1595 * RETURNS:
1596 * NO_ERROR if the function succeeds. System error code if the function fails.
1599 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1600 LPVOID lpBuffer, LPDWORD cbBuffer,
1601 LPWSTR *lplpSystem )
1603 DWORD ret = WN_NO_NETWORK;
1604 DWORD index;
1606 TRACE( "(%p, %p, %p, %p)\n",
1607 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1609 if (!(lpBuffer))
1610 ret = WN_OUT_OF_MEMORY;
1611 else if (providerTable != NULL)
1613 /* FIXME: For function value of a variable is indifferent, it does
1614 * search of all providers in a network.
1616 for (index = 0; index < providerTable->numProviders; index++)
1618 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1619 WNNC_DLG_GETRESOURCEINFORMATION)
1621 if (providerTable->table[index].getResourceInformation)
1622 ret = providerTable->table[index].getResourceInformation(
1623 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1624 else
1625 ret = WN_NO_NETWORK;
1626 if (ret == WN_SUCCESS)
1627 break;
1631 if (ret)
1632 SetLastError(ret);
1633 return ret;
1636 /*********************************************************************
1637 * WNetGetResourceParentA [MPR.@]
1639 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1640 LPVOID lpBuffer, LPDWORD lpBufferSize )
1642 FIXME( "(%p, %p, %p): stub\n",
1643 lpNetResource, lpBuffer, lpBufferSize );
1645 SetLastError(WN_NO_NETWORK);
1646 return WN_NO_NETWORK;
1649 /*********************************************************************
1650 * WNetGetResourceParentW [MPR.@]
1652 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1653 LPVOID lpBuffer, LPDWORD lpBufferSize )
1655 FIXME( "(%p, %p, %p): stub\n",
1656 lpNetResource, lpBuffer, lpBufferSize );
1658 SetLastError(WN_NO_NETWORK);
1659 return WN_NO_NETWORK;
1665 * Connection Functions
1668 /*********************************************************************
1669 * WNetAddConnectionA [MPR.@]
1671 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1672 LPCSTR lpLocalName )
1674 NETRESOURCEA resourcesA;
1676 memset(&resourcesA, 0, sizeof(resourcesA));
1677 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1678 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1679 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1682 /*********************************************************************
1683 * WNetAddConnectionW [MPR.@]
1685 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1686 LPCWSTR lpLocalName )
1688 NETRESOURCEW resourcesW;
1690 memset(&resourcesW, 0, sizeof(resourcesW));
1691 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1692 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1693 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1696 /*********************************************************************
1697 * WNetAddConnection2A [MPR.@]
1699 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1700 LPCSTR lpPassword, LPCSTR lpUserID,
1701 DWORD dwFlags )
1703 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1704 NULL, 0, NULL);
1707 /*********************************************************************
1708 * WNetAddConnection2W [MPR.@]
1710 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1711 LPCWSTR lpPassword, LPCWSTR lpUserID,
1712 DWORD dwFlags )
1714 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1715 NULL, 0, NULL);
1718 /*********************************************************************
1719 * WNetAddConnection3A [MPR.@]
1721 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1722 LPCSTR lpPassword, LPCSTR lpUserID,
1723 DWORD dwFlags )
1725 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1726 dwFlags, NULL, 0, NULL);
1729 /*********************************************************************
1730 * WNetAddConnection3W [MPR.@]
1732 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1733 LPCWSTR lpPassword, LPCWSTR lpUserID,
1734 DWORD dwFlags )
1736 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1737 dwFlags, NULL, 0, NULL);
1740 struct use_connection_context
1742 HWND hwndOwner;
1743 NETRESOURCEW *resource;
1744 NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */
1745 WCHAR *password;
1746 WCHAR *userid;
1747 DWORD flags;
1748 void *accessname;
1749 DWORD *buffer_size;
1750 DWORD *result;
1751 DWORD (*pre_set_accessname)(struct use_connection_context*, WCHAR *);
1752 void (*set_accessname)(struct use_connection_context*, WCHAR *);
1755 static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1757 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1759 DWORD len;
1761 if (local_name)
1762 len = strlenW(local_name);
1763 else
1764 len = strlenW(ctxt->resource->lpRemoteName);
1766 if (++len > *ctxt->buffer_size)
1768 *ctxt->buffer_size = len;
1769 return ERROR_MORE_DATA;
1772 else
1773 ctxt->accessname = NULL;
1775 return ERROR_SUCCESS;
1778 static void use_connection_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1780 WCHAR *accessname = ctxt->accessname;
1781 if (local_name)
1783 strcpyW(accessname, local_name);
1784 if (ctxt->result)
1785 *ctxt->result = CONNECT_LOCALDRIVE;
1787 else
1788 strcpyW(accessname, ctxt->resource->lpRemoteName);
1791 static DWORD wnet_use_provider( struct use_connection_context *ctxt, NETRESOURCEW * netres, WNetProvider *provider, BOOLEAN redirect )
1793 DWORD caps, ret;
1795 caps = provider->getCaps(WNNC_CONNECTION);
1796 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1797 return ERROR_BAD_PROVIDER;
1799 ret = WN_ACCESS_DENIED;
1802 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1803 ret = provider->addConnection3(ctxt->hwndOwner, netres, ctxt->password, ctxt->userid, ctxt->flags);
1804 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1805 ret = provider->addConnection(netres, ctxt->password, ctxt->userid);
1807 if (ret == WN_ALREADY_CONNECTED && redirect)
1808 netres->lpLocalName[0] -= 1;
1809 } while (redirect && ret == WN_ALREADY_CONNECTED && netres->lpLocalName[0] >= 'C');
1811 if (ret == WN_SUCCESS && ctxt->accessname)
1812 ctxt->set_accessname(ctxt, netres->lpLocalName);
1814 return ret;
1817 static DWORD wnet_use_connection( struct use_connection_context *ctxt )
1819 WNetProvider *provider;
1820 DWORD index, ret = WN_NO_NETWORK;
1821 BOOL redirect = FALSE;
1822 WCHAR letter[3] = {'Z', ':', 0};
1823 NETRESOURCEW netres;
1825 if (!providerTable || providerTable->numProviders == 0)
1826 return WN_NO_NETWORK;
1828 if (!ctxt->resource)
1829 return ERROR_INVALID_PARAMETER;
1830 netres = *ctxt->resource;
1832 if (!netres.lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
1834 if (netres.dwType != RESOURCETYPE_DISK && netres.dwType != RESOURCETYPE_PRINT)
1835 return ERROR_BAD_DEV_TYPE;
1837 if (netres.dwType == RESOURCETYPE_PRINT)
1839 FIXME("Local device selection is not implemented for printers.\n");
1840 return WN_NO_NETWORK;
1843 redirect = TRUE;
1844 netres.lpLocalName = letter;
1847 if (ctxt->flags & CONNECT_INTERACTIVE)
1848 return ERROR_BAD_NET_NAME;
1850 if ((ret = ctxt->pre_set_accessname(ctxt, netres.lpLocalName)))
1851 return ret;
1853 if (netres.lpProvider)
1855 index = _findProviderIndexW(netres.lpProvider);
1856 if (index == BAD_PROVIDER_INDEX)
1857 return ERROR_BAD_PROVIDER;
1859 provider = &providerTable->table[index];
1860 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
1862 else
1864 for (index = 0; index < providerTable->numProviders; index++)
1866 provider = &providerTable->table[index];
1867 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
1868 if (ret == WN_SUCCESS || ret == WN_ALREADY_CONNECTED)
1869 break;
1873 return ret;
1876 /*****************************************************************
1877 * WNetUseConnectionW [MPR.@]
1879 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
1880 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
1882 struct use_connection_context ctxt;
1884 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1885 hwndOwner, resource, password, debugstr_w(userid), flags,
1886 accessname, buffer_size, result );
1888 ctxt.hwndOwner = hwndOwner;
1889 ctxt.resource = resource;
1890 ctxt.resourceA = NULL;
1891 ctxt.password = (WCHAR*)password;
1892 ctxt.userid = (WCHAR*)userid;
1893 ctxt.flags = flags;
1894 ctxt.accessname = accessname;
1895 ctxt.buffer_size = buffer_size;
1896 ctxt.result = result;
1897 ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
1898 ctxt.set_accessname = use_connection_set_accessnameW;
1900 return wnet_use_connection(&ctxt);
1903 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
1905 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1907 DWORD len;
1909 if (local_name)
1910 len = WideCharToMultiByte(CP_ACP, 0, local_name, -1, NULL, 0, NULL, NULL) - 1;
1911 else
1912 len = strlen(ctxt->resourceA->lpRemoteName);
1914 if (++len > *ctxt->buffer_size)
1916 *ctxt->buffer_size = len;
1917 return ERROR_MORE_DATA;
1920 else
1921 ctxt->accessname = NULL;
1923 return ERROR_SUCCESS;
1926 static void use_connection_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
1928 char *accessname = ctxt->accessname;
1929 if (local_name)
1931 WideCharToMultiByte(CP_ACP, 0, local_name, -1, accessname, *ctxt->buffer_size, NULL, NULL);
1932 if (ctxt->result)
1933 *ctxt->result = CONNECT_LOCALDRIVE;
1935 else
1936 strcpy(accessname, ctxt->resourceA->lpRemoteName);
1939 static LPWSTR strdupAtoW( LPCSTR str )
1941 LPWSTR ret;
1942 INT len;
1944 if (!str) return NULL;
1945 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
1946 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1947 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
1948 return ret;
1951 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
1953 resourceW->dwScope = resourceA->dwScope;
1954 resourceW->dwType = resourceA->dwType;
1955 resourceW->dwDisplayType = resourceA->dwDisplayType;
1956 resourceW->dwUsage = resourceA->dwUsage;
1957 resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
1958 resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
1959 resourceW->lpComment = strdupAtoW(resourceA->lpComment);
1960 resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
1963 static void free_netresourceW( NETRESOURCEW *resource )
1965 HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
1966 HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
1967 HeapFree(GetProcessHeap(), 0, resource->lpComment);
1968 HeapFree(GetProcessHeap(), 0, resource->lpProvider);
1971 /*****************************************************************
1972 * WNetUseConnectionA [MPR.@]
1974 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
1975 LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
1976 DWORD *buffer_size, DWORD *result )
1978 struct use_connection_context ctxt;
1979 NETRESOURCEW resourceW;
1980 DWORD ret;
1982 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
1983 accessname, buffer_size, result );
1985 netresource_a_to_w(resource, &resourceW);
1987 ctxt.hwndOwner = hwndOwner;
1988 ctxt.resource = &resourceW;
1989 ctxt.resourceA = resource;
1990 ctxt.password = strdupAtoW(password);
1991 ctxt.userid = strdupAtoW(userid);
1992 ctxt.flags = flags;
1993 ctxt.accessname = accessname;
1994 ctxt.buffer_size = buffer_size;
1995 ctxt.result = result;
1996 ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
1997 ctxt.set_accessname = use_connection_set_accessnameA;
1999 ret = wnet_use_connection(&ctxt);
2001 free_netresourceW(&resourceW);
2002 HeapFree(GetProcessHeap(), 0, ctxt.password);
2003 HeapFree(GetProcessHeap(), 0, ctxt.userid);
2005 return ret;
2008 /*********************************************************************
2009 * WNetCancelConnectionA [MPR.@]
2011 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
2013 return WNetCancelConnection2A(lpName, 0, fForce);
2016 /*********************************************************************
2017 * WNetCancelConnectionW [MPR.@]
2019 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
2021 return WNetCancelConnection2W(lpName, 0, fForce);
2024 /*********************************************************************
2025 * WNetCancelConnection2A [MPR.@]
2027 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
2029 DWORD ret;
2030 WCHAR * name = strdupAtoW(lpName);
2031 if (!name)
2032 return ERROR_NOT_CONNECTED;
2034 ret = WNetCancelConnection2W(name, dwFlags, fForce);
2035 HeapFree(GetProcessHeap(), 0, name);
2037 return ret;
2040 /*********************************************************************
2041 * WNetCancelConnection2W [MPR.@]
2043 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
2045 DWORD ret = WN_NO_NETWORK;
2046 DWORD index;
2048 if (providerTable != NULL)
2050 for (index = 0; index < providerTable->numProviders; index++)
2052 if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2053 WNNC_CON_CANCELCONNECTION)
2055 if (providerTable->table[index].cancelConnection)
2056 ret = providerTable->table[index].cancelConnection((LPWSTR)lpName, fForce);
2057 else
2058 ret = WN_NO_NETWORK;
2059 if (ret == WN_SUCCESS || ret == WN_OPEN_FILES)
2060 break;
2064 return ret;
2067 /*****************************************************************
2068 * WNetRestoreConnectionA [MPR.@]
2070 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
2072 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
2074 SetLastError(WN_NO_NETWORK);
2075 return WN_NO_NETWORK;
2078 /*****************************************************************
2079 * WNetRestoreConnectionW [MPR.@]
2081 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
2083 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
2085 SetLastError(WN_NO_NETWORK);
2086 return WN_NO_NETWORK;
2089 /**************************************************************************
2090 * WNetGetConnectionA [MPR.@]
2092 * RETURNS
2093 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2094 * - WN_NOT_CONNECTED drive is a local drive
2095 * - WN_MORE_DATA buffer isn't big enough
2096 * - WN_SUCCESS success (net path in buffer)
2098 * FIXME: need to test return values under different errors
2100 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
2101 LPSTR lpRemoteName, LPDWORD lpBufferSize )
2103 DWORD ret;
2105 if (!lpLocalName)
2106 ret = WN_BAD_POINTER;
2107 else if (!lpBufferSize)
2108 ret = WN_BAD_POINTER;
2109 else if (!lpRemoteName && *lpBufferSize)
2110 ret = WN_BAD_POINTER;
2111 else
2113 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
2115 if (len)
2117 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2119 if (wideLocalName)
2121 WCHAR wideRemoteStatic[MAX_PATH];
2122 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
2124 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
2126 /* try once without memory allocation */
2127 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
2128 &wideRemoteSize);
2129 if (ret == WN_SUCCESS)
2131 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2132 -1, NULL, 0, NULL, NULL);
2134 if (len <= *lpBufferSize)
2136 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
2137 lpRemoteName, *lpBufferSize, NULL, NULL);
2138 ret = WN_SUCCESS;
2140 else
2142 *lpBufferSize = len;
2143 ret = WN_MORE_DATA;
2146 else if (ret == WN_MORE_DATA)
2148 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
2149 wideRemoteSize * sizeof(WCHAR));
2151 if (wideRemote)
2153 ret = WNetGetConnectionW(wideLocalName, wideRemote,
2154 &wideRemoteSize);
2155 if (ret == WN_SUCCESS)
2157 if (len <= *lpBufferSize)
2159 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2160 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
2161 ret = WN_SUCCESS;
2163 else
2165 *lpBufferSize = len;
2166 ret = WN_MORE_DATA;
2169 HeapFree(GetProcessHeap(), 0, wideRemote);
2171 else
2172 ret = WN_OUT_OF_MEMORY;
2174 HeapFree(GetProcessHeap(), 0, wideLocalName);
2176 else
2177 ret = WN_OUT_OF_MEMORY;
2179 else
2180 ret = WN_BAD_LOCALNAME;
2182 if (ret)
2183 SetLastError(ret);
2184 TRACE("Returning %d\n", ret);
2185 return ret;
2188 /* find the network connection for a given drive; helper for WNetGetConnection */
2189 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
2191 char buffer[1024];
2192 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
2193 HANDLE mgr;
2194 DWORD ret = WN_NOT_CONNECTED;
2195 DWORD bytes_returned;
2197 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
2198 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
2199 0, 0 )) == INVALID_HANDLE_VALUE)
2201 ERR( "failed to open mount manager err %u\n", GetLastError() );
2202 return ret;
2204 memset( data, 0, sizeof(*data) );
2205 data->letter = letter;
2206 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
2207 data, sizeof(buffer), &bytes_returned, NULL ))
2209 char *p, *mount_point = buffer + data->mount_point_offset;
2210 DWORD len;
2212 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
2214 mount_point += 2;
2215 mount_point[0] = '\\';
2216 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
2218 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
2219 if (len > *size)
2221 *size = len;
2222 ret = WN_MORE_DATA;
2224 else
2226 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
2227 ret = WN_SUCCESS;
2231 CloseHandle( mgr );
2232 return ret;
2235 /**************************************************************************
2236 * WNetGetConnectionW [MPR.@]
2238 * FIXME: need to test return values under different errors
2240 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
2241 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
2243 DWORD ret;
2245 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
2246 lpBufferSize);
2248 if (!lpLocalName)
2249 ret = WN_BAD_POINTER;
2250 else if (!lpBufferSize)
2251 ret = WN_BAD_POINTER;
2252 else if (!lpRemoteName && *lpBufferSize)
2253 ret = WN_BAD_POINTER;
2254 else if (!lpLocalName[0])
2255 ret = WN_BAD_LOCALNAME;
2256 else
2258 if (lpLocalName[1] == ':')
2260 switch(GetDriveTypeW(lpLocalName))
2262 case DRIVE_REMOTE:
2263 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
2264 break;
2265 case DRIVE_REMOVABLE:
2266 case DRIVE_FIXED:
2267 case DRIVE_CDROM:
2268 TRACE("file is local\n");
2269 ret = WN_NOT_CONNECTED;
2270 break;
2271 default:
2272 ret = WN_BAD_LOCALNAME;
2275 else
2276 ret = WN_BAD_LOCALNAME;
2278 if (ret)
2279 SetLastError(ret);
2280 TRACE("Returning %d\n", ret);
2281 return ret;
2284 /**************************************************************************
2285 * WNetSetConnectionA [MPR.@]
2287 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
2288 LPVOID pvValue )
2290 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
2292 SetLastError(WN_NO_NETWORK);
2293 return WN_NO_NETWORK;
2296 /**************************************************************************
2297 * WNetSetConnectionW [MPR.@]
2299 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2300 LPVOID pvValue )
2302 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2304 SetLastError(WN_NO_NETWORK);
2305 return WN_NO_NETWORK;
2308 /*****************************************************************
2309 * WNetGetUniversalNameA [MPR.@]
2311 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2312 LPVOID lpBuffer, LPDWORD lpBufferSize )
2314 DWORD err, size;
2316 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2317 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2319 switch (dwInfoLevel)
2321 case UNIVERSAL_NAME_INFO_LEVEL:
2323 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2325 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2327 err = ERROR_NOT_CONNECTED;
2328 break;
2331 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2332 if (*lpBufferSize < size)
2334 err = WN_MORE_DATA;
2335 break;
2337 info->lpUniversalName = (char *)info + sizeof(*info);
2338 lstrcpyA(info->lpUniversalName, lpLocalPath);
2339 err = WN_NO_ERROR;
2340 break;
2342 case REMOTE_NAME_INFO_LEVEL:
2343 err = WN_NO_NETWORK;
2344 break;
2346 default:
2347 err = WN_BAD_VALUE;
2348 break;
2351 SetLastError(err);
2352 return err;
2355 /*****************************************************************
2356 * WNetGetUniversalNameW [MPR.@]
2358 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2359 LPVOID lpBuffer, LPDWORD lpBufferSize )
2361 DWORD err, size;
2363 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2364 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2366 switch (dwInfoLevel)
2368 case UNIVERSAL_NAME_INFO_LEVEL:
2370 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2372 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2374 err = ERROR_NOT_CONNECTED;
2375 break;
2378 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2379 if (*lpBufferSize < size)
2381 err = WN_MORE_DATA;
2382 break;
2384 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2385 lstrcpyW(info->lpUniversalName, lpLocalPath);
2386 err = WN_NO_ERROR;
2387 break;
2389 case REMOTE_NAME_INFO_LEVEL:
2390 err = WN_NO_NETWORK;
2391 break;
2393 default:
2394 err = WN_BAD_VALUE;
2395 break;
2398 if (err != WN_NO_ERROR) SetLastError(err);
2399 return err;
2405 * Other Functions
2408 /**************************************************************************
2409 * WNetGetUserA [MPR.@]
2411 * FIXME: we should not return ourselves, but the owner of the drive lpName
2413 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2415 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2416 return GetLastError();
2419 /*****************************************************************
2420 * WNetGetUserW [MPR.@]
2422 * FIXME: we should not return ourselves, but the owner of the drive lpName
2424 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2426 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2427 return GetLastError();
2430 /*********************************************************************
2431 * WNetConnectionDialog [MPR.@]
2433 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2435 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2437 SetLastError(WN_NO_NETWORK);
2438 return WN_NO_NETWORK;
2441 /*********************************************************************
2442 * WNetConnectionDialog1A [MPR.@]
2444 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2446 FIXME( "(%p): stub\n", lpConnDlgStruct );
2448 SetLastError(WN_NO_NETWORK);
2449 return WN_NO_NETWORK;
2452 /*********************************************************************
2453 * WNetConnectionDialog1W [MPR.@]
2455 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2457 FIXME( "(%p): stub\n", lpConnDlgStruct );
2459 SetLastError(WN_NO_NETWORK);
2460 return WN_NO_NETWORK;
2463 /*********************************************************************
2464 * WNetDisconnectDialog [MPR.@]
2466 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2468 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2470 SetLastError(WN_NO_NETWORK);
2471 return WN_NO_NETWORK;
2474 /*********************************************************************
2475 * WNetDisconnectDialog1A [MPR.@]
2477 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2479 FIXME( "(%p): stub\n", lpConnDlgStruct );
2481 SetLastError(WN_NO_NETWORK);
2482 return WN_NO_NETWORK;
2485 /*********************************************************************
2486 * WNetDisconnectDialog1W [MPR.@]
2488 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2490 FIXME( "(%p): stub\n", lpConnDlgStruct );
2492 SetLastError(WN_NO_NETWORK);
2493 return WN_NO_NETWORK;
2496 /*********************************************************************
2497 * WNetGetLastErrorA [MPR.@]
2499 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2500 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2501 LPSTR lpNameBuf, DWORD nNameBufSize )
2503 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2504 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2506 SetLastError(WN_NO_NETWORK);
2507 return WN_NO_NETWORK;
2510 /*********************************************************************
2511 * WNetGetLastErrorW [MPR.@]
2513 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2514 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2515 LPWSTR lpNameBuf, DWORD nNameBufSize )
2517 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2518 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2520 SetLastError(WN_NO_NETWORK);
2521 return WN_NO_NETWORK;
2524 /*********************************************************************
2525 * WNetGetNetworkInformationA [MPR.@]
2527 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2528 LPNETINFOSTRUCT lpNetInfoStruct )
2530 DWORD ret;
2532 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2534 if (!lpProvider)
2535 ret = WN_BAD_POINTER;
2536 else
2538 int len;
2540 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2541 if (len)
2543 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2545 if (wideProvider)
2547 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2548 len);
2549 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2550 HeapFree(GetProcessHeap(), 0, wideProvider);
2552 else
2553 ret = WN_OUT_OF_MEMORY;
2555 else
2556 ret = GetLastError();
2558 if (ret)
2559 SetLastError(ret);
2560 TRACE("Returning %d\n", ret);
2561 return ret;
2564 /*********************************************************************
2565 * WNetGetNetworkInformationW [MPR.@]
2567 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2568 LPNETINFOSTRUCT lpNetInfoStruct )
2570 DWORD ret;
2572 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2574 if (!lpProvider)
2575 ret = WN_BAD_POINTER;
2576 else if (!lpNetInfoStruct)
2577 ret = WN_BAD_POINTER;
2578 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2579 ret = WN_BAD_VALUE;
2580 else
2582 if (providerTable && providerTable->numProviders)
2584 DWORD providerIndex = _findProviderIndexW(lpProvider);
2586 if (providerIndex != BAD_PROVIDER_INDEX)
2588 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2589 lpNetInfoStruct->dwProviderVersion =
2590 providerTable->table[providerIndex].dwSpecVersion;
2591 lpNetInfoStruct->dwStatus = NO_ERROR;
2592 lpNetInfoStruct->dwCharacteristics = 0;
2593 lpNetInfoStruct->dwHandle = 0;
2594 lpNetInfoStruct->wNetType =
2595 HIWORD(providerTable->table[providerIndex].dwNetType);
2596 lpNetInfoStruct->dwPrinters = -1;
2597 lpNetInfoStruct->dwDrives = -1;
2598 ret = WN_SUCCESS;
2600 else
2601 ret = WN_BAD_PROVIDER;
2603 else
2604 ret = WN_NO_NETWORK;
2606 if (ret)
2607 SetLastError(ret);
2608 TRACE("Returning %d\n", ret);
2609 return ret;
2612 /*****************************************************************
2613 * WNetGetProviderNameA [MPR.@]
2615 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2616 LPSTR lpProvider, LPDWORD lpBufferSize )
2618 DWORD ret;
2620 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2621 lpBufferSize);
2623 if (!lpProvider)
2624 ret = WN_BAD_POINTER;
2625 else if (!lpBufferSize)
2626 ret = WN_BAD_POINTER;
2627 else
2629 if (providerTable)
2631 DWORD i;
2633 ret = WN_NO_NETWORK;
2634 for (i = 0; i < providerTable->numProviders &&
2635 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2636 i++)
2638 if (i < providerTable->numProviders)
2640 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2641 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2643 if (*lpBufferSize < sizeNeeded)
2645 *lpBufferSize = sizeNeeded;
2646 ret = WN_MORE_DATA;
2648 else
2650 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2651 -1, lpProvider, *lpBufferSize, NULL, NULL);
2652 ret = WN_SUCCESS;
2653 /* FIXME: is *lpBufferSize set to the number of characters
2654 * copied? */
2658 else
2659 ret = WN_NO_NETWORK;
2661 if (ret)
2662 SetLastError(ret);
2663 TRACE("Returning %d\n", ret);
2664 return ret;
2667 /*****************************************************************
2668 * WNetGetProviderNameW [MPR.@]
2670 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2671 LPWSTR lpProvider, LPDWORD lpBufferSize )
2673 DWORD ret;
2675 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2676 lpBufferSize);
2678 if (!lpProvider)
2679 ret = WN_BAD_POINTER;
2680 else if (!lpBufferSize)
2681 ret = WN_BAD_POINTER;
2682 else
2684 if (providerTable)
2686 DWORD i;
2688 ret = WN_NO_NETWORK;
2689 for (i = 0; i < providerTable->numProviders &&
2690 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2691 i++)
2693 if (i < providerTable->numProviders)
2695 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2697 if (*lpBufferSize < sizeNeeded)
2699 *lpBufferSize = sizeNeeded;
2700 ret = WN_MORE_DATA;
2702 else
2704 strcpyW(lpProvider, providerTable->table[i].name);
2705 ret = WN_SUCCESS;
2706 /* FIXME: is *lpBufferSize set to the number of characters
2707 * copied? */
2711 else
2712 ret = WN_NO_NETWORK;
2714 if (ret)
2715 SetLastError(ret);
2716 TRACE("Returning %d\n", ret);
2717 return ret;