vbscript: Fix memory leak in owned safearray iterator.
[wine.git] / dlls / mpr / wnet.c
blob999a2a0e80c5f1a059b3a0b83818953dfd17a98d
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 "mprres.h"
37 #include "wnetpriv.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(mpr);
41 /* Data structures representing network service providers. Assumes only one
42 * thread creates them, and that they are constant for the life of the process
43 * (and therefore doesn't synchronize access).
44 * FIXME: only basic provider data and enumeration-related data are implemented
45 * so far, need to implement the rest too.
47 typedef struct _WNetProvider
49 HMODULE hLib;
50 PWSTR name;
51 PF_NPGetCaps getCaps;
52 DWORD dwSpecVersion;
53 DWORD dwNetType;
54 DWORD dwEnumScopes;
55 PF_NPOpenEnum openEnum;
56 PF_NPEnumResource enumResource;
57 PF_NPCloseEnum closeEnum;
58 PF_NPGetResourceInformation getResourceInformation;
59 PF_NPAddConnection addConnection;
60 PF_NPAddConnection3 addConnection3;
61 PF_NPCancelConnection cancelConnection;
62 } WNetProvider, *PWNetProvider;
64 typedef struct _WNetProviderTable
66 LPWSTR entireNetwork;
67 DWORD numAllocated;
68 DWORD numProviders;
69 WNetProvider table[1];
70 } WNetProviderTable, *PWNetProviderTable;
72 #define WNET_ENUMERATOR_TYPE_GLOBAL 0
73 #define WNET_ENUMERATOR_TYPE_PROVIDER 1
74 #define WNET_ENUMERATOR_TYPE_CONTEXT 2
75 #define WNET_ENUMERATOR_TYPE_CONNECTED 3
76 #define WNET_ENUMERATOR_TYPE_REMEMBERED 4
78 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
79 * the enumeration; it represents one of the following types:
80 * - a global enumeration, one that's executed across all providers
81 * - a provider-specific enumeration, one that's only executed by a single
82 * provider
83 * - a context enumeration. I know this contradicts what I just said about
84 * there being no correspondence between the scope and the type, but it's
85 * necessary for the special case that a "Entire Network" entry needs to
86 * be enumerated in an enumeration of the context scope. Thus an enumeration
87 * of the context scope results in a context type enumerator, which morphs
88 * into a global enumeration (so the enumeration continues across all
89 * providers).
90 * - a remembered enumeration, not related to providers themselves, but it
91 * is a registry enumeration for saved connections
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 struct
108 HKEY registry;
109 DWORD index;
110 } remembered;
111 } specific;
112 } WNetEnumerator, *PWNetEnumerator;
114 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
116 /* Returns an index (into the global WNetProviderTable) of the provider with
117 * the given name, or BAD_PROVIDER_INDEX if not found.
119 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
121 static PWNetProviderTable providerTable;
124 * Global provider table functions
127 static void _tryLoadProvider(PCWSTR provider)
129 WCHAR serviceName[MAX_PATH];
130 HKEY hKey;
132 TRACE("%s\n", debugstr_w(provider));
133 swprintf(serviceName, ARRAY_SIZE(serviceName), L"%s%s\\NetworkProvider",
134 L"System\\CurrentControlSet\\Services\\", provider);
135 serviceName[ARRAY_SIZE(serviceName) - 1] = '\0';
136 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
137 ERROR_SUCCESS)
139 WCHAR providerPath[MAX_PATH];
140 DWORD type, size = sizeof(providerPath);
142 if (RegQueryValueExW(hKey, L"ProviderPath", NULL, &type, (BYTE *)providerPath, &size) == ERROR_SUCCESS
143 && (type == REG_SZ || type == REG_EXPAND_SZ))
145 PWSTR name = NULL;
147 if (type == REG_EXPAND_SZ)
149 WCHAR path[MAX_PATH];
150 if (ExpandEnvironmentStringsW(providerPath, path, MAX_PATH)) lstrcpyW( providerPath, path );
153 size = 0;
154 RegQueryValueExW(hKey, L"Name", NULL, NULL, NULL, &size);
155 if (size)
157 name = HeapAlloc(GetProcessHeap(), 0, size);
158 if (RegQueryValueExW(hKey, L"Name", NULL, &type, (BYTE *)name, &size) != ERROR_SUCCESS
159 || type != REG_SZ)
161 HeapFree(GetProcessHeap(), 0, name);
162 name = NULL;
165 if (name)
167 HMODULE hLib = LoadLibraryW(providerPath);
169 if (hLib)
171 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
173 PF_NPGetCaps getCaps = MPR_GETPROC(NPGetCaps);
175 TRACE("loaded lib %p\n", hLib);
176 if (getCaps)
178 DWORD connectCap;
179 PWNetProvider provider =
180 &providerTable->table[providerTable->numProviders];
182 provider->hLib = hLib;
183 provider->name = name;
184 TRACE("name is %s\n", debugstr_w(name));
185 provider->getCaps = getCaps;
186 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
187 provider->dwNetType = getCaps(WNNC_NET_TYPE);
188 TRACE("net type is 0x%08lx\n", provider->dwNetType);
189 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
190 if (provider->dwEnumScopes)
192 TRACE("supports enumeration\n");
193 provider->openEnum = MPR_GETPROC(NPOpenEnum);
194 TRACE("NPOpenEnum %p\n", provider->openEnum);
195 provider->enumResource = MPR_GETPROC(NPEnumResource);
196 TRACE("NPEnumResource %p\n", provider->enumResource);
197 provider->closeEnum = MPR_GETPROC(NPCloseEnum);
198 TRACE("NPCloseEnum %p\n", provider->closeEnum);
199 provider->getResourceInformation = MPR_GETPROC(NPGetResourceInformation);
200 TRACE("NPGetResourceInformation %p\n", provider->getResourceInformation);
201 if (!provider->openEnum ||
202 !provider->enumResource ||
203 !provider->closeEnum)
205 provider->openEnum = NULL;
206 provider->enumResource = NULL;
207 provider->closeEnum = NULL;
208 provider->dwEnumScopes = 0;
209 WARN("Couldn't load enumeration functions\n");
212 connectCap = getCaps(WNNC_CONNECTION);
213 if (connectCap & WNNC_CON_ADDCONNECTION)
214 provider->addConnection = MPR_GETPROC(NPAddConnection);
215 if (connectCap & WNNC_CON_ADDCONNECTION3)
216 provider->addConnection3 = MPR_GETPROC(NPAddConnection3);
217 if (connectCap & WNNC_CON_CANCELCONNECTION)
218 provider->cancelConnection = MPR_GETPROC(NPCancelConnection);
219 TRACE("NPAddConnection %p\n", provider->addConnection);
220 TRACE("NPAddConnection3 %p\n", provider->addConnection3);
221 TRACE("NPCancelConnection %p\n", provider->cancelConnection);
222 providerTable->numProviders++;
224 else
226 WARN("Provider %s didn't export NPGetCaps\n",
227 debugstr_w(provider));
228 HeapFree(GetProcessHeap(), 0, name);
229 FreeLibrary(hLib);
232 #undef MPR_GETPROC
234 else
236 WARN("Couldn't load library %s for provider %s\n",
237 debugstr_w(providerPath), debugstr_w(provider));
238 HeapFree(GetProcessHeap(), 0, name);
241 else
243 WARN("Couldn't get provider name for provider %s\n",
244 debugstr_w(provider));
247 else
248 WARN("Couldn't open value ProviderPath\n");
249 RegCloseKey(hKey);
251 else
252 WARN("Couldn't open service key for provider %s\n",
253 debugstr_w(provider));
256 void wnetInit(HINSTANCE hInstDll)
258 HKEY hKey;
260 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\NetworkProvider\\Order",
261 0, KEY_READ, &hKey) == ERROR_SUCCESS)
263 DWORD size = 0;
265 RegQueryValueExW(hKey, L"ProviderOrder", NULL, NULL, NULL, &size);
266 if (size)
268 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
270 if (providers)
272 DWORD type;
274 if (RegQueryValueExW(hKey, L"ProviderOrder", NULL, &type, (BYTE *)providers, &size)
275 == ERROR_SUCCESS && type == REG_SZ)
277 PWSTR ptr;
278 DWORD numToAllocate;
280 TRACE("provider order is %s\n", debugstr_w(providers));
281 /* first count commas as a heuristic for how many to
282 * allocate space for */
283 for (ptr = providers, numToAllocate = 1; ptr; )
285 ptr = wcschr(ptr, ',');
286 if (ptr) {
287 numToAllocate++;
288 ptr++;
291 providerTable =
292 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
293 sizeof(WNetProviderTable)
294 + (numToAllocate - 1) * sizeof(WNetProvider));
295 if (providerTable)
297 PWSTR ptrPrev;
298 int entireNetworkLen;
299 LPCWSTR stringresource;
301 entireNetworkLen = LoadStringW(hInstDll,
302 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
303 providerTable->entireNetwork = HeapAlloc(
304 GetProcessHeap(), 0, (entireNetworkLen + 1) *
305 sizeof(WCHAR));
306 if (providerTable->entireNetwork)
308 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
309 providerTable->entireNetwork[entireNetworkLen] = 0;
311 providerTable->numAllocated = numToAllocate;
312 for (ptr = providers; ptr; )
314 ptrPrev = ptr;
315 ptr = wcschr(ptr, ',');
316 if (ptr)
317 *ptr++ = '\0';
318 _tryLoadProvider(ptrPrev);
322 HeapFree(GetProcessHeap(), 0, providers);
325 RegCloseKey(hKey);
329 void wnetFree(void)
331 if (providerTable)
333 DWORD i;
335 for (i = 0; i < providerTable->numProviders; i++)
337 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
338 FreeModule(providerTable->table[i].hLib);
340 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
341 HeapFree(GetProcessHeap(), 0, providerTable);
342 providerTable = NULL;
346 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
348 DWORD ret = BAD_PROVIDER_INDEX;
350 if (providerTable && providerTable->numProviders)
352 DWORD i;
354 for (i = 0; i < providerTable->numProviders &&
355 ret == BAD_PROVIDER_INDEX; i++)
356 if (!lstrcmpW(lpProvider, providerTable->table[i].name))
357 ret = i;
359 return ret;
363 * Browsing Functions
366 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
368 LPNETRESOURCEW ret;
370 if (lpNet)
372 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
373 if (ret)
375 size_t len;
377 *ret = *lpNet;
378 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
379 if (lpNet->lpRemoteName)
381 len = lstrlenW(lpNet->lpRemoteName) + 1;
382 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
383 if (ret->lpRemoteName)
384 lstrcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
388 else
389 ret = NULL;
390 return ret;
393 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
395 if (lpNet)
397 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
398 HeapFree(GetProcessHeap(), 0, lpNet);
402 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
403 DWORD dwUsage, LPNETRESOURCEW lpNet)
405 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
406 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
408 if (ret)
410 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
411 ret->dwScope = dwScope;
412 ret->dwType = dwType;
413 ret->dwUsage = dwUsage;
414 ret->specific.net = _copyNetResourceForEnumW(lpNet);
416 return ret;
419 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
420 DWORD dwUsage, DWORD index, HANDLE handle)
422 PWNetEnumerator ret;
424 if (!providerTable || index >= providerTable->numProviders)
425 ret = NULL;
426 else
428 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
429 if (ret)
431 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
432 ret->providerIndex = index;
433 ret->dwScope = dwScope;
434 ret->dwType = dwType;
435 ret->dwUsage = dwUsage;
436 ret->handle = handle;
439 return ret;
442 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
443 DWORD dwUsage)
445 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
446 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
448 if (ret)
450 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
451 ret->dwScope = dwScope;
452 ret->dwType = dwType;
453 ret->dwUsage = dwUsage;
455 return ret;
458 static PWNetEnumerator _createConnectedEnumerator(DWORD dwScope, DWORD dwType,
459 DWORD dwUsage)
461 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
462 if (ret)
464 ret->enumType = WNET_ENUMERATOR_TYPE_CONNECTED;
465 ret->dwScope = dwScope;
466 ret->dwType = dwType;
467 ret->dwUsage = dwUsage;
468 ret->specific.handles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HANDLE) * providerTable->numProviders);
469 if (!ret->specific.handles)
471 HeapFree(GetProcessHeap(), 0, ret);
472 ret = NULL;
475 return ret;
478 static PWNetEnumerator _createRememberedEnumerator(DWORD dwScope, DWORD dwType,
479 HKEY remembered)
481 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
482 if (ret)
484 ret->enumType = WNET_ENUMERATOR_TYPE_REMEMBERED;
485 ret->dwScope = dwScope;
486 ret->dwType = dwType;
487 ret->specific.remembered.registry = remembered;
489 return ret;
492 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
493 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
494 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
495 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
496 * if not all members of the array could be thunked, and something else on
497 * failure.
499 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
500 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
502 DWORD i, numToThunk, totalBytes, ret;
503 LPSTR strNext;
505 if (!lpNetArrayIn)
506 return WN_BAD_POINTER;
507 if (!lpcCount)
508 return WN_BAD_POINTER;
509 if (*lpcCount == -1)
510 return WN_BAD_VALUE;
511 if (!lpBuffer)
512 return WN_BAD_POINTER;
513 if (!lpBufferSize)
514 return WN_BAD_POINTER;
516 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
518 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
520 totalBytes += sizeof(NETRESOURCEA);
521 if (lpNet->lpLocalName)
522 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
523 -1, NULL, 0, NULL, NULL);
524 if (lpNet->lpRemoteName)
525 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
526 -1, NULL, 0, NULL, NULL);
527 if (lpNet->lpComment)
528 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
529 -1, NULL, 0, NULL, NULL);
530 if (lpNet->lpProvider)
531 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
532 -1, NULL, 0, NULL, NULL);
533 if (totalBytes < *lpBufferSize)
534 numToThunk = i + 1;
536 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
537 for (i = 0; i < numToThunk; i++)
539 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
540 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
542 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
543 /* lie about string lengths, we already verified how many
544 * we have space for above
546 if (lpNetIn->lpLocalName)
548 lpNetOut->lpLocalName = strNext;
549 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
550 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
552 if (lpNetIn->lpRemoteName)
554 lpNetOut->lpRemoteName = strNext;
555 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
556 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
558 if (lpNetIn->lpComment)
560 lpNetOut->lpComment = strNext;
561 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
562 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
564 if (lpNetIn->lpProvider)
566 lpNetOut->lpProvider = strNext;
567 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
568 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
571 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
572 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk,
573 *lpcCount, ret);
574 return ret;
577 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
578 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
579 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
580 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
581 * if not all members of the array could be thunked, and something else on
582 * failure.
584 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
585 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
587 DWORD i, numToThunk, totalBytes, ret;
588 LPWSTR strNext;
590 if (!lpNetArrayIn)
591 return WN_BAD_POINTER;
592 if (!lpcCount)
593 return WN_BAD_POINTER;
594 if (*lpcCount == -1)
595 return WN_BAD_VALUE;
596 if (!lpBuffer)
597 return WN_BAD_POINTER;
598 if (!lpBufferSize)
599 return WN_BAD_POINTER;
601 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
603 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
605 totalBytes += sizeof(NETRESOURCEW);
606 if (lpNet->lpLocalName)
607 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
608 -1, NULL, 0) * sizeof(WCHAR);
609 if (lpNet->lpRemoteName)
610 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
611 -1, NULL, 0) * sizeof(WCHAR);
612 if (lpNet->lpComment)
613 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
614 -1, NULL, 0) * sizeof(WCHAR);
615 if (lpNet->lpProvider)
616 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
617 -1, NULL, 0) * sizeof(WCHAR);
618 if (totalBytes < *lpBufferSize)
619 numToThunk = i + 1;
621 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
622 for (i = 0; i < numToThunk; i++)
624 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
625 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
627 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
628 /* lie about string lengths, we already verified how many
629 * we have space for above
631 if (lpNetIn->lpLocalName)
633 lpNetOut->lpLocalName = strNext;
634 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
635 -1, lpNetOut->lpLocalName, *lpBufferSize);
637 if (lpNetIn->lpRemoteName)
639 lpNetOut->lpRemoteName = strNext;
640 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
641 -1, lpNetOut->lpRemoteName, *lpBufferSize);
643 if (lpNetIn->lpComment)
645 lpNetOut->lpComment = strNext;
646 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
647 -1, lpNetOut->lpComment, *lpBufferSize);
649 if (lpNetIn->lpProvider)
651 lpNetOut->lpProvider = strNext;
652 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
653 -1, lpNetOut->lpProvider, *lpBufferSize);
656 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
657 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk,
658 *lpcCount, ret);
659 return ret;
662 /*********************************************************************
663 * WNetOpenEnumA [MPR.@]
665 * See comments for WNetOpenEnumW.
667 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
668 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
670 DWORD ret;
672 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
673 dwScope, dwType, dwUsage, lpNet, lphEnum );
675 if (!lphEnum)
676 ret = WN_BAD_POINTER;
677 else if (!providerTable || providerTable->numProviders == 0)
679 *lphEnum = NULL;
680 ret = WN_NO_NETWORK;
682 else
684 if (lpNet)
686 LPNETRESOURCEW lpNetWide = NULL;
687 BYTE buf[1024];
688 DWORD size = sizeof(buf), count = 1;
689 BOOL allocated = FALSE;
691 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
692 if (ret == WN_MORE_DATA)
694 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
695 size);
696 if (lpNetWide)
698 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
699 &size);
700 allocated = TRUE;
702 else
703 ret = WN_OUT_OF_MEMORY;
705 else if (ret == WN_SUCCESS)
706 lpNetWide = (LPNETRESOURCEW)buf;
707 if (ret == WN_SUCCESS)
708 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
709 lphEnum);
710 if (allocated)
711 HeapFree(GetProcessHeap(), 0, lpNetWide);
713 else
714 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
716 if (ret)
717 SetLastError(ret);
718 TRACE("Returning %ld\n", ret);
719 return ret;
722 /*********************************************************************
723 * WNetOpenEnumW [MPR.@]
725 * Network enumeration has way too many parameters, so I'm not positive I got
726 * them right. What I've got so far:
728 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
729 * all the network providers should be enumerated.
731 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
732 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
733 * lpProvider is set, all the network providers should be enumerated.
734 * (This means the enumeration is a list of network providers, not that the
735 * enumeration is passed on to the providers.)
737 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
738 * resource matches the "Entire Network" resource (no remote name, no
739 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
740 * enumeration is done on every network provider.
742 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
743 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
744 * only to the given network provider.
746 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
747 * no lpProvider is set, enumeration will be tried on every network provider,
748 * in the order in which they're loaded.
750 * - The LPNETRESOURCE should be disregarded for scopes besides
751 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
752 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
754 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
755 * resource in the enumerated list, as well as any machines in your
756 * workgroup. The machines in your workgroup come from doing a
757 * RESOURCE_CONTEXT enumeration of every Network Provider.
759 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
760 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
762 DWORD ret;
764 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
765 dwScope, dwType, dwUsage, lpNet, lphEnum );
767 if (!lphEnum)
768 ret = WN_BAD_POINTER;
769 else if (!providerTable || providerTable->numProviders == 0)
771 *lphEnum = NULL;
772 ret = WN_NO_NETWORK;
774 else
776 switch (dwScope)
778 case RESOURCE_GLOBALNET:
779 if (lpNet)
781 if (lpNet->lpProvider)
783 DWORD index = _findProviderIndexW(lpNet->lpProvider);
785 if (index != BAD_PROVIDER_INDEX)
787 if (providerTable->table[index].openEnum &&
788 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
790 HANDLE handle;
791 PWSTR RemoteName = lpNet->lpRemoteName;
793 if ((lpNet->dwUsage & RESOURCEUSAGE_CONTAINER) &&
794 RemoteName && !lstrcmpW(RemoteName, lpNet->lpProvider))
795 lpNet->lpRemoteName = NULL;
797 ret = providerTable->table[index].openEnum(
798 dwScope, dwType, dwUsage, lpNet, &handle);
799 if (ret == WN_SUCCESS)
801 *lphEnum = _createProviderEnumerator(
802 dwScope, dwType, dwUsage, index, handle);
803 ret = *lphEnum ? WN_SUCCESS :
804 WN_OUT_OF_MEMORY;
807 lpNet->lpRemoteName = RemoteName;
809 else
810 ret = WN_NOT_SUPPORTED;
812 else
813 ret = WN_BAD_PROVIDER;
815 else if (lpNet->lpRemoteName)
817 *lphEnum = _createGlobalEnumeratorW(dwScope,
818 dwType, dwUsage, lpNet);
819 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
821 else
823 if (lpNet->lpComment && !lstrcmpW(lpNet->lpComment,
824 providerTable->entireNetwork))
826 /* comment matches the "Entire Network", enumerate
827 * global scope of every provider
829 *lphEnum = _createGlobalEnumeratorW(dwScope,
830 dwType, dwUsage, lpNet);
832 else
834 /* this is the same as not having passed lpNet */
835 *lphEnum = _createGlobalEnumeratorW(dwScope,
836 dwType, dwUsage, NULL);
838 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
841 else
843 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
844 dwUsage, lpNet);
845 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
847 break;
848 case RESOURCE_CONTEXT:
849 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
850 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
851 break;
852 case RESOURCE_CONNECTED:
853 *lphEnum = _createConnectedEnumerator(dwScope, dwType, dwUsage);
854 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
855 break;
856 case RESOURCE_REMEMBERED:
858 HKEY remembered, user_profile;
860 ret = WN_OUT_OF_MEMORY;
861 if (RegOpenCurrentUser(KEY_READ, &user_profile) == ERROR_SUCCESS)
863 WCHAR subkey[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
865 if (RegOpenKeyExW(user_profile, subkey, 0, KEY_READ, &remembered) == ERROR_SUCCESS)
867 *lphEnum = _createRememberedEnumerator(dwScope, dwType, remembered);
868 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
871 RegCloseKey(user_profile);
874 break;
875 default:
876 WARN("unknown scope 0x%08lx\n", dwScope);
877 ret = WN_BAD_VALUE;
880 if (ret)
881 SetLastError(ret);
882 TRACE("Returning %ld\n", ret);
883 return ret;
886 /*********************************************************************
887 * WNetEnumResourceA [MPR.@]
889 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
890 LPVOID lpBuffer, LPDWORD lpBufferSize )
892 DWORD ret;
894 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
896 if (!hEnum)
897 ret = WN_BAD_POINTER;
898 else if (!lpcCount)
899 ret = WN_BAD_POINTER;
900 else if (!lpBuffer)
901 ret = WN_BAD_POINTER;
902 else if (!lpBufferSize)
903 ret = WN_BAD_POINTER;
904 else if (*lpBufferSize < sizeof(NETRESOURCEA))
906 *lpBufferSize = sizeof(NETRESOURCEA);
907 ret = WN_MORE_DATA;
909 else
911 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
912 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
914 if (localBuffer)
916 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
917 &localSize);
918 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
920 /* FIXME: this isn't necessarily going to work in the case of
921 * WN_MORE_DATA, because our enumerator may have moved on to
922 * the next provider. MSDN states that a large (16KB) buffer
923 * size is the appropriate usage of this function, so
924 * hopefully it won't be an issue.
926 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
927 lpBuffer, lpBufferSize);
928 *lpcCount = localCount;
930 HeapFree(GetProcessHeap(), 0, localBuffer);
932 else
933 ret = WN_OUT_OF_MEMORY;
935 if (ret)
936 SetLastError(ret);
937 TRACE("Returning %ld\n", ret);
938 return ret;
941 static DWORD _countProviderBytesW(PWNetProvider provider)
943 DWORD ret;
945 if (provider)
947 ret = sizeof(NETRESOURCEW);
948 ret += 2 * (lstrlenW(provider->name) + 1) * sizeof(WCHAR);
950 else
951 ret = 0;
952 return ret;
955 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
956 LPVOID lpBuffer, const DWORD *lpBufferSize)
958 DWORD ret;
960 if (!enumerator)
961 return WN_BAD_POINTER;
962 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
963 return WN_BAD_VALUE;
964 if (!lpcCount)
965 return WN_BAD_POINTER;
966 if (!lpBuffer)
967 return WN_BAD_POINTER;
968 if (!lpBufferSize)
969 return WN_BAD_POINTER;
970 if (*lpBufferSize < sizeof(NETRESOURCEA))
971 return WN_MORE_DATA;
973 if (!providerTable || enumerator->providerIndex >=
974 providerTable->numProviders)
975 ret = WN_NO_MORE_ENTRIES;
976 else
978 DWORD bytes = 0, count = 0, countLimit, i;
979 LPNETRESOURCEW resource;
980 LPWSTR strNext;
982 countLimit = *lpcCount == -1 ?
983 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
984 while (count < countLimit && bytes < *lpBufferSize)
986 DWORD bytesNext = _countProviderBytesW(
987 &providerTable->table[count + enumerator->providerIndex]);
989 if (bytes + bytesNext < *lpBufferSize)
991 bytes += bytesNext;
992 count++;
995 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
996 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
998 resource->dwScope = RESOURCE_GLOBALNET;
999 resource->dwType = RESOURCETYPE_ANY;
1000 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
1001 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
1002 RESOURCEUSAGE_RESERVED;
1003 resource->lpLocalName = NULL;
1004 resource->lpRemoteName = strNext;
1005 lstrcpyW(resource->lpRemoteName,
1006 providerTable->table[i + enumerator->providerIndex].name);
1007 strNext += lstrlenW(resource->lpRemoteName) + 1;
1008 resource->lpComment = NULL;
1009 resource->lpProvider = strNext;
1010 lstrcpyW(resource->lpProvider,
1011 providerTable->table[i + enumerator->providerIndex].name);
1012 strNext += lstrlenW(resource->lpProvider) + 1;
1014 enumerator->providerIndex += count;
1015 *lpcCount = count;
1016 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
1018 TRACE("Returning %ld\n", ret);
1019 return ret;
1022 /* Advances the enumerator (assumed to be a global enumerator) to the next
1023 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1024 * not open a handle with the next provider.
1025 * If the existing handle is NULL, may leave the enumerator unchanged, since
1026 * the current provider may support the desired scope.
1027 * If the existing handle is not NULL, closes it before moving on.
1028 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1029 * provider, and another error on failure.
1031 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
1033 if (!enumerator)
1034 return WN_BAD_POINTER;
1035 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1036 return WN_BAD_VALUE;
1037 if (!providerTable || enumerator->providerIndex >=
1038 providerTable->numProviders)
1039 return WN_NO_MORE_ENTRIES;
1041 if (enumerator->providerDone)
1043 DWORD dwEnum = 0;
1044 enumerator->providerDone = FALSE;
1045 if (enumerator->handle)
1047 providerTable->table[enumerator->providerIndex].closeEnum(
1048 enumerator->handle);
1049 enumerator->handle = NULL;
1050 enumerator->providerIndex++;
1052 if (enumerator->dwScope == RESOURCE_CONNECTED)
1053 dwEnum = WNNC_ENUM_LOCAL;
1054 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
1055 dwEnum = WNNC_ENUM_GLOBAL;
1056 else if (enumerator->dwScope == RESOURCE_CONTEXT)
1057 dwEnum = WNNC_ENUM_CONTEXT;
1058 for (; enumerator->providerIndex < providerTable->numProviders &&
1059 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
1060 & dwEnum); enumerator->providerIndex++)
1063 return enumerator->providerIndex < providerTable->numProviders ?
1064 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1067 /* "Passes through" call to the next provider that supports the enumeration
1068 * type.
1069 * FIXME: if one call to a provider's enumerator succeeds while there's still
1070 * space in lpBuffer, I don't call to the next provider. The caller may not
1071 * expect that it should call EnumResourceW again with a return value of
1072 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1073 * may have to be moved around a bit, ick.
1075 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1076 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1078 DWORD ret;
1080 if (!enumerator)
1081 return WN_BAD_POINTER;
1082 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1083 return WN_BAD_VALUE;
1084 if (!lpcCount)
1085 return WN_BAD_POINTER;
1086 if (!lpBuffer)
1087 return WN_BAD_POINTER;
1088 if (!lpBufferSize)
1089 return WN_BAD_POINTER;
1090 if (*lpBufferSize < sizeof(NETRESOURCEW))
1091 return WN_MORE_DATA;
1093 ret = _globalEnumeratorAdvance(enumerator);
1094 if (ret == WN_SUCCESS)
1096 ret = providerTable->table[enumerator->providerIndex].
1097 openEnum(enumerator->dwScope, enumerator->dwType,
1098 enumerator->dwUsage, enumerator->specific.net,
1099 &enumerator->handle);
1100 if (ret == WN_SUCCESS)
1102 ret = providerTable->table[enumerator->providerIndex].
1103 enumResource(enumerator->handle, lpcCount, lpBuffer,
1104 lpBufferSize);
1105 if (ret != WN_MORE_DATA)
1106 enumerator->providerDone = TRUE;
1109 TRACE("Returning %ld\n", ret);
1110 return ret;
1113 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1114 LPVOID lpBuffer, LPDWORD lpBufferSize)
1116 DWORD ret;
1118 if (!enumerator)
1119 return WN_BAD_POINTER;
1120 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1121 return WN_BAD_VALUE;
1122 if (!lpcCount)
1123 return WN_BAD_POINTER;
1124 if (!lpBuffer)
1125 return WN_BAD_POINTER;
1126 if (!lpBufferSize)
1127 return WN_BAD_POINTER;
1128 if (*lpBufferSize < sizeof(NETRESOURCEW))
1129 return WN_MORE_DATA;
1130 if (!providerTable)
1131 return WN_NO_NETWORK;
1133 switch (enumerator->dwScope)
1135 case RESOURCE_GLOBALNET:
1136 if (enumerator->specific.net)
1137 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1138 lpBuffer, lpBufferSize);
1139 else
1140 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1141 lpBufferSize);
1142 break;
1143 case RESOURCE_CONTEXT:
1144 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1145 lpBufferSize);
1146 break;
1147 default:
1148 WARN("unexpected scope 0x%08lx\n", enumerator->dwScope);
1149 ret = WN_NO_MORE_ENTRIES;
1151 TRACE("Returning %ld\n", ret);
1152 return ret;
1155 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1156 LPVOID lpBuffer, LPDWORD lpBufferSize)
1158 if (!enumerator)
1159 return WN_BAD_POINTER;
1160 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1161 return WN_BAD_VALUE;
1162 if (!enumerator->handle)
1163 return WN_BAD_VALUE;
1164 if (!lpcCount)
1165 return WN_BAD_POINTER;
1166 if (!lpBuffer)
1167 return WN_BAD_POINTER;
1168 if (!lpBufferSize)
1169 return WN_BAD_POINTER;
1170 if (!providerTable)
1171 return WN_NO_NETWORK;
1172 if (enumerator->providerIndex >= providerTable->numProviders)
1173 return WN_NO_MORE_ENTRIES;
1174 if (!providerTable->table[enumerator->providerIndex].enumResource)
1175 return WN_BAD_VALUE;
1176 return providerTable->table[enumerator->providerIndex].enumResource(
1177 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1180 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1181 LPVOID lpBuffer, LPDWORD lpBufferSize)
1183 DWORD ret;
1184 size_t cchEntireNetworkLen, bytesNeeded;
1186 if (!enumerator)
1187 return WN_BAD_POINTER;
1188 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1189 return WN_BAD_VALUE;
1190 if (!lpcCount)
1191 return WN_BAD_POINTER;
1192 if (!lpBuffer)
1193 return WN_BAD_POINTER;
1194 if (!lpBufferSize)
1195 return WN_BAD_POINTER;
1196 if (!providerTable)
1197 return WN_NO_NETWORK;
1199 cchEntireNetworkLen = lstrlenW(providerTable->entireNetwork) + 1;
1200 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1201 if (*lpBufferSize < bytesNeeded)
1203 *lpBufferSize = bytesNeeded;
1204 ret = WN_MORE_DATA;
1206 else
1208 LPNETRESOURCEW lpNet = lpBuffer;
1210 lpNet->dwScope = RESOURCE_GLOBALNET;
1211 lpNet->dwType = enumerator->dwType;
1212 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1213 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1214 lpNet->lpLocalName = NULL;
1215 lpNet->lpRemoteName = NULL;
1216 lpNet->lpProvider = NULL;
1217 /* odd, but correct: put comment at end of buffer, so it won't get
1218 * overwritten by subsequent calls to a provider's enumResource
1220 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1221 (cchEntireNetworkLen * sizeof(WCHAR)));
1222 lstrcpyW(lpNet->lpComment, providerTable->entireNetwork);
1223 ret = WN_SUCCESS;
1225 if (ret == WN_SUCCESS)
1227 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1229 /* "Entire Network" entry enumerated--morph this into a global
1230 * enumerator. enumerator->lpNet continues to be NULL, since it has
1231 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1233 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1234 ret = _enumerateGlobalW(enumerator, lpcCount,
1235 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1236 if (ret == WN_SUCCESS)
1238 /* reflect the fact that we already enumerated "Entire Network" */
1239 (*lpcCount)++;
1240 *lpBufferSize = bufferSize + bytesNeeded;
1242 else
1244 /* the provider enumeration failed, but we already succeeded in
1245 * enumerating "Entire Network"--leave type as global to allow a
1246 * retry, but indicate success with a count of one.
1248 ret = WN_SUCCESS;
1249 *lpcCount = 1;
1250 *lpBufferSize = bytesNeeded;
1253 TRACE("Returning %ld\n", ret);
1254 return ret;
1257 static DWORD _copyStringToEnumW(const WCHAR *source, DWORD* left, void** end)
1259 DWORD len;
1260 WCHAR* local = *end;
1262 len = lstrlenW(source) + 1;
1263 len *= sizeof(WCHAR);
1264 if (*left < len)
1265 return WN_MORE_DATA;
1267 local -= (len / sizeof(WCHAR));
1268 memcpy(local, source, len);
1269 *left -= len;
1270 *end = local;
1272 return WN_SUCCESS;
1275 static DWORD _enumerateConnectedW(PWNetEnumerator enumerator, DWORD* user_count,
1276 void* user_buffer, DWORD* user_size)
1278 DWORD ret, index, count, total_count, size, i, left;
1279 void* end;
1280 NETRESOURCEW* curr, * buffer;
1281 HANDLE* handles;
1283 if (!enumerator)
1284 return WN_BAD_POINTER;
1285 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONNECTED)
1286 return WN_BAD_VALUE;
1287 if (!user_count || !user_buffer || !user_size)
1288 return WN_BAD_POINTER;
1289 if (!providerTable)
1290 return WN_NO_NETWORK;
1292 handles = enumerator->specific.handles;
1293 left = *user_size;
1294 size = *user_size;
1295 buffer = HeapAlloc(GetProcessHeap(), 0, *user_size);
1296 if (!buffer)
1297 return WN_NO_NETWORK;
1299 curr = user_buffer;
1300 end = (char *)user_buffer + size;
1301 count = *user_count;
1302 total_count = 0;
1304 ret = WN_NO_MORE_ENTRIES;
1305 for (index = 0; index < providerTable->numProviders; index++)
1307 if (providerTable->table[index].dwEnumScopes)
1309 if (handles[index] == 0)
1311 ret = providerTable->table[index].openEnum(enumerator->dwScope,
1312 enumerator->dwType,
1313 enumerator->dwUsage,
1314 NULL, &handles[index]);
1315 if (ret != WN_SUCCESS)
1316 continue;
1319 ret = providerTable->table[index].enumResource(handles[index],
1320 &count, buffer,
1321 &size);
1322 total_count += count;
1323 if (ret == WN_MORE_DATA)
1324 break;
1326 if (ret == WN_SUCCESS)
1328 for (i = 0; i < count; ++i)
1330 if (left < sizeof(NETRESOURCEW))
1332 ret = WN_MORE_DATA;
1333 break;
1336 memcpy(curr, &buffer[i], sizeof(NETRESOURCEW));
1337 left -= sizeof(NETRESOURCEW);
1339 ret = _copyStringToEnumW(buffer[i].lpLocalName, &left, &end);
1340 if (ret == WN_MORE_DATA)
1341 break;
1342 curr->lpLocalName = end;
1344 ret = _copyStringToEnumW(buffer[i].lpRemoteName, &left, &end);
1345 if (ret == WN_MORE_DATA)
1346 break;
1347 curr->lpRemoteName = end;
1349 ret = _copyStringToEnumW(buffer[i].lpProvider, &left, &end);
1350 if (ret == WN_MORE_DATA)
1351 break;
1352 curr->lpProvider = end;
1354 ++curr;
1357 size = left;
1360 if (*user_count != -1)
1361 count = *user_count - total_count;
1362 else
1363 count = *user_count;
1367 if (total_count == 0)
1368 ret = WN_NO_MORE_ENTRIES;
1370 *user_count = total_count;
1371 if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
1372 ret = WN_SUCCESS;
1374 HeapFree(GetProcessHeap(), 0, buffer);
1376 TRACE("Returning %ld\n", ret);
1377 return ret;
1380 static WCHAR *get_reg_str(HKEY hkey, const WCHAR *value, DWORD *len)
1382 DWORD type;
1383 WCHAR *ret = NULL;
1385 if (!RegQueryValueExW(hkey, value, NULL, &type, NULL, len) && type == REG_SZ)
1387 if (!(ret = HeapAlloc(GetProcessHeap(), 0, *len))) return NULL;
1388 RegQueryValueExW(hkey, value, 0, 0, (BYTE *)ret, len);
1391 return ret;
1394 static DWORD _enumeratorRememberedW(PWNetEnumerator enumerator, DWORD* user_count,
1395 void* user_buffer, DWORD* user_size)
1397 HKEY registry, connection;
1398 WCHAR buffer[255];
1399 LONG size_left;
1400 DWORD index, ret, type, len, size, registry_size, full_size = 0, total_count;
1401 NETRESOURCEW * net_buffer = user_buffer;
1402 WCHAR * str, * registry_string;
1404 /* we will do the work in a single loop, so here is some things:
1405 * we write netresource at the begin of the user buffer
1406 * we write strings at the end of the user buffer
1408 size_left = *user_size;
1409 total_count = 0;
1410 type = enumerator->dwType;
1411 registry = enumerator->specific.remembered.registry;
1412 str = (WCHAR *)((ULONG_PTR)user_buffer + *user_size - sizeof(WCHAR));
1413 for (index = enumerator->specific.remembered.index; ; ++index)
1415 enumerator->specific.remembered.index = index;
1417 if (*user_count != -1 && total_count == *user_count)
1419 ret = WN_SUCCESS;
1420 break;
1423 len = ARRAY_SIZE(buffer);
1424 ret = RegEnumKeyExW(registry, index, buffer, &len, NULL, NULL, NULL, NULL);
1425 if (ret != ERROR_SUCCESS)
1427 if (ret == ERROR_NO_MORE_ITEMS) ret = WN_SUCCESS;
1428 break;
1431 if (RegOpenKeyExW(registry, buffer, 0, KEY_READ, &connection) != ERROR_SUCCESS)
1433 continue;
1436 full_size = sizeof(NETRESOURCEW);
1437 size_left -= sizeof(NETRESOURCEW);
1439 if (size_left > 0)
1441 size = sizeof(DWORD);
1442 RegQueryValueExW(connection, L"ConnectionType", NULL, NULL, (BYTE *)&net_buffer->dwType, &size);
1443 if (type != RESOURCETYPE_ANY && net_buffer->dwType != type)
1445 size_left += sizeof(NETRESOURCEW);
1446 RegCloseKey(connection);
1447 continue;
1450 net_buffer->dwScope = RESOURCE_REMEMBERED;
1451 net_buffer->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
1452 net_buffer->dwUsage = RESOURCEUSAGE_CONNECTABLE;
1454 else
1455 ret = WN_MORE_DATA;
1457 /* FIXME: this only supports drive letters */
1458 full_size += 3 * sizeof(WCHAR);
1459 size_left -= 3 * sizeof(WCHAR);
1460 if (size_left > 0)
1462 str -= 3;
1463 str[0] = buffer[0];
1464 str[1] = ':';
1465 str[2] = 0;
1466 net_buffer->lpLocalName = str;
1469 registry_size = 0;
1470 registry_string = get_reg_str(connection, L"ProviderName", &registry_size);
1471 if (registry_string)
1473 full_size += registry_size;
1474 size_left -= registry_size;
1476 if (size_left > 0)
1478 str -= (registry_size / sizeof(WCHAR));
1479 lstrcpyW(str, registry_string);
1480 net_buffer->lpProvider = str;
1482 else
1483 ret = WN_MORE_DATA;
1485 HeapFree(GetProcessHeap(), 0, registry_string);
1488 registry_size = 0;
1489 registry_string = get_reg_str(connection, L"RemotePath", &registry_size);
1490 if (registry_string)
1492 full_size += registry_size;
1493 size_left -= registry_size;
1495 if (size_left > 0)
1497 str -= (registry_size / sizeof(WCHAR));
1498 lstrcpyW(str, registry_string);
1499 net_buffer->lpRemoteName = str;
1501 else
1502 ret = WN_MORE_DATA;
1504 HeapFree(GetProcessHeap(), 0, registry_string);
1507 RegCloseKey(connection);
1509 net_buffer->lpComment = NULL;
1511 if (size_left < 0)
1512 break;
1514 ++total_count;
1515 ++net_buffer;
1518 if (total_count == 0)
1519 ret = WN_NO_MORE_ENTRIES;
1521 *user_count = total_count;
1523 if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
1524 ret = WN_SUCCESS;
1526 if (ret == WN_MORE_DATA)
1527 *user_size = *user_size + full_size;
1529 return ret;
1532 /*********************************************************************
1533 * WNetEnumResourceW [MPR.@]
1535 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1536 LPVOID lpBuffer, LPDWORD lpBufferSize )
1538 DWORD ret;
1540 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1542 if (!hEnum)
1543 ret = WN_BAD_POINTER;
1544 else if (!lpcCount)
1545 ret = WN_BAD_POINTER;
1546 else if (!lpBuffer)
1547 ret = WN_BAD_POINTER;
1548 else if (!lpBufferSize)
1549 ret = WN_BAD_POINTER;
1550 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1552 *lpBufferSize = sizeof(NETRESOURCEW);
1553 ret = WN_MORE_DATA;
1555 else
1557 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1559 switch (enumerator->enumType)
1561 case WNET_ENUMERATOR_TYPE_GLOBAL:
1562 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1563 lpBufferSize);
1564 break;
1565 case WNET_ENUMERATOR_TYPE_PROVIDER:
1566 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1567 lpBufferSize);
1568 break;
1569 case WNET_ENUMERATOR_TYPE_CONTEXT:
1570 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1571 lpBufferSize);
1572 break;
1573 case WNET_ENUMERATOR_TYPE_CONNECTED:
1574 ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer,
1575 lpBufferSize);
1576 break;
1577 case WNET_ENUMERATOR_TYPE_REMEMBERED:
1578 ret = _enumeratorRememberedW(enumerator, lpcCount, lpBuffer,
1579 lpBufferSize);
1580 break;
1581 default:
1582 WARN("bogus enumerator type!\n");
1583 ret = WN_NO_NETWORK;
1586 if (ret)
1587 SetLastError(ret);
1588 TRACE("Returning %ld\n", ret);
1589 return ret;
1592 /*********************************************************************
1593 * WNetCloseEnum [MPR.@]
1595 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1597 DWORD ret, index;
1598 HANDLE *handles;
1600 TRACE( "(%p)\n", hEnum );
1602 if (hEnum)
1604 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1606 switch (enumerator->enumType)
1608 case WNET_ENUMERATOR_TYPE_GLOBAL:
1609 if (enumerator->specific.net)
1610 _freeEnumNetResource(enumerator->specific.net);
1611 if (enumerator->handle)
1612 providerTable->table[enumerator->providerIndex].
1613 closeEnum(enumerator->handle);
1614 ret = WN_SUCCESS;
1615 break;
1616 case WNET_ENUMERATOR_TYPE_PROVIDER:
1617 if (enumerator->handle)
1618 providerTable->table[enumerator->providerIndex].
1619 closeEnum(enumerator->handle);
1620 ret = WN_SUCCESS;
1621 break;
1622 case WNET_ENUMERATOR_TYPE_CONNECTED:
1623 handles = enumerator->specific.handles;
1624 for (index = 0; index < providerTable->numProviders; index++)
1626 if (providerTable->table[index].dwEnumScopes && handles[index])
1627 providerTable->table[index].closeEnum(handles[index]);
1629 HeapFree(GetProcessHeap(), 0, handles);
1630 ret = WN_SUCCESS;
1631 break;
1632 case WNET_ENUMERATOR_TYPE_REMEMBERED:
1633 RegCloseKey(enumerator->specific.remembered.registry);
1634 ret = WN_SUCCESS;
1635 break;
1636 default:
1637 WARN("bogus enumerator type!\n");
1638 ret = WN_BAD_HANDLE;
1640 HeapFree(GetProcessHeap(), 0, hEnum);
1642 else
1643 ret = WN_BAD_HANDLE;
1644 if (ret)
1645 SetLastError(ret);
1646 TRACE("Returning %ld\n", ret);
1647 return ret;
1650 /*********************************************************************
1651 * WNetGetResourceInformationA [MPR.@]
1653 * See WNetGetResourceInformationW
1655 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1656 LPVOID lpBuffer, LPDWORD cbBuffer,
1657 LPSTR *lplpSystem )
1659 DWORD ret;
1661 TRACE( "(%p, %p, %p, %p)\n",
1662 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1664 if (!providerTable || providerTable->numProviders == 0)
1665 ret = WN_NO_NETWORK;
1666 else if (lpNetResource)
1668 LPNETRESOURCEW lpNetResourceW = NULL;
1669 DWORD size = 1024, count = 1;
1670 DWORD len;
1672 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1673 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1674 if (ret == WN_MORE_DATA)
1676 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1677 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1678 if (lpNetResourceW)
1679 ret = _thunkNetResourceArrayAToW(lpNetResource,
1680 &count, lpNetResourceW, &size);
1681 else
1682 ret = WN_OUT_OF_MEMORY;
1684 if (ret == WN_SUCCESS)
1686 LPWSTR lpSystemW = NULL;
1687 LPVOID lpBufferW;
1688 size = 1024;
1689 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1690 if (lpBufferW)
1692 ret = WNetGetResourceInformationW(lpNetResourceW,
1693 lpBufferW, &size, &lpSystemW);
1694 if (ret == WN_MORE_DATA)
1696 HeapFree(GetProcessHeap(), 0, lpBufferW);
1697 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1698 if (lpBufferW)
1699 ret = WNetGetResourceInformationW(lpNetResourceW,
1700 lpBufferW, &size, &lpSystemW);
1701 else
1702 ret = WN_OUT_OF_MEMORY;
1704 if (ret == WN_SUCCESS)
1706 ret = _thunkNetResourceArrayWToA(lpBufferW,
1707 &count, lpBuffer, cbBuffer);
1708 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1709 lpNetResourceW = lpBufferW;
1710 size = sizeof(NETRESOURCEA);
1711 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1712 -1, NULL, 0, NULL, NULL);
1713 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1714 -1, NULL, 0, NULL, NULL);
1716 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1717 -1, NULL, 0, NULL, NULL);
1718 if ((len) && ( size + len < *cbBuffer))
1720 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1721 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1722 *lplpSystem, len, NULL, NULL);
1723 ret = WN_SUCCESS;
1725 else
1726 ret = WN_MORE_DATA;
1728 else
1729 ret = WN_OUT_OF_MEMORY;
1730 HeapFree(GetProcessHeap(), 0, lpBufferW);
1732 else
1733 ret = WN_OUT_OF_MEMORY;
1734 HeapFree(GetProcessHeap(), 0, lpSystemW);
1736 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1738 else
1739 ret = WN_NO_NETWORK;
1741 if (ret)
1742 SetLastError(ret);
1743 TRACE("Returning %ld\n", ret);
1744 return ret;
1747 /*********************************************************************
1748 * WNetGetResourceInformationW [MPR.@]
1750 * WNetGetResourceInformationW function identifies the network provider
1751 * that owns the resource and gets information about the type of the resource.
1753 * PARAMS:
1754 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1755 * defines a network resource.
1756 * lpBuffer [ O] the pointer to buffer, containing result. It
1757 * contains NETRESOURCEW structure and strings to
1758 * which the members of the NETRESOURCEW structure
1759 * point.
1760 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1761 * in bytes.
1762 * lplpSystem [ O] the pointer to string in the output buffer,
1763 * containing the part of the resource name without
1764 * names of the server and share.
1766 * RETURNS:
1767 * NO_ERROR if the function succeeds. System error code if the function fails.
1770 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1771 LPVOID lpBuffer, LPDWORD cbBuffer,
1772 LPWSTR *lplpSystem )
1774 DWORD ret = WN_NO_NETWORK;
1775 DWORD index;
1777 TRACE( "(%p, %p, %p, %p)\n",
1778 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1780 if (!(lpBuffer))
1781 ret = WN_OUT_OF_MEMORY;
1782 else if (providerTable != NULL)
1784 /* FIXME: For function value of a variable is indifferent, it does
1785 * search of all providers in a network.
1787 for (index = 0; index < providerTable->numProviders; index++)
1789 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1790 WNNC_DLG_GETRESOURCEINFORMATION)
1792 if (providerTable->table[index].getResourceInformation)
1793 ret = providerTable->table[index].getResourceInformation(
1794 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1795 else
1796 ret = WN_NO_NETWORK;
1797 if (ret == WN_SUCCESS)
1798 break;
1802 if (ret)
1803 SetLastError(ret);
1804 return ret;
1807 /*********************************************************************
1808 * WNetGetResourceParentA [MPR.@]
1810 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1811 LPVOID lpBuffer, LPDWORD lpBufferSize )
1813 FIXME( "(%p, %p, %p): stub\n",
1814 lpNetResource, lpBuffer, lpBufferSize );
1816 SetLastError(WN_NO_NETWORK);
1817 return WN_NO_NETWORK;
1820 /*********************************************************************
1821 * WNetGetResourceParentW [MPR.@]
1823 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1824 LPVOID lpBuffer, LPDWORD lpBufferSize )
1826 FIXME( "(%p, %p, %p): stub\n",
1827 lpNetResource, lpBuffer, lpBufferSize );
1829 SetLastError(WN_NO_NETWORK);
1830 return WN_NO_NETWORK;
1836 * Connection Functions
1839 /*********************************************************************
1840 * WNetAddConnectionA [MPR.@]
1842 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1843 LPCSTR lpLocalName )
1845 NETRESOURCEA resourcesA;
1847 memset(&resourcesA, 0, sizeof(resourcesA));
1848 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1849 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1850 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1853 /*********************************************************************
1854 * WNetAddConnectionW [MPR.@]
1856 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1857 LPCWSTR lpLocalName )
1859 NETRESOURCEW resourcesW;
1861 memset(&resourcesW, 0, sizeof(resourcesW));
1862 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1863 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1864 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1867 /*********************************************************************
1868 * WNetAddConnection2A [MPR.@]
1870 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1871 LPCSTR lpPassword, LPCSTR lpUserID,
1872 DWORD dwFlags )
1874 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1875 NULL, 0, NULL);
1878 /*********************************************************************
1879 * WNetAddConnection2W [MPR.@]
1881 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1882 LPCWSTR lpPassword, LPCWSTR lpUserID,
1883 DWORD dwFlags )
1885 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1886 NULL, 0, NULL);
1889 /*********************************************************************
1890 * WNetAddConnection3A [MPR.@]
1892 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1893 LPCSTR lpPassword, LPCSTR lpUserID,
1894 DWORD dwFlags )
1896 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1897 dwFlags, NULL, 0, NULL);
1900 /*********************************************************************
1901 * WNetAddConnection3W [MPR.@]
1903 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1904 LPCWSTR lpPassword, LPCWSTR lpUserID,
1905 DWORD dwFlags )
1907 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1908 dwFlags, NULL, 0, NULL);
1911 struct use_connection_context
1913 HWND hwndOwner;
1914 NETRESOURCEW *resource;
1915 NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */
1916 WCHAR *password;
1917 WCHAR *userid;
1918 DWORD flags;
1919 void *accessname;
1920 DWORD *buffer_size;
1921 DWORD *result;
1922 DWORD (*pre_set_accessname)(struct use_connection_context*, WCHAR *);
1923 void (*set_accessname)(struct use_connection_context*, WCHAR *);
1926 static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1928 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1930 DWORD len;
1932 if (local_name)
1933 len = lstrlenW(local_name);
1934 else
1935 len = lstrlenW(ctxt->resource->lpRemoteName);
1937 if (++len > *ctxt->buffer_size)
1939 *ctxt->buffer_size = len;
1940 return ERROR_MORE_DATA;
1943 else
1944 ctxt->accessname = NULL;
1946 return ERROR_SUCCESS;
1949 static void use_connection_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1951 WCHAR *accessname = ctxt->accessname;
1952 if (local_name)
1954 lstrcpyW(accessname, local_name);
1955 if (ctxt->result)
1956 *ctxt->result = CONNECT_LOCALDRIVE;
1958 else
1959 lstrcpyW(accessname, ctxt->resource->lpRemoteName);
1962 static DWORD wnet_use_provider( struct use_connection_context *ctxt, NETRESOURCEW * netres, WNetProvider *provider, BOOLEAN redirect )
1964 DWORD caps, ret;
1966 caps = provider->getCaps(WNNC_CONNECTION);
1967 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1968 return ERROR_BAD_PROVIDER;
1970 ret = WN_ACCESS_DENIED;
1973 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1974 ret = provider->addConnection3(ctxt->hwndOwner, netres, ctxt->password, ctxt->userid, ctxt->flags);
1975 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1976 ret = provider->addConnection(netres, ctxt->password, ctxt->userid);
1978 if (ret == WN_ALREADY_CONNECTED && redirect)
1979 netres->lpLocalName[0] -= 1;
1980 } while (redirect && ret == WN_ALREADY_CONNECTED && netres->lpLocalName[0] >= 'C');
1982 if (ret == WN_SUCCESS && ctxt->accessname)
1983 ctxt->set_accessname(ctxt, netres->lpLocalName);
1985 return ret;
1988 static DWORD wnet_use_connection( struct use_connection_context *ctxt )
1990 WNetProvider *provider = NULL;
1991 DWORD index, ret = WN_NO_NETWORK;
1992 BOOL redirect = FALSE;
1993 WCHAR letter[3] = {'Z', ':', 0};
1994 NETRESOURCEW netres;
1996 if (!providerTable || providerTable->numProviders == 0)
1997 return WN_NO_NETWORK;
1999 if (!ctxt->resource)
2000 return ERROR_INVALID_PARAMETER;
2001 netres = *ctxt->resource;
2003 if (!netres.lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
2005 if (netres.dwType != RESOURCETYPE_DISK && netres.dwType != RESOURCETYPE_PRINT)
2006 return ERROR_BAD_DEV_TYPE;
2008 if (netres.dwType == RESOURCETYPE_PRINT)
2010 FIXME("Local device selection is not implemented for printers.\n");
2011 return WN_NO_NETWORK;
2014 redirect = TRUE;
2015 netres.lpLocalName = letter;
2018 if (ctxt->flags & CONNECT_INTERACTIVE)
2019 return ERROR_BAD_NET_NAME;
2021 if ((ret = ctxt->pre_set_accessname(ctxt, netres.lpLocalName)))
2022 return ret;
2024 if (netres.lpProvider)
2026 index = _findProviderIndexW(netres.lpProvider);
2027 if (index == BAD_PROVIDER_INDEX)
2028 return ERROR_BAD_PROVIDER;
2030 provider = &providerTable->table[index];
2031 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
2033 else
2035 for (index = 0; index < providerTable->numProviders; index++)
2037 provider = &providerTable->table[index];
2038 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
2039 if (ret == WN_SUCCESS || ret == WN_ALREADY_CONNECTED)
2040 break;
2044 if (ret == WN_SUCCESS && ctxt->flags & CONNECT_UPDATE_PROFILE)
2046 HKEY user_profile;
2048 if (netres.dwType == RESOURCETYPE_PRINT)
2050 FIXME("Persistent connection are not supported for printers\n");
2051 return ret;
2054 if (RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
2056 HKEY network;
2057 WCHAR subkey[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres.lpLocalName[0], 0};
2059 if (RegCreateKeyExW(user_profile, subkey, 0, NULL, REG_OPTION_NON_VOLATILE,
2060 KEY_ALL_ACCESS, NULL, &network, NULL) == ERROR_SUCCESS)
2062 DWORD dword_arg = RESOURCETYPE_DISK;
2063 DWORD len = (lstrlenW(provider->name) + 1) * sizeof(WCHAR);
2065 RegSetValueExW(network, L"ConnectionType", 0, REG_DWORD, (const BYTE *)&dword_arg,
2066 sizeof(DWORD));
2067 RegSetValueExW(network, L"ProviderName", 0, REG_SZ, (const BYTE *)provider->name, len);
2068 RegSetValueExW(network, L"ProviderType", 0, REG_DWORD,
2069 (const BYTE *)&provider->dwNetType, sizeof(DWORD));
2070 len = (lstrlenW(netres.lpRemoteName) + 1) * sizeof(WCHAR);
2071 RegSetValueExW(network, L"RemotePath", 0, REG_SZ, (const BYTE *)netres.lpRemoteName, len);
2072 len = sizeof(L"");
2073 RegSetValueExW(network, L"UserName", 0, REG_SZ, (const BYTE *) L"", len);
2074 RegCloseKey(network);
2077 RegCloseKey(user_profile);
2081 return ret;
2084 /*****************************************************************
2085 * WNetUseConnectionW [MPR.@]
2087 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
2088 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
2090 struct use_connection_context ctxt;
2092 TRACE( "(%p, %p, %p, %s, 0x%08lX, %p, %p, %p)\n",
2093 hwndOwner, resource, password, debugstr_w(userid), flags,
2094 accessname, buffer_size, result );
2096 ctxt.hwndOwner = hwndOwner;
2097 ctxt.resource = resource;
2098 ctxt.resourceA = NULL;
2099 ctxt.password = (WCHAR*)password;
2100 ctxt.userid = (WCHAR*)userid;
2101 ctxt.flags = flags;
2102 ctxt.accessname = accessname;
2103 ctxt.buffer_size = buffer_size;
2104 ctxt.result = result;
2105 ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
2106 ctxt.set_accessname = use_connection_set_accessnameW;
2108 return wnet_use_connection(&ctxt);
2111 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
2113 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
2115 DWORD len;
2117 if (local_name)
2118 len = WideCharToMultiByte(CP_ACP, 0, local_name, -1, NULL, 0, NULL, NULL) - 1;
2119 else
2120 len = strlen(ctxt->resourceA->lpRemoteName);
2122 if (++len > *ctxt->buffer_size)
2124 *ctxt->buffer_size = len;
2125 return ERROR_MORE_DATA;
2128 else
2129 ctxt->accessname = NULL;
2131 return ERROR_SUCCESS;
2134 static void use_connection_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
2136 char *accessname = ctxt->accessname;
2137 if (local_name)
2139 WideCharToMultiByte(CP_ACP, 0, local_name, -1, accessname, *ctxt->buffer_size, NULL, NULL);
2140 if (ctxt->result)
2141 *ctxt->result = CONNECT_LOCALDRIVE;
2143 else
2144 strcpy(accessname, ctxt->resourceA->lpRemoteName);
2147 static LPWSTR strdupAtoW( LPCSTR str )
2149 LPWSTR ret;
2150 INT len;
2152 if (!str) return NULL;
2153 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
2154 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2155 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
2156 return ret;
2159 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
2161 resourceW->dwScope = resourceA->dwScope;
2162 resourceW->dwType = resourceA->dwType;
2163 resourceW->dwDisplayType = resourceA->dwDisplayType;
2164 resourceW->dwUsage = resourceA->dwUsage;
2165 resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
2166 resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
2167 resourceW->lpComment = strdupAtoW(resourceA->lpComment);
2168 resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
2171 static void free_netresourceW( NETRESOURCEW *resource )
2173 HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
2174 HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
2175 HeapFree(GetProcessHeap(), 0, resource->lpComment);
2176 HeapFree(GetProcessHeap(), 0, resource->lpProvider);
2179 /*****************************************************************
2180 * WNetUseConnectionA [MPR.@]
2182 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
2183 LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
2184 DWORD *buffer_size, DWORD *result )
2186 struct use_connection_context ctxt;
2187 NETRESOURCEW resourceW;
2188 DWORD ret;
2190 TRACE( "(%p, %p, %p, %s, 0x%08lX, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
2191 accessname, buffer_size, result );
2193 netresource_a_to_w(resource, &resourceW);
2195 ctxt.hwndOwner = hwndOwner;
2196 ctxt.resource = &resourceW;
2197 ctxt.resourceA = resource;
2198 ctxt.password = strdupAtoW(password);
2199 ctxt.userid = strdupAtoW(userid);
2200 ctxt.flags = flags;
2201 ctxt.accessname = accessname;
2202 ctxt.buffer_size = buffer_size;
2203 ctxt.result = result;
2204 ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
2205 ctxt.set_accessname = use_connection_set_accessnameA;
2207 ret = wnet_use_connection(&ctxt);
2209 free_netresourceW(&resourceW);
2210 HeapFree(GetProcessHeap(), 0, ctxt.password);
2211 HeapFree(GetProcessHeap(), 0, ctxt.userid);
2213 return ret;
2216 /*********************************************************************
2217 * WNetCancelConnectionA [MPR.@]
2219 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
2221 return WNetCancelConnection2A(lpName, 0, fForce);
2224 /*********************************************************************
2225 * WNetCancelConnectionW [MPR.@]
2227 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
2229 return WNetCancelConnection2W(lpName, 0, fForce);
2232 /*********************************************************************
2233 * WNetCancelConnection2A [MPR.@]
2235 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
2237 DWORD ret;
2238 WCHAR * name = strdupAtoW(lpName);
2239 if (!name)
2240 return ERROR_NOT_CONNECTED;
2242 ret = WNetCancelConnection2W(name, dwFlags, fForce);
2243 HeapFree(GetProcessHeap(), 0, name);
2245 return ret;
2248 /*********************************************************************
2249 * WNetCancelConnection2W [MPR.@]
2251 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
2253 DWORD ret = WN_NO_NETWORK;
2254 DWORD index;
2256 if (providerTable != NULL)
2258 for (index = 0; index < providerTable->numProviders; index++)
2260 if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2261 WNNC_CON_CANCELCONNECTION)
2263 if (providerTable->table[index].cancelConnection)
2264 ret = providerTable->table[index].cancelConnection((LPWSTR)lpName, fForce);
2265 else
2266 ret = WN_NO_NETWORK;
2267 if (ret == WN_SUCCESS || ret == WN_OPEN_FILES)
2268 break;
2273 if (ret == WN_SUCCESS && dwFlags & CONNECT_UPDATE_PROFILE)
2275 HKEY user_profile;
2277 /* FIXME: Only remove it if that's a drive letter */
2278 if (iswalpha(lpName[0]) && lpName[1] == ':' &&
2279 RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
2281 WCHAR subkey[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', lpName[0], 0};
2283 RegDeleteKeyW(user_profile, subkey);
2285 RegCloseKey(user_profile);
2289 return ret;
2292 /*****************************************************************
2293 * WNetRestoreConnectionA [MPR.@]
2295 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
2297 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
2299 SetLastError(WN_NO_NETWORK);
2300 return WN_NO_NETWORK;
2303 /*****************************************************************
2304 * WNetRestoreConnectionW [MPR.@]
2306 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
2308 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
2310 SetLastError(WN_NO_NETWORK);
2311 return WN_NO_NETWORK;
2314 /**************************************************************************
2315 * WNetGetConnectionA [MPR.@]
2317 * RETURNS
2318 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2319 * - WN_NOT_CONNECTED drive is a local drive
2320 * - WN_MORE_DATA buffer isn't big enough
2321 * - WN_SUCCESS success (net path in buffer)
2323 * FIXME: need to test return values under different errors
2325 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
2326 LPSTR lpRemoteName, LPDWORD lpBufferSize )
2328 DWORD ret;
2330 if (!lpLocalName)
2331 ret = WN_BAD_POINTER;
2332 else if (!lpBufferSize)
2333 ret = WN_BAD_POINTER;
2334 else if (!lpRemoteName && *lpBufferSize)
2335 ret = WN_BAD_POINTER;
2336 else
2338 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
2340 if (len)
2342 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2344 if (wideLocalName)
2346 WCHAR wideRemoteStatic[MAX_PATH];
2347 DWORD wideRemoteSize = ARRAY_SIZE(wideRemoteStatic);
2349 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
2351 /* try once without memory allocation */
2352 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
2353 &wideRemoteSize);
2354 if (ret == WN_SUCCESS)
2356 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2357 -1, NULL, 0, NULL, NULL);
2359 if (len <= *lpBufferSize)
2361 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
2362 lpRemoteName, *lpBufferSize, NULL, NULL);
2363 ret = WN_SUCCESS;
2365 else
2367 *lpBufferSize = len;
2368 ret = WN_MORE_DATA;
2371 else if (ret == WN_MORE_DATA)
2373 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
2374 wideRemoteSize * sizeof(WCHAR));
2376 if (wideRemote)
2378 ret = WNetGetConnectionW(wideLocalName, wideRemote,
2379 &wideRemoteSize);
2380 if (ret == WN_SUCCESS)
2382 if (len <= *lpBufferSize)
2384 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2385 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
2386 ret = WN_SUCCESS;
2388 else
2390 *lpBufferSize = len;
2391 ret = WN_MORE_DATA;
2394 HeapFree(GetProcessHeap(), 0, wideRemote);
2396 else
2397 ret = WN_OUT_OF_MEMORY;
2399 HeapFree(GetProcessHeap(), 0, wideLocalName);
2401 else
2402 ret = WN_OUT_OF_MEMORY;
2404 else
2405 ret = WN_BAD_LOCALNAME;
2407 if (ret)
2408 SetLastError(ret);
2409 TRACE("Returning %ld\n", ret);
2410 return ret;
2413 /* find the network connection for a given drive; helper for WNetGetConnection */
2414 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
2416 char buffer[1024];
2417 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
2418 HANDLE mgr;
2419 DWORD ret = WN_NOT_CONNECTED;
2420 DWORD bytes_returned;
2422 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
2423 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
2424 0, 0 )) == INVALID_HANDLE_VALUE)
2426 ERR( "failed to open mount manager err %lu\n", GetLastError() );
2427 return ret;
2429 memset( data, 0, sizeof(*data) );
2430 data->letter = letter;
2431 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
2432 data, sizeof(buffer), &bytes_returned, NULL ))
2434 char *p, *mount_point = buffer + data->mount_point_offset;
2435 DWORD len;
2437 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
2439 mount_point += 2;
2440 mount_point[0] = '\\';
2441 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
2443 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
2444 if (len > *size)
2446 *size = len;
2447 ret = WN_MORE_DATA;
2449 else
2451 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
2452 ret = WN_SUCCESS;
2456 CloseHandle( mgr );
2457 return ret;
2460 /**************************************************************************
2461 * WNetGetConnectionW [MPR.@]
2463 * FIXME: need to test return values under different errors
2465 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
2466 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
2468 DWORD ret;
2470 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
2471 lpBufferSize);
2473 if (!lpLocalName)
2474 ret = WN_BAD_POINTER;
2475 else if (!lpBufferSize)
2476 ret = WN_BAD_POINTER;
2477 else if (!lpRemoteName && *lpBufferSize)
2478 ret = WN_BAD_POINTER;
2479 else if (!lpLocalName[0])
2480 ret = WN_BAD_LOCALNAME;
2481 else
2483 if (lpLocalName[1] == ':')
2485 switch(GetDriveTypeW(lpLocalName))
2487 case DRIVE_REMOTE:
2488 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
2489 break;
2490 case DRIVE_REMOVABLE:
2491 case DRIVE_FIXED:
2492 case DRIVE_CDROM:
2493 TRACE("file is local\n");
2494 ret = WN_NOT_CONNECTED;
2495 break;
2496 default:
2497 ret = WN_BAD_LOCALNAME;
2500 else
2501 ret = WN_BAD_LOCALNAME;
2503 if (ret)
2504 SetLastError(ret);
2505 TRACE("Returning %ld\n", ret);
2506 return ret;
2509 /**************************************************************************
2510 * WNetSetConnectionA [MPR.@]
2512 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
2513 LPVOID pvValue )
2515 FIXME( "(%s, %08lX, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
2517 SetLastError(WN_NO_NETWORK);
2518 return WN_NO_NETWORK;
2521 /**************************************************************************
2522 * WNetSetConnectionW [MPR.@]
2524 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2525 LPVOID pvValue )
2527 FIXME( "(%s, %08lX, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2529 SetLastError(WN_NO_NETWORK);
2530 return WN_NO_NETWORK;
2533 /*****************************************************************
2534 * WNetGetUniversalNameA [MPR.@]
2536 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2537 LPVOID lpBuffer, LPDWORD lpBufferSize )
2539 DWORD err, size;
2541 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
2542 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2544 switch (dwInfoLevel)
2546 case UNIVERSAL_NAME_INFO_LEVEL:
2548 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2550 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2552 err = ERROR_NOT_CONNECTED;
2553 break;
2556 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2557 if (*lpBufferSize < size)
2559 err = WN_MORE_DATA;
2560 break;
2562 info->lpUniversalName = (char *)info + sizeof(*info);
2563 lstrcpyA(info->lpUniversalName, lpLocalPath);
2564 err = WN_NO_ERROR;
2565 break;
2567 case REMOTE_NAME_INFO_LEVEL:
2568 err = WN_NOT_CONNECTED;
2569 break;
2571 default:
2572 err = WN_BAD_VALUE;
2573 break;
2576 SetLastError(err);
2577 return err;
2580 /*****************************************************************
2581 * WNetGetUniversalNameW [MPR.@]
2583 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2584 LPVOID lpBuffer, LPDWORD lpBufferSize )
2586 DWORD err, size;
2588 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
2589 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2591 switch (dwInfoLevel)
2593 case UNIVERSAL_NAME_INFO_LEVEL:
2595 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2597 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2599 err = ERROR_NOT_CONNECTED;
2600 break;
2603 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2604 if (*lpBufferSize < size)
2606 *lpBufferSize = size;
2607 err = WN_MORE_DATA;
2608 break;
2610 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2611 lstrcpyW(info->lpUniversalName, lpLocalPath);
2612 err = WN_NO_ERROR;
2613 break;
2615 case REMOTE_NAME_INFO_LEVEL:
2616 err = WN_NO_NETWORK;
2617 break;
2619 default:
2620 err = WN_BAD_VALUE;
2621 break;
2624 if (err != WN_NO_ERROR) SetLastError(err);
2625 return err;
2628 /*****************************************************************
2629 * WNetClearConnections [MPR.@]
2631 DWORD WINAPI WNetClearConnections ( HWND owner )
2633 HANDLE connected;
2634 PWSTR connection;
2635 DWORD ret, size, count;
2636 NETRESOURCEW * resources, * iter;
2638 ret = WNetOpenEnumW(RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL, &connected);
2639 if (ret != WN_SUCCESS)
2641 if (ret != WN_NO_NETWORK)
2643 return ret;
2646 /* Means no provider, then, clearing is OK */
2647 return WN_SUCCESS;
2650 size = 0x1000;
2651 resources = HeapAlloc(GetProcessHeap(), 0, size);
2652 if (!resources)
2654 WNetCloseEnum(connected);
2655 return WN_OUT_OF_MEMORY;
2658 for (;;)
2660 size = 0x1000;
2661 count = -1;
2663 memset(resources, 0, size);
2664 ret = WNetEnumResourceW(connected, &count, resources, &size);
2665 if (ret == WN_SUCCESS || ret == WN_MORE_DATA)
2667 for (iter = resources; count; count--, iter++)
2669 if (iter->lpLocalName && iter->lpLocalName[0])
2670 connection = iter->lpLocalName;
2671 else
2672 connection = iter->lpRemoteName;
2674 WNetCancelConnection2W(connection, 0, TRUE);
2677 else
2678 break;
2681 HeapFree(GetProcessHeap(), 0, resources);
2682 WNetCloseEnum(connected);
2684 return ret;
2689 * Other Functions
2692 /**************************************************************************
2693 * WNetGetUserA [MPR.@]
2695 * FIXME: we should not return ourselves, but the owner of the drive lpName
2697 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2699 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2700 return GetLastError();
2703 /*****************************************************************
2704 * WNetGetUserW [MPR.@]
2706 * FIXME: we should not return ourselves, but the owner of the drive lpName
2708 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2710 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2711 return GetLastError();
2714 /*********************************************************************
2715 * WNetConnectionDialog [MPR.@]
2717 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2719 CONNECTDLGSTRUCTW conn_dlg;
2720 NETRESOURCEW net_res;
2722 ZeroMemory(&conn_dlg, sizeof(conn_dlg));
2723 ZeroMemory(&net_res, sizeof(net_res));
2725 conn_dlg.cbStructure = sizeof(conn_dlg);
2726 conn_dlg.lpConnRes = &net_res;
2727 conn_dlg.hwndOwner = hwnd;
2728 net_res.dwType = dwType;
2730 return WNetConnectionDialog1W(&conn_dlg);
2733 /*********************************************************************
2734 * WNetConnectionDialog1A [MPR.@]
2736 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2738 FIXME( "(%p): stub\n", lpConnDlgStruct );
2740 SetLastError(WN_NO_NETWORK);
2741 return WN_NO_NETWORK;
2744 /*********************************************************************
2745 * WNetConnectionDialog1W [MPR.@]
2747 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2749 FIXME( "(%p): stub\n", lpConnDlgStruct );
2751 SetLastError(WN_NO_NETWORK);
2752 return WN_NO_NETWORK;
2755 /*********************************************************************
2756 * WNetDisconnectDialog [MPR.@]
2758 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2760 FIXME( "(%p, %08lX): stub\n", hwnd, dwType );
2762 SetLastError(WN_NO_NETWORK);
2763 return WN_NO_NETWORK;
2766 /*********************************************************************
2767 * WNetDisconnectDialog1A [MPR.@]
2769 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2771 FIXME( "(%p): stub\n", lpConnDlgStruct );
2773 SetLastError(WN_NO_NETWORK);
2774 return WN_NO_NETWORK;
2777 /*********************************************************************
2778 * WNetDisconnectDialog1W [MPR.@]
2780 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2782 FIXME( "(%p): stub\n", lpConnDlgStruct );
2784 SetLastError(WN_NO_NETWORK);
2785 return WN_NO_NETWORK;
2788 /*********************************************************************
2789 * WNetGetLastErrorA [MPR.@]
2791 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2792 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2793 LPSTR lpNameBuf, DWORD nNameBufSize )
2795 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
2796 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2798 SetLastError(WN_NO_NETWORK);
2799 return WN_NO_NETWORK;
2802 /*********************************************************************
2803 * WNetGetLastErrorW [MPR.@]
2805 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2806 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2807 LPWSTR lpNameBuf, DWORD nNameBufSize )
2809 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
2810 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2812 SetLastError(WN_NO_NETWORK);
2813 return WN_NO_NETWORK;
2816 /*********************************************************************
2817 * WNetGetNetworkInformationA [MPR.@]
2819 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2820 LPNETINFOSTRUCT lpNetInfoStruct )
2822 DWORD ret;
2824 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2826 if (!lpProvider)
2827 ret = WN_BAD_POINTER;
2828 else
2830 int len;
2832 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2833 if (len)
2835 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2837 if (wideProvider)
2839 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2840 len);
2841 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2842 HeapFree(GetProcessHeap(), 0, wideProvider);
2844 else
2845 ret = WN_OUT_OF_MEMORY;
2847 else
2848 ret = GetLastError();
2850 if (ret)
2851 SetLastError(ret);
2852 TRACE("Returning %ld\n", ret);
2853 return ret;
2856 /*********************************************************************
2857 * WNetGetNetworkInformationW [MPR.@]
2859 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2860 LPNETINFOSTRUCT lpNetInfoStruct )
2862 DWORD ret;
2864 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2866 if (!lpProvider)
2867 ret = WN_BAD_POINTER;
2868 else if (!lpNetInfoStruct)
2869 ret = WN_BAD_POINTER;
2870 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2871 ret = WN_BAD_VALUE;
2872 else
2874 if (providerTable && providerTable->numProviders)
2876 DWORD providerIndex = _findProviderIndexW(lpProvider);
2878 if (providerIndex != BAD_PROVIDER_INDEX)
2880 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2881 lpNetInfoStruct->dwProviderVersion =
2882 providerTable->table[providerIndex].dwSpecVersion;
2883 lpNetInfoStruct->dwStatus = NO_ERROR;
2884 lpNetInfoStruct->dwCharacteristics = 0;
2885 lpNetInfoStruct->dwHandle = 0;
2886 lpNetInfoStruct->wNetType =
2887 HIWORD(providerTable->table[providerIndex].dwNetType);
2888 lpNetInfoStruct->dwPrinters = -1;
2889 lpNetInfoStruct->dwDrives = -1;
2890 ret = WN_SUCCESS;
2892 else
2893 ret = WN_BAD_PROVIDER;
2895 else
2896 ret = WN_NO_NETWORK;
2898 if (ret)
2899 SetLastError(ret);
2900 TRACE("Returning %ld\n", ret);
2901 return ret;
2904 /*****************************************************************
2905 * WNetGetProviderNameA [MPR.@]
2907 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2908 LPSTR lpProvider, LPDWORD lpBufferSize )
2910 DWORD ret;
2912 TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2913 lpBufferSize);
2915 if (!lpProvider)
2916 ret = WN_BAD_POINTER;
2917 else if (!lpBufferSize)
2918 ret = WN_BAD_POINTER;
2919 else
2921 if (providerTable)
2923 DWORD i;
2925 ret = WN_NO_NETWORK;
2926 for (i = 0; i < providerTable->numProviders &&
2927 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2928 i++)
2930 if (i < providerTable->numProviders)
2932 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2933 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2935 if (*lpBufferSize < sizeNeeded)
2937 *lpBufferSize = sizeNeeded;
2938 ret = WN_MORE_DATA;
2940 else
2942 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2943 -1, lpProvider, *lpBufferSize, NULL, NULL);
2944 ret = WN_SUCCESS;
2945 /* FIXME: is *lpBufferSize set to the number of characters
2946 * copied? */
2950 else
2951 ret = WN_NO_NETWORK;
2953 if (ret)
2954 SetLastError(ret);
2955 TRACE("Returning %ld\n", ret);
2956 return ret;
2959 /*****************************************************************
2960 * WNetGetProviderNameW [MPR.@]
2962 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2963 LPWSTR lpProvider, LPDWORD lpBufferSize )
2965 DWORD ret;
2967 TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2968 lpBufferSize);
2970 if (!lpProvider)
2971 ret = WN_BAD_POINTER;
2972 else if (!lpBufferSize)
2973 ret = WN_BAD_POINTER;
2974 else
2976 if (providerTable)
2978 DWORD i;
2980 ret = WN_NO_NETWORK;
2981 for (i = 0; i < providerTable->numProviders &&
2982 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2983 i++)
2985 if (i < providerTable->numProviders)
2987 DWORD sizeNeeded = lstrlenW(providerTable->table[i].name) + 1;
2989 if (*lpBufferSize < sizeNeeded)
2991 *lpBufferSize = sizeNeeded;
2992 ret = WN_MORE_DATA;
2994 else
2996 lstrcpyW(lpProvider, providerTable->table[i].name);
2997 ret = WN_SUCCESS;
2998 /* FIXME: is *lpBufferSize set to the number of characters
2999 * copied? */
3003 else
3004 ret = WN_NO_NETWORK;
3006 if (ret)
3007 SetLastError(ret);
3008 TRACE("Returning %ld\n", ret);
3009 return ret;