mpr: Properly handle device-less connections.
[wine.git] / dlls / mpr / wnet.c
blob4260ee1d4e6897f9fb73964ec6034cc22f39da78
1 /*
2 * MPR WNet functions
4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
7 * Copyright 2016-2018 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, ARRAY_SIZE(serviceName), serviceFmt, servicePrefix, provider);
134 serviceName[ARRAY_SIZE(serviceName) - 1] = '\0';
135 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
136 ERROR_SUCCESS)
138 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
139 'P','a','t','h',0 };
140 WCHAR providerPath[MAX_PATH];
141 DWORD type, size = sizeof(providerPath);
143 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
144 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && (type == REG_SZ || type == REG_EXPAND_SZ))
146 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
147 PWSTR name = NULL;
149 if (type == REG_EXPAND_SZ)
151 WCHAR path[MAX_PATH];
152 if (ExpandEnvironmentStringsW(providerPath, path, MAX_PATH)) lstrcpyW( providerPath, path );
155 size = 0;
156 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
157 if (size)
159 name = HeapAlloc(GetProcessHeap(), 0, size);
160 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
161 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
163 HeapFree(GetProcessHeap(), 0, name);
164 name = NULL;
167 if (name)
169 HMODULE hLib = LoadLibraryW(providerPath);
171 if (hLib)
173 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
175 PF_NPGetCaps getCaps = MPR_GETPROC(NPGetCaps);
177 TRACE("loaded lib %p\n", hLib);
178 if (getCaps)
180 DWORD connectCap;
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 connectCap = getCaps(WNNC_CONNECTION);
215 if (connectCap & WNNC_CON_ADDCONNECTION)
216 provider->addConnection = MPR_GETPROC(NPAddConnection);
217 if (connectCap & WNNC_CON_ADDCONNECTION3)
218 provider->addConnection3 = MPR_GETPROC(NPAddConnection3);
219 if (connectCap & WNNC_CON_CANCELCONNECTION)
220 provider->cancelConnection = MPR_GETPROC(NPCancelConnection);
221 TRACE("NPAddConnection %p\n", provider->addConnection);
222 TRACE("NPAddConnection3 %p\n", provider->addConnection3);
223 TRACE("NPCancelConnection %p\n", provider->cancelConnection);
224 providerTable->numProviders++;
226 else
228 WARN("Provider %s didn't export NPGetCaps\n",
229 debugstr_w(provider));
230 HeapFree(GetProcessHeap(), 0, name);
231 FreeLibrary(hLib);
234 #undef MPR_GETPROC
236 else
238 WARN("Couldn't load library %s for provider %s\n",
239 debugstr_w(providerPath), debugstr_w(provider));
240 HeapFree(GetProcessHeap(), 0, name);
243 else
245 WARN("Couldn't get provider name for provider %s\n",
246 debugstr_w(provider));
249 else
250 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
251 RegCloseKey(hKey);
253 else
254 WARN("Couldn't open service key for provider %s\n",
255 debugstr_w(provider));
258 void wnetInit(HINSTANCE hInstDll)
260 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
261 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
262 'C','o','n','t','r','o','l','\\',
263 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
264 'O','r','d','e','r',0 };
265 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
266 'O','r','d','e','r',0 };
267 HKEY hKey;
269 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
270 == ERROR_SUCCESS)
272 DWORD size = 0;
274 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
275 if (size)
277 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
279 if (providers)
281 DWORD type;
283 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
284 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
286 PWSTR ptr;
287 DWORD numToAllocate;
289 TRACE("provider order is %s\n", debugstr_w(providers));
290 /* first count commas as a heuristic for how many to
291 * allocate space for */
292 for (ptr = providers, numToAllocate = 1; ptr; )
294 ptr = strchrW(ptr, ',');
295 if (ptr) {
296 numToAllocate++;
297 ptr++;
300 providerTable =
301 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
302 sizeof(WNetProviderTable)
303 + (numToAllocate - 1) * sizeof(WNetProvider));
304 if (providerTable)
306 PWSTR ptrPrev;
307 int entireNetworkLen;
308 LPCWSTR stringresource;
310 entireNetworkLen = LoadStringW(hInstDll,
311 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
312 providerTable->entireNetwork = HeapAlloc(
313 GetProcessHeap(), 0, (entireNetworkLen + 1) *
314 sizeof(WCHAR));
315 if (providerTable->entireNetwork)
317 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
318 providerTable->entireNetwork[entireNetworkLen] = 0;
320 providerTable->numAllocated = numToAllocate;
321 for (ptr = providers; ptr; )
323 ptrPrev = ptr;
324 ptr = strchrW(ptr, ',');
325 if (ptr)
326 *ptr++ = '\0';
327 _tryLoadProvider(ptrPrev);
331 HeapFree(GetProcessHeap(), 0, providers);
334 RegCloseKey(hKey);
338 void wnetFree(void)
340 if (providerTable)
342 DWORD i;
344 for (i = 0; i < providerTable->numProviders; i++)
346 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
347 FreeModule(providerTable->table[i].hLib);
349 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
350 HeapFree(GetProcessHeap(), 0, providerTable);
351 providerTable = NULL;
355 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
357 DWORD ret = BAD_PROVIDER_INDEX;
359 if (providerTable && providerTable->numProviders)
361 DWORD i;
363 for (i = 0; i < providerTable->numProviders &&
364 ret == BAD_PROVIDER_INDEX; i++)
365 if (!strcmpW(lpProvider, providerTable->table[i].name))
366 ret = i;
368 return ret;
372 * Browsing Functions
375 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
377 LPNETRESOURCEW ret;
379 if (lpNet)
381 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
382 if (ret)
384 size_t len;
386 *ret = *lpNet;
387 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
388 if (lpNet->lpRemoteName)
390 len = strlenW(lpNet->lpRemoteName) + 1;
391 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
392 if (ret->lpRemoteName)
393 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
397 else
398 ret = NULL;
399 return ret;
402 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
404 if (lpNet)
406 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
407 HeapFree(GetProcessHeap(), 0, lpNet);
411 static PWNetEnumerator _createNullEnumerator(void)
413 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
414 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
416 if (ret)
417 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
418 return ret;
421 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
422 DWORD dwUsage, LPNETRESOURCEW lpNet)
424 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
425 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
427 if (ret)
429 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
430 ret->dwScope = dwScope;
431 ret->dwType = dwType;
432 ret->dwUsage = dwUsage;
433 ret->specific.net = _copyNetResourceForEnumW(lpNet);
435 return ret;
438 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
439 DWORD dwUsage, DWORD index, HANDLE handle)
441 PWNetEnumerator ret;
443 if (!providerTable || index >= providerTable->numProviders)
444 ret = NULL;
445 else
447 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
448 if (ret)
450 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
451 ret->providerIndex = index;
452 ret->dwScope = dwScope;
453 ret->dwType = dwType;
454 ret->dwUsage = dwUsage;
455 ret->handle = handle;
458 return ret;
461 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
462 DWORD dwUsage)
464 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
465 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
467 if (ret)
469 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
470 ret->dwScope = dwScope;
471 ret->dwType = dwType;
472 ret->dwUsage = dwUsage;
474 return ret;
477 static PWNetEnumerator _createConnectedEnumerator(DWORD dwScope, DWORD dwType,
478 DWORD dwUsage)
480 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
481 if (ret)
483 ret->enumType = WNET_ENUMERATOR_TYPE_CONNECTED;
484 ret->dwScope = dwScope;
485 ret->dwType = dwType;
486 ret->dwUsage = dwUsage;
487 ret->specific.handles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HANDLE) * providerTable->numProviders);
488 if (!ret->specific.handles)
490 HeapFree(GetProcessHeap(), 0, ret);
491 ret = NULL;
494 return ret;
497 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
498 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
499 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
500 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
501 * if not all members of the array could be thunked, and something else on
502 * failure.
504 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
505 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
507 DWORD i, numToThunk, totalBytes, ret;
508 LPSTR strNext;
510 if (!lpNetArrayIn)
511 return WN_BAD_POINTER;
512 if (!lpcCount)
513 return WN_BAD_POINTER;
514 if (*lpcCount == -1)
515 return WN_BAD_VALUE;
516 if (!lpBuffer)
517 return WN_BAD_POINTER;
518 if (!lpBufferSize)
519 return WN_BAD_POINTER;
521 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
523 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
525 totalBytes += sizeof(NETRESOURCEA);
526 if (lpNet->lpLocalName)
527 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
528 -1, NULL, 0, NULL, NULL);
529 if (lpNet->lpRemoteName)
530 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
531 -1, NULL, 0, NULL, NULL);
532 if (lpNet->lpComment)
533 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
534 -1, NULL, 0, NULL, NULL);
535 if (lpNet->lpProvider)
536 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
537 -1, NULL, 0, NULL, NULL);
538 if (totalBytes < *lpBufferSize)
539 numToThunk = i + 1;
541 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
542 for (i = 0; i < numToThunk; i++)
544 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
545 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
547 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
548 /* lie about string lengths, we already verified how many
549 * we have space for above
551 if (lpNetIn->lpLocalName)
553 lpNetOut->lpLocalName = strNext;
554 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
555 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
557 if (lpNetIn->lpRemoteName)
559 lpNetOut->lpRemoteName = strNext;
560 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
561 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
563 if (lpNetIn->lpComment)
565 lpNetOut->lpComment = strNext;
566 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
567 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
569 if (lpNetIn->lpProvider)
571 lpNetOut->lpProvider = strNext;
572 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
573 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
576 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
577 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
578 *lpcCount, ret);
579 return ret;
582 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
583 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
584 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
585 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
586 * if not all members of the array could be thunked, and something else on
587 * failure.
589 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
590 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
592 DWORD i, numToThunk, totalBytes, ret;
593 LPWSTR strNext;
595 if (!lpNetArrayIn)
596 return WN_BAD_POINTER;
597 if (!lpcCount)
598 return WN_BAD_POINTER;
599 if (*lpcCount == -1)
600 return WN_BAD_VALUE;
601 if (!lpBuffer)
602 return WN_BAD_POINTER;
603 if (!lpBufferSize)
604 return WN_BAD_POINTER;
606 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
608 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
610 totalBytes += sizeof(NETRESOURCEW);
611 if (lpNet->lpLocalName)
612 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
613 -1, NULL, 0) * sizeof(WCHAR);
614 if (lpNet->lpRemoteName)
615 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
616 -1, NULL, 0) * sizeof(WCHAR);
617 if (lpNet->lpComment)
618 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
619 -1, NULL, 0) * sizeof(WCHAR);
620 if (lpNet->lpProvider)
621 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
622 -1, NULL, 0) * sizeof(WCHAR);
623 if (totalBytes < *lpBufferSize)
624 numToThunk = i + 1;
626 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
627 for (i = 0; i < numToThunk; i++)
629 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
630 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
632 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
633 /* lie about string lengths, we already verified how many
634 * we have space for above
636 if (lpNetIn->lpLocalName)
638 lpNetOut->lpLocalName = strNext;
639 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
640 -1, lpNetOut->lpLocalName, *lpBufferSize);
642 if (lpNetIn->lpRemoteName)
644 lpNetOut->lpRemoteName = strNext;
645 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
646 -1, lpNetOut->lpRemoteName, *lpBufferSize);
648 if (lpNetIn->lpComment)
650 lpNetOut->lpComment = strNext;
651 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
652 -1, lpNetOut->lpComment, *lpBufferSize);
654 if (lpNetIn->lpProvider)
656 lpNetOut->lpProvider = strNext;
657 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
658 -1, lpNetOut->lpProvider, *lpBufferSize);
661 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
662 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
663 *lpcCount, ret);
664 return ret;
667 /*********************************************************************
668 * WNetOpenEnumA [MPR.@]
670 * See comments for WNetOpenEnumW.
672 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
673 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
675 DWORD ret;
677 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
678 dwScope, dwType, dwUsage, lpNet, lphEnum );
680 if (!lphEnum)
681 ret = WN_BAD_POINTER;
682 else if (!providerTable || providerTable->numProviders == 0)
684 *lphEnum = NULL;
685 ret = WN_NO_NETWORK;
687 else
689 if (lpNet)
691 LPNETRESOURCEW lpNetWide = NULL;
692 BYTE buf[1024];
693 DWORD size = sizeof(buf), count = 1;
694 BOOL allocated = FALSE;
696 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
697 if (ret == WN_MORE_DATA)
699 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
700 size);
701 if (lpNetWide)
703 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
704 &size);
705 allocated = TRUE;
707 else
708 ret = WN_OUT_OF_MEMORY;
710 else if (ret == WN_SUCCESS)
711 lpNetWide = (LPNETRESOURCEW)buf;
712 if (ret == WN_SUCCESS)
713 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
714 lphEnum);
715 if (allocated)
716 HeapFree(GetProcessHeap(), 0, lpNetWide);
718 else
719 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
721 if (ret)
722 SetLastError(ret);
723 TRACE("Returning %d\n", ret);
724 return ret;
727 /*********************************************************************
728 * WNetOpenEnumW [MPR.@]
730 * Network enumeration has way too many parameters, so I'm not positive I got
731 * them right. What I've got so far:
733 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
734 * all the network providers should be enumerated.
736 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
737 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
738 * lpProvider is set, all the network providers should be enumerated.
739 * (This means the enumeration is a list of network providers, not that the
740 * enumeration is passed on to the providers.)
742 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
743 * resource matches the "Entire Network" resource (no remote name, no
744 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
745 * enumeration is done on every network provider.
747 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
748 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
749 * only to the given network provider.
751 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
752 * no lpProvider is set, enumeration will be tried on every network provider,
753 * in the order in which they're loaded.
755 * - The LPNETRESOURCE should be disregarded for scopes besides
756 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
757 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
759 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
760 * resource in the enumerated list, as well as any machines in your
761 * workgroup. The machines in your workgroup come from doing a
762 * RESOURCE_CONTEXT enumeration of every Network Provider.
764 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
765 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
767 DWORD ret;
769 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
770 dwScope, dwType, dwUsage, lpNet, lphEnum );
772 if (!lphEnum)
773 ret = WN_BAD_POINTER;
774 else if (!providerTable || providerTable->numProviders == 0)
776 *lphEnum = NULL;
777 ret = WN_NO_NETWORK;
779 else
781 switch (dwScope)
783 case RESOURCE_GLOBALNET:
784 if (lpNet)
786 if (lpNet->lpProvider)
788 DWORD index = _findProviderIndexW(lpNet->lpProvider);
790 if (index != BAD_PROVIDER_INDEX)
792 if (providerTable->table[index].openEnum &&
793 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
795 HANDLE handle;
796 PWSTR RemoteName = lpNet->lpRemoteName;
798 if ((lpNet->dwUsage & RESOURCEUSAGE_CONTAINER) &&
799 RemoteName && !strcmpW(RemoteName, lpNet->lpProvider))
800 lpNet->lpRemoteName = NULL;
802 ret = providerTable->table[index].openEnum(
803 dwScope, dwType, dwUsage, lpNet, &handle);
804 if (ret == WN_SUCCESS)
806 *lphEnum = _createProviderEnumerator(
807 dwScope, dwType, dwUsage, index, handle);
808 ret = *lphEnum ? WN_SUCCESS :
809 WN_OUT_OF_MEMORY;
812 lpNet->lpRemoteName = RemoteName;
814 else
815 ret = WN_NOT_SUPPORTED;
817 else
818 ret = WN_BAD_PROVIDER;
820 else if (lpNet->lpRemoteName)
822 *lphEnum = _createGlobalEnumeratorW(dwScope,
823 dwType, dwUsage, lpNet);
824 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
826 else
828 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
829 providerTable->entireNetwork))
831 /* comment matches the "Entire Network", enumerate
832 * global scope of every provider
834 *lphEnum = _createGlobalEnumeratorW(dwScope,
835 dwType, dwUsage, lpNet);
837 else
839 /* this is the same as not having passed lpNet */
840 *lphEnum = _createGlobalEnumeratorW(dwScope,
841 dwType, dwUsage, NULL);
843 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
846 else
848 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
849 dwUsage, lpNet);
850 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
852 break;
853 case RESOURCE_CONTEXT:
854 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
855 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
856 break;
857 case RESOURCE_CONNECTED:
858 *lphEnum = _createConnectedEnumerator(dwScope, dwType, dwUsage);
859 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
860 break;
861 case RESOURCE_REMEMBERED:
862 *lphEnum = _createNullEnumerator();
863 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
864 break;
865 default:
866 WARN("unknown scope 0x%08x\n", dwScope);
867 ret = WN_BAD_VALUE;
870 if (ret)
871 SetLastError(ret);
872 TRACE("Returning %d\n", ret);
873 return ret;
876 /*********************************************************************
877 * WNetEnumResourceA [MPR.@]
879 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
880 LPVOID lpBuffer, LPDWORD lpBufferSize )
882 DWORD ret;
884 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
886 if (!hEnum)
887 ret = WN_BAD_POINTER;
888 else if (!lpcCount)
889 ret = WN_BAD_POINTER;
890 else if (!lpBuffer)
891 ret = WN_BAD_POINTER;
892 else if (!lpBufferSize)
893 ret = WN_BAD_POINTER;
894 else if (*lpBufferSize < sizeof(NETRESOURCEA))
896 *lpBufferSize = sizeof(NETRESOURCEA);
897 ret = WN_MORE_DATA;
899 else
901 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
902 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
904 if (localBuffer)
906 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
907 &localSize);
908 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
910 /* FIXME: this isn't necessarily going to work in the case of
911 * WN_MORE_DATA, because our enumerator may have moved on to
912 * the next provider. MSDN states that a large (16KB) buffer
913 * size is the appropriate usage of this function, so
914 * hopefully it won't be an issue.
916 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
917 lpBuffer, lpBufferSize);
918 *lpcCount = localCount;
920 HeapFree(GetProcessHeap(), 0, localBuffer);
922 else
923 ret = WN_OUT_OF_MEMORY;
925 if (ret)
926 SetLastError(ret);
927 TRACE("Returning %d\n", ret);
928 return ret;
931 static DWORD _countProviderBytesW(PWNetProvider provider)
933 DWORD ret;
935 if (provider)
937 ret = sizeof(NETRESOURCEW);
938 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
940 else
941 ret = 0;
942 return ret;
945 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
946 LPVOID lpBuffer, const DWORD *lpBufferSize)
948 DWORD ret;
950 if (!enumerator)
951 return WN_BAD_POINTER;
952 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
953 return WN_BAD_VALUE;
954 if (!lpcCount)
955 return WN_BAD_POINTER;
956 if (!lpBuffer)
957 return WN_BAD_POINTER;
958 if (!lpBufferSize)
959 return WN_BAD_POINTER;
960 if (*lpBufferSize < sizeof(NETRESOURCEA))
961 return WN_MORE_DATA;
963 if (!providerTable || enumerator->providerIndex >=
964 providerTable->numProviders)
965 ret = WN_NO_MORE_ENTRIES;
966 else
968 DWORD bytes = 0, count = 0, countLimit, i;
969 LPNETRESOURCEW resource;
970 LPWSTR strNext;
972 countLimit = *lpcCount == -1 ?
973 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
974 while (count < countLimit && bytes < *lpBufferSize)
976 DWORD bytesNext = _countProviderBytesW(
977 &providerTable->table[count + enumerator->providerIndex]);
979 if (bytes + bytesNext < *lpBufferSize)
981 bytes += bytesNext;
982 count++;
985 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
986 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
988 resource->dwScope = RESOURCE_GLOBALNET;
989 resource->dwType = RESOURCETYPE_ANY;
990 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
991 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
992 RESOURCEUSAGE_RESERVED;
993 resource->lpLocalName = NULL;
994 resource->lpRemoteName = strNext;
995 strcpyW(resource->lpRemoteName,
996 providerTable->table[i + enumerator->providerIndex].name);
997 strNext += strlenW(resource->lpRemoteName) + 1;
998 resource->lpComment = NULL;
999 resource->lpProvider = strNext;
1000 strcpyW(resource->lpProvider,
1001 providerTable->table[i + enumerator->providerIndex].name);
1002 strNext += strlenW(resource->lpProvider) + 1;
1004 enumerator->providerIndex += count;
1005 *lpcCount = count;
1006 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
1008 TRACE("Returning %d\n", ret);
1009 return ret;
1012 /* Advances the enumerator (assumed to be a global enumerator) to the next
1013 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1014 * not open a handle with the next provider.
1015 * If the existing handle is NULL, may leave the enumerator unchanged, since
1016 * the current provider may support the desired scope.
1017 * If the existing handle is not NULL, closes it before moving on.
1018 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1019 * provider, and another error on failure.
1021 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
1023 if (!enumerator)
1024 return WN_BAD_POINTER;
1025 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1026 return WN_BAD_VALUE;
1027 if (!providerTable || enumerator->providerIndex >=
1028 providerTable->numProviders)
1029 return WN_NO_MORE_ENTRIES;
1031 if (enumerator->providerDone)
1033 DWORD dwEnum = 0;
1034 enumerator->providerDone = FALSE;
1035 if (enumerator->handle)
1037 providerTable->table[enumerator->providerIndex].closeEnum(
1038 enumerator->handle);
1039 enumerator->handle = NULL;
1040 enumerator->providerIndex++;
1042 if (enumerator->dwScope == RESOURCE_CONNECTED)
1043 dwEnum = WNNC_ENUM_LOCAL;
1044 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
1045 dwEnum = WNNC_ENUM_GLOBAL;
1046 else if (enumerator->dwScope == RESOURCE_CONTEXT)
1047 dwEnum = WNNC_ENUM_CONTEXT;
1048 for (; enumerator->providerIndex < providerTable->numProviders &&
1049 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
1050 & dwEnum); enumerator->providerIndex++)
1053 return enumerator->providerIndex < providerTable->numProviders ?
1054 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1057 /* "Passes through" call to the next provider that supports the enumeration
1058 * type.
1059 * FIXME: if one call to a provider's enumerator succeeds while there's still
1060 * space in lpBuffer, I don't call to the next provider. The caller may not
1061 * expect that it should call EnumResourceW again with a return value of
1062 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1063 * may have to be moved around a bit, ick.
1065 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1066 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1068 DWORD ret;
1070 if (!enumerator)
1071 return WN_BAD_POINTER;
1072 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1073 return WN_BAD_VALUE;
1074 if (!lpcCount)
1075 return WN_BAD_POINTER;
1076 if (!lpBuffer)
1077 return WN_BAD_POINTER;
1078 if (!lpBufferSize)
1079 return WN_BAD_POINTER;
1080 if (*lpBufferSize < sizeof(NETRESOURCEW))
1081 return WN_MORE_DATA;
1083 ret = _globalEnumeratorAdvance(enumerator);
1084 if (ret == WN_SUCCESS)
1086 ret = providerTable->table[enumerator->providerIndex].
1087 openEnum(enumerator->dwScope, enumerator->dwType,
1088 enumerator->dwUsage, enumerator->specific.net,
1089 &enumerator->handle);
1090 if (ret == WN_SUCCESS)
1092 ret = providerTable->table[enumerator->providerIndex].
1093 enumResource(enumerator->handle, lpcCount, lpBuffer,
1094 lpBufferSize);
1095 if (ret != WN_MORE_DATA)
1096 enumerator->providerDone = TRUE;
1099 TRACE("Returning %d\n", ret);
1100 return ret;
1103 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1104 LPVOID lpBuffer, LPDWORD lpBufferSize)
1106 DWORD ret;
1108 if (!enumerator)
1109 return WN_BAD_POINTER;
1110 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1111 return WN_BAD_VALUE;
1112 if (!lpcCount)
1113 return WN_BAD_POINTER;
1114 if (!lpBuffer)
1115 return WN_BAD_POINTER;
1116 if (!lpBufferSize)
1117 return WN_BAD_POINTER;
1118 if (*lpBufferSize < sizeof(NETRESOURCEW))
1119 return WN_MORE_DATA;
1120 if (!providerTable)
1121 return WN_NO_NETWORK;
1123 switch (enumerator->dwScope)
1125 case RESOURCE_GLOBALNET:
1126 if (enumerator->specific.net)
1127 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1128 lpBuffer, lpBufferSize);
1129 else
1130 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1131 lpBufferSize);
1132 break;
1133 case RESOURCE_CONTEXT:
1134 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1135 lpBufferSize);
1136 break;
1137 default:
1138 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1139 ret = WN_NO_MORE_ENTRIES;
1141 TRACE("Returning %d\n", ret);
1142 return ret;
1145 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1146 LPVOID lpBuffer, LPDWORD lpBufferSize)
1148 if (!enumerator)
1149 return WN_BAD_POINTER;
1150 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1151 return WN_BAD_VALUE;
1152 if (!enumerator->handle)
1153 return WN_BAD_VALUE;
1154 if (!lpcCount)
1155 return WN_BAD_POINTER;
1156 if (!lpBuffer)
1157 return WN_BAD_POINTER;
1158 if (!lpBufferSize)
1159 return WN_BAD_POINTER;
1160 if (!providerTable)
1161 return WN_NO_NETWORK;
1162 if (enumerator->providerIndex >= providerTable->numProviders)
1163 return WN_NO_MORE_ENTRIES;
1164 if (!providerTable->table[enumerator->providerIndex].enumResource)
1165 return WN_BAD_VALUE;
1166 return providerTable->table[enumerator->providerIndex].enumResource(
1167 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1170 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1171 LPVOID lpBuffer, LPDWORD lpBufferSize)
1173 DWORD ret;
1174 size_t cchEntireNetworkLen, bytesNeeded;
1176 if (!enumerator)
1177 return WN_BAD_POINTER;
1178 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1179 return WN_BAD_VALUE;
1180 if (!lpcCount)
1181 return WN_BAD_POINTER;
1182 if (!lpBuffer)
1183 return WN_BAD_POINTER;
1184 if (!lpBufferSize)
1185 return WN_BAD_POINTER;
1186 if (!providerTable)
1187 return WN_NO_NETWORK;
1189 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1190 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1191 if (*lpBufferSize < bytesNeeded)
1193 *lpBufferSize = bytesNeeded;
1194 ret = WN_MORE_DATA;
1196 else
1198 LPNETRESOURCEW lpNet = lpBuffer;
1200 lpNet->dwScope = RESOURCE_GLOBALNET;
1201 lpNet->dwType = enumerator->dwType;
1202 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1203 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1204 lpNet->lpLocalName = NULL;
1205 lpNet->lpRemoteName = NULL;
1206 lpNet->lpProvider = NULL;
1207 /* odd, but correct: put comment at end of buffer, so it won't get
1208 * overwritten by subsequent calls to a provider's enumResource
1210 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1211 (cchEntireNetworkLen * sizeof(WCHAR)));
1212 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1213 ret = WN_SUCCESS;
1215 if (ret == WN_SUCCESS)
1217 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1219 /* "Entire Network" entry enumerated--morph this into a global
1220 * enumerator. enumerator->lpNet continues to be NULL, since it has
1221 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1223 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1224 ret = _enumerateGlobalW(enumerator, lpcCount,
1225 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1226 if (ret == WN_SUCCESS)
1228 /* reflect the fact that we already enumerated "Entire Network" */
1229 (*lpcCount)++;
1230 *lpBufferSize = bufferSize + bytesNeeded;
1232 else
1234 /* the provider enumeration failed, but we already succeeded in
1235 * enumerating "Entire Network"--leave type as global to allow a
1236 * retry, but indicate success with a count of one.
1238 ret = WN_SUCCESS;
1239 *lpcCount = 1;
1240 *lpBufferSize = bytesNeeded;
1243 TRACE("Returning %d\n", ret);
1244 return ret;
1247 static DWORD _copyStringToEnumW(const WCHAR *source, DWORD* left, void** end)
1249 DWORD len;
1250 WCHAR* local = *end;
1252 len = strlenW(source) + 1;
1253 len *= sizeof(WCHAR);
1254 if (*left < len)
1255 return WN_MORE_DATA;
1257 local -= (len / sizeof(WCHAR));
1258 memcpy(local, source, len);
1259 *left -= len;
1260 *end = local;
1262 return WN_SUCCESS;
1265 static DWORD _enumerateConnectedW(PWNetEnumerator enumerator, DWORD* user_count,
1266 void* user_buffer, DWORD* user_size)
1268 DWORD ret, index, count, total_count, size, i, left;
1269 void* end;
1270 NETRESOURCEW* curr, * buffer;
1271 HANDLE* handles;
1273 if (!enumerator)
1274 return WN_BAD_POINTER;
1275 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONNECTED)
1276 return WN_BAD_VALUE;
1277 if (!user_count || !user_buffer || !user_size)
1278 return WN_BAD_POINTER;
1279 if (!providerTable)
1280 return WN_NO_NETWORK;
1282 handles = enumerator->specific.handles;
1283 left = *user_size;
1284 size = *user_size;
1285 buffer = HeapAlloc(GetProcessHeap(), 0, *user_size);
1286 if (!buffer)
1287 return WN_NO_NETWORK;
1289 curr = user_buffer;
1290 end = (char *)user_buffer + size;
1291 count = *user_count;
1292 total_count = 0;
1294 ret = WN_NO_MORE_ENTRIES;
1295 for (index = 0; index < providerTable->numProviders; index++)
1297 if (providerTable->table[index].dwEnumScopes)
1299 if (handles[index] == 0)
1301 ret = providerTable->table[index].openEnum(enumerator->dwScope,
1302 enumerator->dwType,
1303 enumerator->dwUsage,
1304 NULL, &handles[index]);
1305 if (ret != WN_SUCCESS)
1306 continue;
1309 ret = providerTable->table[index].enumResource(handles[index],
1310 &count, buffer,
1311 &size);
1312 total_count += count;
1313 if (ret == WN_MORE_DATA)
1314 break;
1316 if (ret == WN_SUCCESS)
1318 for (i = 0; i < count; ++i)
1320 if (left < sizeof(NETRESOURCEW))
1322 ret = WN_MORE_DATA;
1323 break;
1326 memcpy(curr, &buffer[i], sizeof(NETRESOURCEW));
1327 left -= sizeof(NETRESOURCEW);
1329 ret = _copyStringToEnumW(buffer[i].lpLocalName, &left, &end);
1330 if (ret == WN_MORE_DATA)
1331 break;
1332 curr->lpLocalName = end;
1334 ret = _copyStringToEnumW(buffer[i].lpRemoteName, &left, &end);
1335 if (ret == WN_MORE_DATA)
1336 break;
1337 curr->lpRemoteName = end;
1339 ret = _copyStringToEnumW(buffer[i].lpProvider, &left, &end);
1340 if (ret == WN_MORE_DATA)
1341 break;
1342 curr->lpProvider = end;
1344 ++curr;
1347 size = left;
1350 if (*user_count != -1)
1351 count = *user_count - total_count;
1352 else
1353 count = *user_count;
1357 if (total_count == 0)
1358 ret = WN_NO_MORE_ENTRIES;
1360 *user_count = total_count;
1361 if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
1362 ret = WN_SUCCESS;
1364 HeapFree(GetProcessHeap(), 0, buffer);
1366 TRACE("Returning %d\n", ret);
1367 return ret;
1370 /*********************************************************************
1371 * WNetEnumResourceW [MPR.@]
1373 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1374 LPVOID lpBuffer, LPDWORD lpBufferSize )
1376 DWORD ret;
1378 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1380 if (!hEnum)
1381 ret = WN_BAD_POINTER;
1382 else if (!lpcCount)
1383 ret = WN_BAD_POINTER;
1384 else if (!lpBuffer)
1385 ret = WN_BAD_POINTER;
1386 else if (!lpBufferSize)
1387 ret = WN_BAD_POINTER;
1388 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1390 *lpBufferSize = sizeof(NETRESOURCEW);
1391 ret = WN_MORE_DATA;
1393 else
1395 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1397 switch (enumerator->enumType)
1399 case WNET_ENUMERATOR_TYPE_NULL:
1400 ret = WN_NO_MORE_ENTRIES;
1401 break;
1402 case WNET_ENUMERATOR_TYPE_GLOBAL:
1403 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1404 lpBufferSize);
1405 break;
1406 case WNET_ENUMERATOR_TYPE_PROVIDER:
1407 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1408 lpBufferSize);
1409 break;
1410 case WNET_ENUMERATOR_TYPE_CONTEXT:
1411 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1412 lpBufferSize);
1413 break;
1414 case WNET_ENUMERATOR_TYPE_CONNECTED:
1415 ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer,
1416 lpBufferSize);
1417 break;
1418 default:
1419 WARN("bogus enumerator type!\n");
1420 ret = WN_NO_NETWORK;
1423 if (ret)
1424 SetLastError(ret);
1425 TRACE("Returning %d\n", ret);
1426 return ret;
1429 /*********************************************************************
1430 * WNetCloseEnum [MPR.@]
1432 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1434 DWORD ret, index;
1435 HANDLE *handles;
1437 TRACE( "(%p)\n", hEnum );
1439 if (hEnum)
1441 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1443 switch (enumerator->enumType)
1445 case WNET_ENUMERATOR_TYPE_NULL:
1446 ret = WN_SUCCESS;
1447 break;
1448 case WNET_ENUMERATOR_TYPE_GLOBAL:
1449 if (enumerator->specific.net)
1450 _freeEnumNetResource(enumerator->specific.net);
1451 if (enumerator->handle)
1452 providerTable->table[enumerator->providerIndex].
1453 closeEnum(enumerator->handle);
1454 ret = WN_SUCCESS;
1455 break;
1456 case WNET_ENUMERATOR_TYPE_PROVIDER:
1457 if (enumerator->handle)
1458 providerTable->table[enumerator->providerIndex].
1459 closeEnum(enumerator->handle);
1460 ret = WN_SUCCESS;
1461 break;
1462 case WNET_ENUMERATOR_TYPE_CONNECTED:
1463 handles = enumerator->specific.handles;
1464 for (index = 0; index < providerTable->numProviders; index++)
1466 if (providerTable->table[index].dwEnumScopes && handles[index])
1467 providerTable->table[index].closeEnum(handles[index]);
1469 HeapFree(GetProcessHeap(), 0, handles);
1470 ret = WN_SUCCESS;
1471 break;
1472 default:
1473 WARN("bogus enumerator type!\n");
1474 ret = WN_BAD_HANDLE;
1476 HeapFree(GetProcessHeap(), 0, hEnum);
1478 else
1479 ret = WN_BAD_HANDLE;
1480 if (ret)
1481 SetLastError(ret);
1482 TRACE("Returning %d\n", ret);
1483 return ret;
1486 /*********************************************************************
1487 * WNetGetResourceInformationA [MPR.@]
1489 * See WNetGetResourceInformationW
1491 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1492 LPVOID lpBuffer, LPDWORD cbBuffer,
1493 LPSTR *lplpSystem )
1495 DWORD ret;
1497 TRACE( "(%p, %p, %p, %p)\n",
1498 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1500 if (!providerTable || providerTable->numProviders == 0)
1501 ret = WN_NO_NETWORK;
1502 else if (lpNetResource)
1504 LPNETRESOURCEW lpNetResourceW = NULL;
1505 DWORD size = 1024, count = 1;
1506 DWORD len;
1508 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1509 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1510 if (ret == WN_MORE_DATA)
1512 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1513 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1514 if (lpNetResourceW)
1515 ret = _thunkNetResourceArrayAToW(lpNetResource,
1516 &count, lpNetResourceW, &size);
1517 else
1518 ret = WN_OUT_OF_MEMORY;
1520 if (ret == WN_SUCCESS)
1522 LPWSTR lpSystemW = NULL;
1523 LPVOID lpBufferW;
1524 size = 1024;
1525 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1526 if (lpBufferW)
1528 ret = WNetGetResourceInformationW(lpNetResourceW,
1529 lpBufferW, &size, &lpSystemW);
1530 if (ret == WN_MORE_DATA)
1532 HeapFree(GetProcessHeap(), 0, lpBufferW);
1533 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1534 if (lpBufferW)
1535 ret = WNetGetResourceInformationW(lpNetResourceW,
1536 lpBufferW, &size, &lpSystemW);
1537 else
1538 ret = WN_OUT_OF_MEMORY;
1540 if (ret == WN_SUCCESS)
1542 ret = _thunkNetResourceArrayWToA(lpBufferW,
1543 &count, lpBuffer, cbBuffer);
1544 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1545 lpNetResourceW = lpBufferW;
1546 size = sizeof(NETRESOURCEA);
1547 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1548 -1, NULL, 0, NULL, NULL);
1549 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1550 -1, NULL, 0, NULL, NULL);
1552 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1553 -1, NULL, 0, NULL, NULL);
1554 if ((len) && ( size + len < *cbBuffer))
1556 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1557 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1558 *lplpSystem, len, NULL, NULL);
1559 ret = WN_SUCCESS;
1561 else
1562 ret = WN_MORE_DATA;
1564 else
1565 ret = WN_OUT_OF_MEMORY;
1566 HeapFree(GetProcessHeap(), 0, lpBufferW);
1568 else
1569 ret = WN_OUT_OF_MEMORY;
1570 HeapFree(GetProcessHeap(), 0, lpSystemW);
1572 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1574 else
1575 ret = WN_NO_NETWORK;
1577 if (ret)
1578 SetLastError(ret);
1579 TRACE("Returning %d\n", ret);
1580 return ret;
1583 /*********************************************************************
1584 * WNetGetResourceInformationW [MPR.@]
1586 * WNetGetResourceInformationW function identifies the network provider
1587 * that owns the resource and gets information about the type of the resource.
1589 * PARAMS:
1590 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1591 * defines a network resource.
1592 * lpBuffer [ O] the pointer to buffer, containing result. It
1593 * contains NETRESOURCEW structure and strings to
1594 * which the members of the NETRESOURCEW structure
1595 * point.
1596 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1597 * in bytes.
1598 * lplpSystem [ O] the pointer to string in the output buffer,
1599 * containing the part of the resource name without
1600 * names of the server and share.
1602 * RETURNS:
1603 * NO_ERROR if the function succeeds. System error code if the function fails.
1606 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1607 LPVOID lpBuffer, LPDWORD cbBuffer,
1608 LPWSTR *lplpSystem )
1610 DWORD ret = WN_NO_NETWORK;
1611 DWORD index;
1613 TRACE( "(%p, %p, %p, %p)\n",
1614 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1616 if (!(lpBuffer))
1617 ret = WN_OUT_OF_MEMORY;
1618 else if (providerTable != NULL)
1620 /* FIXME: For function value of a variable is indifferent, it does
1621 * search of all providers in a network.
1623 for (index = 0; index < providerTable->numProviders; index++)
1625 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1626 WNNC_DLG_GETRESOURCEINFORMATION)
1628 if (providerTable->table[index].getResourceInformation)
1629 ret = providerTable->table[index].getResourceInformation(
1630 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1631 else
1632 ret = WN_NO_NETWORK;
1633 if (ret == WN_SUCCESS)
1634 break;
1638 if (ret)
1639 SetLastError(ret);
1640 return ret;
1643 /*********************************************************************
1644 * WNetGetResourceParentA [MPR.@]
1646 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1647 LPVOID lpBuffer, LPDWORD lpBufferSize )
1649 FIXME( "(%p, %p, %p): stub\n",
1650 lpNetResource, lpBuffer, lpBufferSize );
1652 SetLastError(WN_NO_NETWORK);
1653 return WN_NO_NETWORK;
1656 /*********************************************************************
1657 * WNetGetResourceParentW [MPR.@]
1659 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1660 LPVOID lpBuffer, LPDWORD lpBufferSize )
1662 FIXME( "(%p, %p, %p): stub\n",
1663 lpNetResource, lpBuffer, lpBufferSize );
1665 SetLastError(WN_NO_NETWORK);
1666 return WN_NO_NETWORK;
1672 * Connection Functions
1675 /*********************************************************************
1676 * WNetAddConnectionA [MPR.@]
1678 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1679 LPCSTR lpLocalName )
1681 NETRESOURCEA resourcesA;
1683 memset(&resourcesA, 0, sizeof(resourcesA));
1684 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1685 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1686 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1689 /*********************************************************************
1690 * WNetAddConnectionW [MPR.@]
1692 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1693 LPCWSTR lpLocalName )
1695 NETRESOURCEW resourcesW;
1697 memset(&resourcesW, 0, sizeof(resourcesW));
1698 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1699 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1700 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1703 /*********************************************************************
1704 * WNetAddConnection2A [MPR.@]
1706 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1707 LPCSTR lpPassword, LPCSTR lpUserID,
1708 DWORD dwFlags )
1710 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1711 NULL, 0, NULL);
1714 /*********************************************************************
1715 * WNetAddConnection2W [MPR.@]
1717 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1718 LPCWSTR lpPassword, LPCWSTR lpUserID,
1719 DWORD dwFlags )
1721 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1722 NULL, 0, NULL);
1725 /*********************************************************************
1726 * WNetAddConnection3A [MPR.@]
1728 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1729 LPCSTR lpPassword, LPCSTR lpUserID,
1730 DWORD dwFlags )
1732 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1733 dwFlags, NULL, 0, NULL);
1736 /*********************************************************************
1737 * WNetAddConnection3W [MPR.@]
1739 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1740 LPCWSTR lpPassword, LPCWSTR lpUserID,
1741 DWORD dwFlags )
1743 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1744 dwFlags, NULL, 0, NULL);
1747 struct use_connection_context
1749 HWND hwndOwner;
1750 NETRESOURCEW *resource;
1751 NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */
1752 WCHAR *password;
1753 WCHAR *userid;
1754 DWORD flags;
1755 void *accessname;
1756 DWORD *buffer_size;
1757 DWORD *result;
1758 DWORD (*pre_set_accessname)(struct use_connection_context*, WCHAR *);
1759 void (*set_accessname)(struct use_connection_context*, WCHAR *);
1762 static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1764 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1766 DWORD len;
1768 if (local_name)
1769 len = strlenW(local_name);
1770 else
1771 len = strlenW(ctxt->resource->lpRemoteName);
1773 if (++len > *ctxt->buffer_size)
1775 *ctxt->buffer_size = len;
1776 return ERROR_MORE_DATA;
1779 else
1780 ctxt->accessname = NULL;
1782 return ERROR_SUCCESS;
1785 static void use_connection_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1787 WCHAR *accessname = ctxt->accessname;
1788 if (local_name)
1790 strcpyW(accessname, local_name);
1791 if (ctxt->result)
1792 *ctxt->result = CONNECT_LOCALDRIVE;
1794 else
1795 strcpyW(accessname, ctxt->resource->lpRemoteName);
1798 static DWORD wnet_use_provider( struct use_connection_context *ctxt, NETRESOURCEW * netres, WNetProvider *provider, BOOLEAN redirect )
1800 DWORD caps, ret;
1802 caps = provider->getCaps(WNNC_CONNECTION);
1803 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1804 return ERROR_BAD_PROVIDER;
1806 ret = WN_ACCESS_DENIED;
1809 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1810 ret = provider->addConnection3(ctxt->hwndOwner, netres, ctxt->password, ctxt->userid, ctxt->flags);
1811 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1812 ret = provider->addConnection(netres, ctxt->password, ctxt->userid);
1814 if (ret == WN_ALREADY_CONNECTED && redirect)
1815 netres->lpLocalName[0] -= 1;
1816 } while (redirect && ret == WN_ALREADY_CONNECTED && netres->lpLocalName[0] >= 'C');
1818 if (ret == WN_SUCCESS && ctxt->accessname)
1819 ctxt->set_accessname(ctxt, netres->lpLocalName);
1821 return ret;
1824 static DWORD wnet_use_connection( struct use_connection_context *ctxt )
1826 WNetProvider *provider;
1827 DWORD index, ret = WN_NO_NETWORK;
1828 BOOL redirect = FALSE;
1829 WCHAR letter[3] = {'Z', ':', 0};
1830 NETRESOURCEW netres;
1832 if (!providerTable || providerTable->numProviders == 0)
1833 return WN_NO_NETWORK;
1835 if (!ctxt->resource)
1836 return ERROR_INVALID_PARAMETER;
1837 netres = *ctxt->resource;
1839 if (!netres.lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
1841 if (netres.dwType != RESOURCETYPE_DISK && netres.dwType != RESOURCETYPE_PRINT)
1842 return ERROR_BAD_DEV_TYPE;
1844 if (netres.dwType == RESOURCETYPE_PRINT)
1846 FIXME("Local device selection is not implemented for printers.\n");
1847 return WN_NO_NETWORK;
1850 redirect = TRUE;
1851 netres.lpLocalName = letter;
1854 if (ctxt->flags & CONNECT_INTERACTIVE)
1855 return ERROR_BAD_NET_NAME;
1857 if ((ret = ctxt->pre_set_accessname(ctxt, netres.lpLocalName)))
1858 return ret;
1860 if (netres.lpProvider)
1862 index = _findProviderIndexW(netres.lpProvider);
1863 if (index == BAD_PROVIDER_INDEX)
1864 return ERROR_BAD_PROVIDER;
1866 provider = &providerTable->table[index];
1867 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
1869 else
1871 for (index = 0; index < providerTable->numProviders; index++)
1873 provider = &providerTable->table[index];
1874 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
1875 if (ret == WN_SUCCESS || ret == WN_ALREADY_CONNECTED)
1876 break;
1880 return ret;
1883 /*****************************************************************
1884 * WNetUseConnectionW [MPR.@]
1886 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
1887 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
1889 struct use_connection_context ctxt;
1891 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1892 hwndOwner, resource, password, debugstr_w(userid), flags,
1893 accessname, buffer_size, result );
1895 ctxt.hwndOwner = hwndOwner;
1896 ctxt.resource = resource;
1897 ctxt.resourceA = NULL;
1898 ctxt.password = (WCHAR*)password;
1899 ctxt.userid = (WCHAR*)userid;
1900 ctxt.flags = flags;
1901 ctxt.accessname = accessname;
1902 ctxt.buffer_size = buffer_size;
1903 ctxt.result = result;
1904 ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
1905 ctxt.set_accessname = use_connection_set_accessnameW;
1907 return wnet_use_connection(&ctxt);
1910 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
1912 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1914 DWORD len;
1916 if (local_name)
1917 len = WideCharToMultiByte(CP_ACP, 0, local_name, -1, NULL, 0, NULL, NULL) - 1;
1918 else
1919 len = strlen(ctxt->resourceA->lpRemoteName);
1921 if (++len > *ctxt->buffer_size)
1923 *ctxt->buffer_size = len;
1924 return ERROR_MORE_DATA;
1927 else
1928 ctxt->accessname = NULL;
1930 return ERROR_SUCCESS;
1933 static void use_connection_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
1935 char *accessname = ctxt->accessname;
1936 if (local_name)
1938 WideCharToMultiByte(CP_ACP, 0, local_name, -1, accessname, *ctxt->buffer_size, NULL, NULL);
1939 if (ctxt->result)
1940 *ctxt->result = CONNECT_LOCALDRIVE;
1942 else
1943 strcpy(accessname, ctxt->resourceA->lpRemoteName);
1946 static LPWSTR strdupAtoW( LPCSTR str )
1948 LPWSTR ret;
1949 INT len;
1951 if (!str) return NULL;
1952 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
1953 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1954 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
1955 return ret;
1958 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
1960 resourceW->dwScope = resourceA->dwScope;
1961 resourceW->dwType = resourceA->dwType;
1962 resourceW->dwDisplayType = resourceA->dwDisplayType;
1963 resourceW->dwUsage = resourceA->dwUsage;
1964 resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
1965 resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
1966 resourceW->lpComment = strdupAtoW(resourceA->lpComment);
1967 resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
1970 static void free_netresourceW( NETRESOURCEW *resource )
1972 HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
1973 HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
1974 HeapFree(GetProcessHeap(), 0, resource->lpComment);
1975 HeapFree(GetProcessHeap(), 0, resource->lpProvider);
1978 /*****************************************************************
1979 * WNetUseConnectionA [MPR.@]
1981 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
1982 LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
1983 DWORD *buffer_size, DWORD *result )
1985 struct use_connection_context ctxt;
1986 NETRESOURCEW resourceW;
1987 DWORD ret;
1989 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
1990 accessname, buffer_size, result );
1992 netresource_a_to_w(resource, &resourceW);
1994 ctxt.hwndOwner = hwndOwner;
1995 ctxt.resource = &resourceW;
1996 ctxt.resourceA = resource;
1997 ctxt.password = strdupAtoW(password);
1998 ctxt.userid = strdupAtoW(userid);
1999 ctxt.flags = flags;
2000 ctxt.accessname = accessname;
2001 ctxt.buffer_size = buffer_size;
2002 ctxt.result = result;
2003 ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
2004 ctxt.set_accessname = use_connection_set_accessnameA;
2006 ret = wnet_use_connection(&ctxt);
2008 free_netresourceW(&resourceW);
2009 HeapFree(GetProcessHeap(), 0, ctxt.password);
2010 HeapFree(GetProcessHeap(), 0, ctxt.userid);
2012 return ret;
2015 /*********************************************************************
2016 * WNetCancelConnectionA [MPR.@]
2018 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
2020 return WNetCancelConnection2A(lpName, 0, fForce);
2023 /*********************************************************************
2024 * WNetCancelConnectionW [MPR.@]
2026 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
2028 return WNetCancelConnection2W(lpName, 0, fForce);
2031 /*********************************************************************
2032 * WNetCancelConnection2A [MPR.@]
2034 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
2036 DWORD ret;
2037 WCHAR * name = strdupAtoW(lpName);
2038 if (!name)
2039 return ERROR_NOT_CONNECTED;
2041 ret = WNetCancelConnection2W(name, dwFlags, fForce);
2042 HeapFree(GetProcessHeap(), 0, name);
2044 return ret;
2047 /*********************************************************************
2048 * WNetCancelConnection2W [MPR.@]
2050 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
2052 DWORD ret = WN_NO_NETWORK;
2053 DWORD index;
2055 if (providerTable != NULL)
2057 for (index = 0; index < providerTable->numProviders; index++)
2059 if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2060 WNNC_CON_CANCELCONNECTION)
2062 if (providerTable->table[index].cancelConnection)
2063 ret = providerTable->table[index].cancelConnection((LPWSTR)lpName, fForce);
2064 else
2065 ret = WN_NO_NETWORK;
2066 if (ret == WN_SUCCESS || ret == WN_OPEN_FILES)
2067 break;
2071 return ret;
2074 /*****************************************************************
2075 * WNetRestoreConnectionA [MPR.@]
2077 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
2079 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
2081 SetLastError(WN_NO_NETWORK);
2082 return WN_NO_NETWORK;
2085 /*****************************************************************
2086 * WNetRestoreConnectionW [MPR.@]
2088 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
2090 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
2092 SetLastError(WN_NO_NETWORK);
2093 return WN_NO_NETWORK;
2096 /**************************************************************************
2097 * WNetGetConnectionA [MPR.@]
2099 * RETURNS
2100 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2101 * - WN_NOT_CONNECTED drive is a local drive
2102 * - WN_MORE_DATA buffer isn't big enough
2103 * - WN_SUCCESS success (net path in buffer)
2105 * FIXME: need to test return values under different errors
2107 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
2108 LPSTR lpRemoteName, LPDWORD lpBufferSize )
2110 DWORD ret;
2112 if (!lpLocalName)
2113 ret = WN_BAD_POINTER;
2114 else if (!lpBufferSize)
2115 ret = WN_BAD_POINTER;
2116 else if (!lpRemoteName && *lpBufferSize)
2117 ret = WN_BAD_POINTER;
2118 else
2120 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
2122 if (len)
2124 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2126 if (wideLocalName)
2128 WCHAR wideRemoteStatic[MAX_PATH];
2129 DWORD wideRemoteSize = ARRAY_SIZE(wideRemoteStatic);
2131 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
2133 /* try once without memory allocation */
2134 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
2135 &wideRemoteSize);
2136 if (ret == WN_SUCCESS)
2138 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2139 -1, NULL, 0, NULL, NULL);
2141 if (len <= *lpBufferSize)
2143 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
2144 lpRemoteName, *lpBufferSize, NULL, NULL);
2145 ret = WN_SUCCESS;
2147 else
2149 *lpBufferSize = len;
2150 ret = WN_MORE_DATA;
2153 else if (ret == WN_MORE_DATA)
2155 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
2156 wideRemoteSize * sizeof(WCHAR));
2158 if (wideRemote)
2160 ret = WNetGetConnectionW(wideLocalName, wideRemote,
2161 &wideRemoteSize);
2162 if (ret == WN_SUCCESS)
2164 if (len <= *lpBufferSize)
2166 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2167 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
2168 ret = WN_SUCCESS;
2170 else
2172 *lpBufferSize = len;
2173 ret = WN_MORE_DATA;
2176 HeapFree(GetProcessHeap(), 0, wideRemote);
2178 else
2179 ret = WN_OUT_OF_MEMORY;
2181 HeapFree(GetProcessHeap(), 0, wideLocalName);
2183 else
2184 ret = WN_OUT_OF_MEMORY;
2186 else
2187 ret = WN_BAD_LOCALNAME;
2189 if (ret)
2190 SetLastError(ret);
2191 TRACE("Returning %d\n", ret);
2192 return ret;
2195 /* find the network connection for a given drive; helper for WNetGetConnection */
2196 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
2198 char buffer[1024];
2199 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
2200 HANDLE mgr;
2201 DWORD ret = WN_NOT_CONNECTED;
2202 DWORD bytes_returned;
2204 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
2205 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
2206 0, 0 )) == INVALID_HANDLE_VALUE)
2208 ERR( "failed to open mount manager err %u\n", GetLastError() );
2209 return ret;
2211 memset( data, 0, sizeof(*data) );
2212 data->letter = letter;
2213 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
2214 data, sizeof(buffer), &bytes_returned, NULL ))
2216 char *p, *mount_point = buffer + data->mount_point_offset;
2217 DWORD len;
2219 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
2221 mount_point += 2;
2222 mount_point[0] = '\\';
2223 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
2225 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
2226 if (len > *size)
2228 *size = len;
2229 ret = WN_MORE_DATA;
2231 else
2233 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
2234 ret = WN_SUCCESS;
2238 CloseHandle( mgr );
2239 return ret;
2242 /**************************************************************************
2243 * WNetGetConnectionW [MPR.@]
2245 * FIXME: need to test return values under different errors
2247 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
2248 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
2250 DWORD ret;
2252 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
2253 lpBufferSize);
2255 if (!lpLocalName)
2256 ret = WN_BAD_POINTER;
2257 else if (!lpBufferSize)
2258 ret = WN_BAD_POINTER;
2259 else if (!lpRemoteName && *lpBufferSize)
2260 ret = WN_BAD_POINTER;
2261 else if (!lpLocalName[0])
2262 ret = WN_BAD_LOCALNAME;
2263 else
2265 if (lpLocalName[1] == ':')
2267 switch(GetDriveTypeW(lpLocalName))
2269 case DRIVE_REMOTE:
2270 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
2271 break;
2272 case DRIVE_REMOVABLE:
2273 case DRIVE_FIXED:
2274 case DRIVE_CDROM:
2275 TRACE("file is local\n");
2276 ret = WN_NOT_CONNECTED;
2277 break;
2278 default:
2279 ret = WN_BAD_LOCALNAME;
2282 else
2283 ret = WN_BAD_LOCALNAME;
2285 if (ret)
2286 SetLastError(ret);
2287 TRACE("Returning %d\n", ret);
2288 return ret;
2291 /**************************************************************************
2292 * WNetSetConnectionA [MPR.@]
2294 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
2295 LPVOID pvValue )
2297 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
2299 SetLastError(WN_NO_NETWORK);
2300 return WN_NO_NETWORK;
2303 /**************************************************************************
2304 * WNetSetConnectionW [MPR.@]
2306 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2307 LPVOID pvValue )
2309 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2311 SetLastError(WN_NO_NETWORK);
2312 return WN_NO_NETWORK;
2315 /*****************************************************************
2316 * WNetGetUniversalNameA [MPR.@]
2318 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2319 LPVOID lpBuffer, LPDWORD lpBufferSize )
2321 DWORD err, size;
2323 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2324 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2326 switch (dwInfoLevel)
2328 case UNIVERSAL_NAME_INFO_LEVEL:
2330 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2332 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2334 err = ERROR_NOT_CONNECTED;
2335 break;
2338 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2339 if (*lpBufferSize < size)
2341 err = WN_MORE_DATA;
2342 break;
2344 info->lpUniversalName = (char *)info + sizeof(*info);
2345 lstrcpyA(info->lpUniversalName, lpLocalPath);
2346 err = WN_NO_ERROR;
2347 break;
2349 case REMOTE_NAME_INFO_LEVEL:
2350 err = WN_NOT_CONNECTED;
2351 break;
2353 default:
2354 err = WN_BAD_VALUE;
2355 break;
2358 SetLastError(err);
2359 return err;
2362 /*****************************************************************
2363 * WNetGetUniversalNameW [MPR.@]
2365 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2366 LPVOID lpBuffer, LPDWORD lpBufferSize )
2368 DWORD err, size;
2370 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2371 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2373 switch (dwInfoLevel)
2375 case UNIVERSAL_NAME_INFO_LEVEL:
2377 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2379 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2381 err = ERROR_NOT_CONNECTED;
2382 break;
2385 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2386 if (*lpBufferSize < size)
2388 *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;
2410 /*****************************************************************
2411 * WNetClearConnections [MPR.@]
2413 DWORD WINAPI WNetClearConnections ( HWND owner )
2415 HANDLE connected;
2416 PWSTR connection;
2417 DWORD ret, size, count;
2418 NETRESOURCEW * resources, * iter;
2420 ret = WNetOpenEnumW(RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL, &connected);
2421 if (ret != WN_SUCCESS)
2423 if (ret != WN_NO_NETWORK)
2425 return ret;
2428 /* Means no provider, then, clearing is OK */
2429 return WN_SUCCESS;
2432 size = 0x1000;
2433 resources = HeapAlloc(GetProcessHeap(), 0, size);
2434 if (!resources)
2436 WNetCloseEnum(connected);
2437 return WN_OUT_OF_MEMORY;
2440 for (;;)
2442 size = 0x1000;
2443 count = -1;
2445 memset(resources, 0, size);
2446 ret = WNetEnumResourceW(connected, &count, resources, &size);
2447 if (ret == WN_SUCCESS || ret == WN_MORE_DATA)
2449 for (iter = resources; count; count--, iter++)
2451 if (iter->lpLocalName && iter->lpLocalName[0])
2452 connection = iter->lpLocalName;
2453 else
2454 connection = iter->lpRemoteName;
2456 WNetCancelConnection2W(connection, 0, TRUE);
2459 else
2460 break;
2463 HeapFree(GetProcessHeap(), 0, resources);
2464 WNetCloseEnum(connected);
2466 return ret;
2471 * Other Functions
2474 /**************************************************************************
2475 * WNetGetUserA [MPR.@]
2477 * FIXME: we should not return ourselves, but the owner of the drive lpName
2479 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2481 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2482 return GetLastError();
2485 /*****************************************************************
2486 * WNetGetUserW [MPR.@]
2488 * FIXME: we should not return ourselves, but the owner of the drive lpName
2490 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2492 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2493 return GetLastError();
2496 /*********************************************************************
2497 * WNetConnectionDialog [MPR.@]
2499 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2501 CONNECTDLGSTRUCTW conn_dlg;
2502 NETRESOURCEW net_res;
2504 ZeroMemory(&conn_dlg, sizeof(conn_dlg));
2505 ZeroMemory(&net_res, sizeof(net_res));
2507 conn_dlg.cbStructure = sizeof(conn_dlg);
2508 conn_dlg.lpConnRes = &net_res;
2509 conn_dlg.hwndOwner = hwnd;
2510 net_res.dwType = dwType;
2512 return WNetConnectionDialog1W(&conn_dlg);
2515 /*********************************************************************
2516 * WNetConnectionDialog1A [MPR.@]
2518 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2520 FIXME( "(%p): stub\n", lpConnDlgStruct );
2522 SetLastError(WN_NO_NETWORK);
2523 return WN_NO_NETWORK;
2526 /*********************************************************************
2527 * WNetConnectionDialog1W [MPR.@]
2529 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2531 FIXME( "(%p): stub\n", lpConnDlgStruct );
2533 SetLastError(WN_NO_NETWORK);
2534 return WN_NO_NETWORK;
2537 /*********************************************************************
2538 * WNetDisconnectDialog [MPR.@]
2540 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2542 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2544 SetLastError(WN_NO_NETWORK);
2545 return WN_NO_NETWORK;
2548 /*********************************************************************
2549 * WNetDisconnectDialog1A [MPR.@]
2551 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2553 FIXME( "(%p): stub\n", lpConnDlgStruct );
2555 SetLastError(WN_NO_NETWORK);
2556 return WN_NO_NETWORK;
2559 /*********************************************************************
2560 * WNetDisconnectDialog1W [MPR.@]
2562 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2564 FIXME( "(%p): stub\n", lpConnDlgStruct );
2566 SetLastError(WN_NO_NETWORK);
2567 return WN_NO_NETWORK;
2570 /*********************************************************************
2571 * WNetGetLastErrorA [MPR.@]
2573 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2574 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2575 LPSTR lpNameBuf, DWORD nNameBufSize )
2577 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2578 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2580 SetLastError(WN_NO_NETWORK);
2581 return WN_NO_NETWORK;
2584 /*********************************************************************
2585 * WNetGetLastErrorW [MPR.@]
2587 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2588 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2589 LPWSTR lpNameBuf, DWORD nNameBufSize )
2591 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2592 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2594 SetLastError(WN_NO_NETWORK);
2595 return WN_NO_NETWORK;
2598 /*********************************************************************
2599 * WNetGetNetworkInformationA [MPR.@]
2601 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2602 LPNETINFOSTRUCT lpNetInfoStruct )
2604 DWORD ret;
2606 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2608 if (!lpProvider)
2609 ret = WN_BAD_POINTER;
2610 else
2612 int len;
2614 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2615 if (len)
2617 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2619 if (wideProvider)
2621 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2622 len);
2623 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2624 HeapFree(GetProcessHeap(), 0, wideProvider);
2626 else
2627 ret = WN_OUT_OF_MEMORY;
2629 else
2630 ret = GetLastError();
2632 if (ret)
2633 SetLastError(ret);
2634 TRACE("Returning %d\n", ret);
2635 return ret;
2638 /*********************************************************************
2639 * WNetGetNetworkInformationW [MPR.@]
2641 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2642 LPNETINFOSTRUCT lpNetInfoStruct )
2644 DWORD ret;
2646 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2648 if (!lpProvider)
2649 ret = WN_BAD_POINTER;
2650 else if (!lpNetInfoStruct)
2651 ret = WN_BAD_POINTER;
2652 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2653 ret = WN_BAD_VALUE;
2654 else
2656 if (providerTable && providerTable->numProviders)
2658 DWORD providerIndex = _findProviderIndexW(lpProvider);
2660 if (providerIndex != BAD_PROVIDER_INDEX)
2662 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2663 lpNetInfoStruct->dwProviderVersion =
2664 providerTable->table[providerIndex].dwSpecVersion;
2665 lpNetInfoStruct->dwStatus = NO_ERROR;
2666 lpNetInfoStruct->dwCharacteristics = 0;
2667 lpNetInfoStruct->dwHandle = 0;
2668 lpNetInfoStruct->wNetType =
2669 HIWORD(providerTable->table[providerIndex].dwNetType);
2670 lpNetInfoStruct->dwPrinters = -1;
2671 lpNetInfoStruct->dwDrives = -1;
2672 ret = WN_SUCCESS;
2674 else
2675 ret = WN_BAD_PROVIDER;
2677 else
2678 ret = WN_NO_NETWORK;
2680 if (ret)
2681 SetLastError(ret);
2682 TRACE("Returning %d\n", ret);
2683 return ret;
2686 /*****************************************************************
2687 * WNetGetProviderNameA [MPR.@]
2689 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2690 LPSTR lpProvider, LPDWORD lpBufferSize )
2692 DWORD ret;
2694 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2695 lpBufferSize);
2697 if (!lpProvider)
2698 ret = WN_BAD_POINTER;
2699 else if (!lpBufferSize)
2700 ret = WN_BAD_POINTER;
2701 else
2703 if (providerTable)
2705 DWORD i;
2707 ret = WN_NO_NETWORK;
2708 for (i = 0; i < providerTable->numProviders &&
2709 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2710 i++)
2712 if (i < providerTable->numProviders)
2714 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2715 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2717 if (*lpBufferSize < sizeNeeded)
2719 *lpBufferSize = sizeNeeded;
2720 ret = WN_MORE_DATA;
2722 else
2724 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2725 -1, lpProvider, *lpBufferSize, NULL, NULL);
2726 ret = WN_SUCCESS;
2727 /* FIXME: is *lpBufferSize set to the number of characters
2728 * copied? */
2732 else
2733 ret = WN_NO_NETWORK;
2735 if (ret)
2736 SetLastError(ret);
2737 TRACE("Returning %d\n", ret);
2738 return ret;
2741 /*****************************************************************
2742 * WNetGetProviderNameW [MPR.@]
2744 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2745 LPWSTR lpProvider, LPDWORD lpBufferSize )
2747 DWORD ret;
2749 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2750 lpBufferSize);
2752 if (!lpProvider)
2753 ret = WN_BAD_POINTER;
2754 else if (!lpBufferSize)
2755 ret = WN_BAD_POINTER;
2756 else
2758 if (providerTable)
2760 DWORD i;
2762 ret = WN_NO_NETWORK;
2763 for (i = 0; i < providerTable->numProviders &&
2764 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2765 i++)
2767 if (i < providerTable->numProviders)
2769 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2771 if (*lpBufferSize < sizeNeeded)
2773 *lpBufferSize = sizeNeeded;
2774 ret = WN_MORE_DATA;
2776 else
2778 strcpyW(lpProvider, providerTable->table[i].name);
2779 ret = WN_SUCCESS;
2780 /* FIXME: is *lpBufferSize set to the number of characters
2781 * copied? */
2785 else
2786 ret = WN_NO_NETWORK;
2788 if (ret)
2789 SetLastError(ret);
2790 TRACE("Returning %d\n", ret);
2791 return ret;