ntdll: Move the loading of .so dlls to the Unix library.
[wine.git] / dlls / mpr / wnet.c
blob1333082705bf6b75638f20b0e0c8ee94f7628528
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 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
130 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
131 'S','e','r','v','i','c','e','s','\\',0 };
132 static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
133 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
134 WCHAR serviceName[MAX_PATH];
135 HKEY hKey;
137 TRACE("%s\n", debugstr_w(provider));
138 swprintf(serviceName, ARRAY_SIZE(serviceName), serviceFmt, servicePrefix, provider);
139 serviceName[ARRAY_SIZE(serviceName) - 1] = '\0';
140 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
141 ERROR_SUCCESS)
143 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
144 'P','a','t','h',0 };
145 WCHAR providerPath[MAX_PATH];
146 DWORD type, size = sizeof(providerPath);
148 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
149 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && (type == REG_SZ || type == REG_EXPAND_SZ))
151 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
152 PWSTR name = NULL;
154 if (type == REG_EXPAND_SZ)
156 WCHAR path[MAX_PATH];
157 if (ExpandEnvironmentStringsW(providerPath, path, MAX_PATH)) lstrcpyW( providerPath, path );
160 size = 0;
161 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
162 if (size)
164 name = HeapAlloc(GetProcessHeap(), 0, size);
165 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
166 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
168 HeapFree(GetProcessHeap(), 0, name);
169 name = NULL;
172 if (name)
174 HMODULE hLib = LoadLibraryW(providerPath);
176 if (hLib)
178 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
180 PF_NPGetCaps getCaps = MPR_GETPROC(NPGetCaps);
182 TRACE("loaded lib %p\n", hLib);
183 if (getCaps)
185 DWORD connectCap;
186 PWNetProvider provider =
187 &providerTable->table[providerTable->numProviders];
189 provider->hLib = hLib;
190 provider->name = name;
191 TRACE("name is %s\n", debugstr_w(name));
192 provider->getCaps = getCaps;
193 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
194 provider->dwNetType = getCaps(WNNC_NET_TYPE);
195 TRACE("net type is 0x%08x\n", provider->dwNetType);
196 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
197 if (provider->dwEnumScopes)
199 TRACE("supports enumeration\n");
200 provider->openEnum = MPR_GETPROC(NPOpenEnum);
201 TRACE("NPOpenEnum %p\n", provider->openEnum);
202 provider->enumResource = MPR_GETPROC(NPEnumResource);
203 TRACE("NPEnumResource %p\n", provider->enumResource);
204 provider->closeEnum = MPR_GETPROC(NPCloseEnum);
205 TRACE("NPCloseEnum %p\n", provider->closeEnum);
206 provider->getResourceInformation = MPR_GETPROC(NPGetResourceInformation);
207 TRACE("NPGetResourceInformation %p\n", provider->getResourceInformation);
208 if (!provider->openEnum ||
209 !provider->enumResource ||
210 !provider->closeEnum)
212 provider->openEnum = NULL;
213 provider->enumResource = NULL;
214 provider->closeEnum = NULL;
215 provider->dwEnumScopes = 0;
216 WARN("Couldn't load enumeration functions\n");
219 connectCap = getCaps(WNNC_CONNECTION);
220 if (connectCap & WNNC_CON_ADDCONNECTION)
221 provider->addConnection = MPR_GETPROC(NPAddConnection);
222 if (connectCap & WNNC_CON_ADDCONNECTION3)
223 provider->addConnection3 = MPR_GETPROC(NPAddConnection3);
224 if (connectCap & WNNC_CON_CANCELCONNECTION)
225 provider->cancelConnection = MPR_GETPROC(NPCancelConnection);
226 TRACE("NPAddConnection %p\n", provider->addConnection);
227 TRACE("NPAddConnection3 %p\n", provider->addConnection3);
228 TRACE("NPCancelConnection %p\n", provider->cancelConnection);
229 providerTable->numProviders++;
231 else
233 WARN("Provider %s didn't export NPGetCaps\n",
234 debugstr_w(provider));
235 HeapFree(GetProcessHeap(), 0, name);
236 FreeLibrary(hLib);
239 #undef MPR_GETPROC
241 else
243 WARN("Couldn't load library %s for provider %s\n",
244 debugstr_w(providerPath), debugstr_w(provider));
245 HeapFree(GetProcessHeap(), 0, name);
248 else
250 WARN("Couldn't get provider name for provider %s\n",
251 debugstr_w(provider));
254 else
255 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
256 RegCloseKey(hKey);
258 else
259 WARN("Couldn't open service key for provider %s\n",
260 debugstr_w(provider));
263 void wnetInit(HINSTANCE hInstDll)
265 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
266 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
267 'C','o','n','t','r','o','l','\\',
268 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
269 'O','r','d','e','r',0 };
270 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
271 'O','r','d','e','r',0 };
272 HKEY hKey;
274 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
275 == ERROR_SUCCESS)
277 DWORD size = 0;
279 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
280 if (size)
282 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
284 if (providers)
286 DWORD type;
288 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
289 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
291 PWSTR ptr;
292 DWORD numToAllocate;
294 TRACE("provider order is %s\n", debugstr_w(providers));
295 /* first count commas as a heuristic for how many to
296 * allocate space for */
297 for (ptr = providers, numToAllocate = 1; ptr; )
299 ptr = wcschr(ptr, ',');
300 if (ptr) {
301 numToAllocate++;
302 ptr++;
305 providerTable =
306 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
307 sizeof(WNetProviderTable)
308 + (numToAllocate - 1) * sizeof(WNetProvider));
309 if (providerTable)
311 PWSTR ptrPrev;
312 int entireNetworkLen;
313 LPCWSTR stringresource;
315 entireNetworkLen = LoadStringW(hInstDll,
316 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
317 providerTable->entireNetwork = HeapAlloc(
318 GetProcessHeap(), 0, (entireNetworkLen + 1) *
319 sizeof(WCHAR));
320 if (providerTable->entireNetwork)
322 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
323 providerTable->entireNetwork[entireNetworkLen] = 0;
325 providerTable->numAllocated = numToAllocate;
326 for (ptr = providers; ptr; )
328 ptrPrev = ptr;
329 ptr = wcschr(ptr, ',');
330 if (ptr)
331 *ptr++ = '\0';
332 _tryLoadProvider(ptrPrev);
336 HeapFree(GetProcessHeap(), 0, providers);
339 RegCloseKey(hKey);
343 void wnetFree(void)
345 if (providerTable)
347 DWORD i;
349 for (i = 0; i < providerTable->numProviders; i++)
351 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
352 FreeModule(providerTable->table[i].hLib);
354 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
355 HeapFree(GetProcessHeap(), 0, providerTable);
356 providerTable = NULL;
360 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
362 DWORD ret = BAD_PROVIDER_INDEX;
364 if (providerTable && providerTable->numProviders)
366 DWORD i;
368 for (i = 0; i < providerTable->numProviders &&
369 ret == BAD_PROVIDER_INDEX; i++)
370 if (!lstrcmpW(lpProvider, providerTable->table[i].name))
371 ret = i;
373 return ret;
377 * Browsing Functions
380 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
382 LPNETRESOURCEW ret;
384 if (lpNet)
386 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
387 if (ret)
389 size_t len;
391 *ret = *lpNet;
392 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
393 if (lpNet->lpRemoteName)
395 len = lstrlenW(lpNet->lpRemoteName) + 1;
396 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
397 if (ret->lpRemoteName)
398 lstrcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
402 else
403 ret = NULL;
404 return ret;
407 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
409 if (lpNet)
411 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
412 HeapFree(GetProcessHeap(), 0, lpNet);
416 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
417 DWORD dwUsage, LPNETRESOURCEW lpNet)
419 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
420 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
422 if (ret)
424 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
425 ret->dwScope = dwScope;
426 ret->dwType = dwType;
427 ret->dwUsage = dwUsage;
428 ret->specific.net = _copyNetResourceForEnumW(lpNet);
430 return ret;
433 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
434 DWORD dwUsage, DWORD index, HANDLE handle)
436 PWNetEnumerator ret;
438 if (!providerTable || index >= providerTable->numProviders)
439 ret = NULL;
440 else
442 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
443 if (ret)
445 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
446 ret->providerIndex = index;
447 ret->dwScope = dwScope;
448 ret->dwType = dwType;
449 ret->dwUsage = dwUsage;
450 ret->handle = handle;
453 return ret;
456 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
457 DWORD dwUsage)
459 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
460 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
462 if (ret)
464 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
465 ret->dwScope = dwScope;
466 ret->dwType = dwType;
467 ret->dwUsage = dwUsage;
469 return ret;
472 static PWNetEnumerator _createConnectedEnumerator(DWORD dwScope, DWORD dwType,
473 DWORD dwUsage)
475 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
476 if (ret)
478 ret->enumType = WNET_ENUMERATOR_TYPE_CONNECTED;
479 ret->dwScope = dwScope;
480 ret->dwType = dwType;
481 ret->dwUsage = dwUsage;
482 ret->specific.handles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HANDLE) * providerTable->numProviders);
483 if (!ret->specific.handles)
485 HeapFree(GetProcessHeap(), 0, ret);
486 ret = NULL;
489 return ret;
492 static PWNetEnumerator _createRememberedEnumerator(DWORD dwScope, DWORD dwType,
493 HKEY remembered)
495 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
496 if (ret)
498 ret->enumType = WNET_ENUMERATOR_TYPE_REMEMBERED;
499 ret->dwScope = dwScope;
500 ret->dwType = dwType;
501 ret->specific.remembered.registry = remembered;
503 return ret;
506 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
507 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
508 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
509 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
510 * if not all members of the array could be thunked, and something else on
511 * failure.
513 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
514 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
516 DWORD i, numToThunk, totalBytes, ret;
517 LPSTR strNext;
519 if (!lpNetArrayIn)
520 return WN_BAD_POINTER;
521 if (!lpcCount)
522 return WN_BAD_POINTER;
523 if (*lpcCount == -1)
524 return WN_BAD_VALUE;
525 if (!lpBuffer)
526 return WN_BAD_POINTER;
527 if (!lpBufferSize)
528 return WN_BAD_POINTER;
530 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
532 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
534 totalBytes += sizeof(NETRESOURCEA);
535 if (lpNet->lpLocalName)
536 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
537 -1, NULL, 0, NULL, NULL);
538 if (lpNet->lpRemoteName)
539 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
540 -1, NULL, 0, NULL, NULL);
541 if (lpNet->lpComment)
542 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
543 -1, NULL, 0, NULL, NULL);
544 if (lpNet->lpProvider)
545 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
546 -1, NULL, 0, NULL, NULL);
547 if (totalBytes < *lpBufferSize)
548 numToThunk = i + 1;
550 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
551 for (i = 0; i < numToThunk; i++)
553 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
554 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
556 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
557 /* lie about string lengths, we already verified how many
558 * we have space for above
560 if (lpNetIn->lpLocalName)
562 lpNetOut->lpLocalName = strNext;
563 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
564 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
566 if (lpNetIn->lpRemoteName)
568 lpNetOut->lpRemoteName = strNext;
569 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
570 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
572 if (lpNetIn->lpComment)
574 lpNetOut->lpComment = strNext;
575 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
576 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
578 if (lpNetIn->lpProvider)
580 lpNetOut->lpProvider = strNext;
581 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
582 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
585 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
586 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
587 *lpcCount, ret);
588 return ret;
591 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
592 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
593 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
594 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
595 * if not all members of the array could be thunked, and something else on
596 * failure.
598 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
599 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
601 DWORD i, numToThunk, totalBytes, ret;
602 LPWSTR strNext;
604 if (!lpNetArrayIn)
605 return WN_BAD_POINTER;
606 if (!lpcCount)
607 return WN_BAD_POINTER;
608 if (*lpcCount == -1)
609 return WN_BAD_VALUE;
610 if (!lpBuffer)
611 return WN_BAD_POINTER;
612 if (!lpBufferSize)
613 return WN_BAD_POINTER;
615 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
617 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
619 totalBytes += sizeof(NETRESOURCEW);
620 if (lpNet->lpLocalName)
621 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
622 -1, NULL, 0) * sizeof(WCHAR);
623 if (lpNet->lpRemoteName)
624 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
625 -1, NULL, 0) * sizeof(WCHAR);
626 if (lpNet->lpComment)
627 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
628 -1, NULL, 0) * sizeof(WCHAR);
629 if (lpNet->lpProvider)
630 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
631 -1, NULL, 0) * sizeof(WCHAR);
632 if (totalBytes < *lpBufferSize)
633 numToThunk = i + 1;
635 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
636 for (i = 0; i < numToThunk; i++)
638 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
639 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
641 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
642 /* lie about string lengths, we already verified how many
643 * we have space for above
645 if (lpNetIn->lpLocalName)
647 lpNetOut->lpLocalName = strNext;
648 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
649 -1, lpNetOut->lpLocalName, *lpBufferSize);
651 if (lpNetIn->lpRemoteName)
653 lpNetOut->lpRemoteName = strNext;
654 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
655 -1, lpNetOut->lpRemoteName, *lpBufferSize);
657 if (lpNetIn->lpComment)
659 lpNetOut->lpComment = strNext;
660 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
661 -1, lpNetOut->lpComment, *lpBufferSize);
663 if (lpNetIn->lpProvider)
665 lpNetOut->lpProvider = strNext;
666 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
667 -1, lpNetOut->lpProvider, *lpBufferSize);
670 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
671 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
672 *lpcCount, ret);
673 return ret;
676 /*********************************************************************
677 * WNetOpenEnumA [MPR.@]
679 * See comments for WNetOpenEnumW.
681 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
682 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
684 DWORD ret;
686 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
687 dwScope, dwType, dwUsage, lpNet, lphEnum );
689 if (!lphEnum)
690 ret = WN_BAD_POINTER;
691 else if (!providerTable || providerTable->numProviders == 0)
693 *lphEnum = NULL;
694 ret = WN_NO_NETWORK;
696 else
698 if (lpNet)
700 LPNETRESOURCEW lpNetWide = NULL;
701 BYTE buf[1024];
702 DWORD size = sizeof(buf), count = 1;
703 BOOL allocated = FALSE;
705 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
706 if (ret == WN_MORE_DATA)
708 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
709 size);
710 if (lpNetWide)
712 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
713 &size);
714 allocated = TRUE;
716 else
717 ret = WN_OUT_OF_MEMORY;
719 else if (ret == WN_SUCCESS)
720 lpNetWide = (LPNETRESOURCEW)buf;
721 if (ret == WN_SUCCESS)
722 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
723 lphEnum);
724 if (allocated)
725 HeapFree(GetProcessHeap(), 0, lpNetWide);
727 else
728 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
730 if (ret)
731 SetLastError(ret);
732 TRACE("Returning %d\n", ret);
733 return ret;
736 /*********************************************************************
737 * WNetOpenEnumW [MPR.@]
739 * Network enumeration has way too many parameters, so I'm not positive I got
740 * them right. What I've got so far:
742 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
743 * all the network providers should be enumerated.
745 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
746 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
747 * lpProvider is set, all the network providers should be enumerated.
748 * (This means the enumeration is a list of network providers, not that the
749 * enumeration is passed on to the providers.)
751 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
752 * resource matches the "Entire Network" resource (no remote name, no
753 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
754 * enumeration is done on every network provider.
756 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
757 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
758 * only to the given network provider.
760 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
761 * no lpProvider is set, enumeration will be tried on every network provider,
762 * in the order in which they're loaded.
764 * - The LPNETRESOURCE should be disregarded for scopes besides
765 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
766 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
768 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
769 * resource in the enumerated list, as well as any machines in your
770 * workgroup. The machines in your workgroup come from doing a
771 * RESOURCE_CONTEXT enumeration of every Network Provider.
773 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
774 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
776 DWORD ret;
778 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
779 dwScope, dwType, dwUsage, lpNet, lphEnum );
781 if (!lphEnum)
782 ret = WN_BAD_POINTER;
783 else if (!providerTable || providerTable->numProviders == 0)
785 *lphEnum = NULL;
786 ret = WN_NO_NETWORK;
788 else
790 switch (dwScope)
792 case RESOURCE_GLOBALNET:
793 if (lpNet)
795 if (lpNet->lpProvider)
797 DWORD index = _findProviderIndexW(lpNet->lpProvider);
799 if (index != BAD_PROVIDER_INDEX)
801 if (providerTable->table[index].openEnum &&
802 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
804 HANDLE handle;
805 PWSTR RemoteName = lpNet->lpRemoteName;
807 if ((lpNet->dwUsage & RESOURCEUSAGE_CONTAINER) &&
808 RemoteName && !lstrcmpW(RemoteName, lpNet->lpProvider))
809 lpNet->lpRemoteName = NULL;
811 ret = providerTable->table[index].openEnum(
812 dwScope, dwType, dwUsage, lpNet, &handle);
813 if (ret == WN_SUCCESS)
815 *lphEnum = _createProviderEnumerator(
816 dwScope, dwType, dwUsage, index, handle);
817 ret = *lphEnum ? WN_SUCCESS :
818 WN_OUT_OF_MEMORY;
821 lpNet->lpRemoteName = RemoteName;
823 else
824 ret = WN_NOT_SUPPORTED;
826 else
827 ret = WN_BAD_PROVIDER;
829 else if (lpNet->lpRemoteName)
831 *lphEnum = _createGlobalEnumeratorW(dwScope,
832 dwType, dwUsage, lpNet);
833 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
835 else
837 if (lpNet->lpComment && !lstrcmpW(lpNet->lpComment,
838 providerTable->entireNetwork))
840 /* comment matches the "Entire Network", enumerate
841 * global scope of every provider
843 *lphEnum = _createGlobalEnumeratorW(dwScope,
844 dwType, dwUsage, lpNet);
846 else
848 /* this is the same as not having passed lpNet */
849 *lphEnum = _createGlobalEnumeratorW(dwScope,
850 dwType, dwUsage, NULL);
852 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
855 else
857 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
858 dwUsage, lpNet);
859 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
861 break;
862 case RESOURCE_CONTEXT:
863 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
864 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
865 break;
866 case RESOURCE_CONNECTED:
867 *lphEnum = _createConnectedEnumerator(dwScope, dwType, dwUsage);
868 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
869 break;
870 case RESOURCE_REMEMBERED:
872 HKEY remembered, user_profile;
874 ret = WN_OUT_OF_MEMORY;
875 if (RegOpenCurrentUser(KEY_READ, &user_profile) == ERROR_SUCCESS)
877 WCHAR subkey[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
879 if (RegOpenKeyExW(user_profile, subkey, 0, KEY_READ, &remembered) == ERROR_SUCCESS)
881 *lphEnum = _createRememberedEnumerator(dwScope, dwType, remembered);
882 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
885 RegCloseKey(user_profile);
888 break;
889 default:
890 WARN("unknown scope 0x%08x\n", dwScope);
891 ret = WN_BAD_VALUE;
894 if (ret)
895 SetLastError(ret);
896 TRACE("Returning %d\n", ret);
897 return ret;
900 /*********************************************************************
901 * WNetEnumResourceA [MPR.@]
903 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
904 LPVOID lpBuffer, LPDWORD lpBufferSize )
906 DWORD ret;
908 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
910 if (!hEnum)
911 ret = WN_BAD_POINTER;
912 else if (!lpcCount)
913 ret = WN_BAD_POINTER;
914 else if (!lpBuffer)
915 ret = WN_BAD_POINTER;
916 else if (!lpBufferSize)
917 ret = WN_BAD_POINTER;
918 else if (*lpBufferSize < sizeof(NETRESOURCEA))
920 *lpBufferSize = sizeof(NETRESOURCEA);
921 ret = WN_MORE_DATA;
923 else
925 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
926 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
928 if (localBuffer)
930 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
931 &localSize);
932 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
934 /* FIXME: this isn't necessarily going to work in the case of
935 * WN_MORE_DATA, because our enumerator may have moved on to
936 * the next provider. MSDN states that a large (16KB) buffer
937 * size is the appropriate usage of this function, so
938 * hopefully it won't be an issue.
940 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
941 lpBuffer, lpBufferSize);
942 *lpcCount = localCount;
944 HeapFree(GetProcessHeap(), 0, localBuffer);
946 else
947 ret = WN_OUT_OF_MEMORY;
949 if (ret)
950 SetLastError(ret);
951 TRACE("Returning %d\n", ret);
952 return ret;
955 static DWORD _countProviderBytesW(PWNetProvider provider)
957 DWORD ret;
959 if (provider)
961 ret = sizeof(NETRESOURCEW);
962 ret += 2 * (lstrlenW(provider->name) + 1) * sizeof(WCHAR);
964 else
965 ret = 0;
966 return ret;
969 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
970 LPVOID lpBuffer, const DWORD *lpBufferSize)
972 DWORD ret;
974 if (!enumerator)
975 return WN_BAD_POINTER;
976 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
977 return WN_BAD_VALUE;
978 if (!lpcCount)
979 return WN_BAD_POINTER;
980 if (!lpBuffer)
981 return WN_BAD_POINTER;
982 if (!lpBufferSize)
983 return WN_BAD_POINTER;
984 if (*lpBufferSize < sizeof(NETRESOURCEA))
985 return WN_MORE_DATA;
987 if (!providerTable || enumerator->providerIndex >=
988 providerTable->numProviders)
989 ret = WN_NO_MORE_ENTRIES;
990 else
992 DWORD bytes = 0, count = 0, countLimit, i;
993 LPNETRESOURCEW resource;
994 LPWSTR strNext;
996 countLimit = *lpcCount == -1 ?
997 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
998 while (count < countLimit && bytes < *lpBufferSize)
1000 DWORD bytesNext = _countProviderBytesW(
1001 &providerTable->table[count + enumerator->providerIndex]);
1003 if (bytes + bytesNext < *lpBufferSize)
1005 bytes += bytesNext;
1006 count++;
1009 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
1010 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
1012 resource->dwScope = RESOURCE_GLOBALNET;
1013 resource->dwType = RESOURCETYPE_ANY;
1014 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
1015 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
1016 RESOURCEUSAGE_RESERVED;
1017 resource->lpLocalName = NULL;
1018 resource->lpRemoteName = strNext;
1019 lstrcpyW(resource->lpRemoteName,
1020 providerTable->table[i + enumerator->providerIndex].name);
1021 strNext += lstrlenW(resource->lpRemoteName) + 1;
1022 resource->lpComment = NULL;
1023 resource->lpProvider = strNext;
1024 lstrcpyW(resource->lpProvider,
1025 providerTable->table[i + enumerator->providerIndex].name);
1026 strNext += lstrlenW(resource->lpProvider) + 1;
1028 enumerator->providerIndex += count;
1029 *lpcCount = count;
1030 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
1032 TRACE("Returning %d\n", ret);
1033 return ret;
1036 /* Advances the enumerator (assumed to be a global enumerator) to the next
1037 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1038 * not open a handle with the next provider.
1039 * If the existing handle is NULL, may leave the enumerator unchanged, since
1040 * the current provider may support the desired scope.
1041 * If the existing handle is not NULL, closes it before moving on.
1042 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1043 * provider, and another error on failure.
1045 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
1047 if (!enumerator)
1048 return WN_BAD_POINTER;
1049 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1050 return WN_BAD_VALUE;
1051 if (!providerTable || enumerator->providerIndex >=
1052 providerTable->numProviders)
1053 return WN_NO_MORE_ENTRIES;
1055 if (enumerator->providerDone)
1057 DWORD dwEnum = 0;
1058 enumerator->providerDone = FALSE;
1059 if (enumerator->handle)
1061 providerTable->table[enumerator->providerIndex].closeEnum(
1062 enumerator->handle);
1063 enumerator->handle = NULL;
1064 enumerator->providerIndex++;
1066 if (enumerator->dwScope == RESOURCE_CONNECTED)
1067 dwEnum = WNNC_ENUM_LOCAL;
1068 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
1069 dwEnum = WNNC_ENUM_GLOBAL;
1070 else if (enumerator->dwScope == RESOURCE_CONTEXT)
1071 dwEnum = WNNC_ENUM_CONTEXT;
1072 for (; enumerator->providerIndex < providerTable->numProviders &&
1073 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
1074 & dwEnum); enumerator->providerIndex++)
1077 return enumerator->providerIndex < providerTable->numProviders ?
1078 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1081 /* "Passes through" call to the next provider that supports the enumeration
1082 * type.
1083 * FIXME: if one call to a provider's enumerator succeeds while there's still
1084 * space in lpBuffer, I don't call to the next provider. The caller may not
1085 * expect that it should call EnumResourceW again with a return value of
1086 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1087 * may have to be moved around a bit, ick.
1089 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1090 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1092 DWORD ret;
1094 if (!enumerator)
1095 return WN_BAD_POINTER;
1096 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1097 return WN_BAD_VALUE;
1098 if (!lpcCount)
1099 return WN_BAD_POINTER;
1100 if (!lpBuffer)
1101 return WN_BAD_POINTER;
1102 if (!lpBufferSize)
1103 return WN_BAD_POINTER;
1104 if (*lpBufferSize < sizeof(NETRESOURCEW))
1105 return WN_MORE_DATA;
1107 ret = _globalEnumeratorAdvance(enumerator);
1108 if (ret == WN_SUCCESS)
1110 ret = providerTable->table[enumerator->providerIndex].
1111 openEnum(enumerator->dwScope, enumerator->dwType,
1112 enumerator->dwUsage, enumerator->specific.net,
1113 &enumerator->handle);
1114 if (ret == WN_SUCCESS)
1116 ret = providerTable->table[enumerator->providerIndex].
1117 enumResource(enumerator->handle, lpcCount, lpBuffer,
1118 lpBufferSize);
1119 if (ret != WN_MORE_DATA)
1120 enumerator->providerDone = TRUE;
1123 TRACE("Returning %d\n", ret);
1124 return ret;
1127 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1128 LPVOID lpBuffer, LPDWORD lpBufferSize)
1130 DWORD ret;
1132 if (!enumerator)
1133 return WN_BAD_POINTER;
1134 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1135 return WN_BAD_VALUE;
1136 if (!lpcCount)
1137 return WN_BAD_POINTER;
1138 if (!lpBuffer)
1139 return WN_BAD_POINTER;
1140 if (!lpBufferSize)
1141 return WN_BAD_POINTER;
1142 if (*lpBufferSize < sizeof(NETRESOURCEW))
1143 return WN_MORE_DATA;
1144 if (!providerTable)
1145 return WN_NO_NETWORK;
1147 switch (enumerator->dwScope)
1149 case RESOURCE_GLOBALNET:
1150 if (enumerator->specific.net)
1151 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1152 lpBuffer, lpBufferSize);
1153 else
1154 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1155 lpBufferSize);
1156 break;
1157 case RESOURCE_CONTEXT:
1158 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1159 lpBufferSize);
1160 break;
1161 default:
1162 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1163 ret = WN_NO_MORE_ENTRIES;
1165 TRACE("Returning %d\n", ret);
1166 return ret;
1169 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1170 LPVOID lpBuffer, LPDWORD lpBufferSize)
1172 if (!enumerator)
1173 return WN_BAD_POINTER;
1174 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1175 return WN_BAD_VALUE;
1176 if (!enumerator->handle)
1177 return WN_BAD_VALUE;
1178 if (!lpcCount)
1179 return WN_BAD_POINTER;
1180 if (!lpBuffer)
1181 return WN_BAD_POINTER;
1182 if (!lpBufferSize)
1183 return WN_BAD_POINTER;
1184 if (!providerTable)
1185 return WN_NO_NETWORK;
1186 if (enumerator->providerIndex >= providerTable->numProviders)
1187 return WN_NO_MORE_ENTRIES;
1188 if (!providerTable->table[enumerator->providerIndex].enumResource)
1189 return WN_BAD_VALUE;
1190 return providerTable->table[enumerator->providerIndex].enumResource(
1191 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1194 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1195 LPVOID lpBuffer, LPDWORD lpBufferSize)
1197 DWORD ret;
1198 size_t cchEntireNetworkLen, bytesNeeded;
1200 if (!enumerator)
1201 return WN_BAD_POINTER;
1202 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1203 return WN_BAD_VALUE;
1204 if (!lpcCount)
1205 return WN_BAD_POINTER;
1206 if (!lpBuffer)
1207 return WN_BAD_POINTER;
1208 if (!lpBufferSize)
1209 return WN_BAD_POINTER;
1210 if (!providerTable)
1211 return WN_NO_NETWORK;
1213 cchEntireNetworkLen = lstrlenW(providerTable->entireNetwork) + 1;
1214 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1215 if (*lpBufferSize < bytesNeeded)
1217 *lpBufferSize = bytesNeeded;
1218 ret = WN_MORE_DATA;
1220 else
1222 LPNETRESOURCEW lpNet = lpBuffer;
1224 lpNet->dwScope = RESOURCE_GLOBALNET;
1225 lpNet->dwType = enumerator->dwType;
1226 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1227 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1228 lpNet->lpLocalName = NULL;
1229 lpNet->lpRemoteName = NULL;
1230 lpNet->lpProvider = NULL;
1231 /* odd, but correct: put comment at end of buffer, so it won't get
1232 * overwritten by subsequent calls to a provider's enumResource
1234 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1235 (cchEntireNetworkLen * sizeof(WCHAR)));
1236 lstrcpyW(lpNet->lpComment, providerTable->entireNetwork);
1237 ret = WN_SUCCESS;
1239 if (ret == WN_SUCCESS)
1241 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1243 /* "Entire Network" entry enumerated--morph this into a global
1244 * enumerator. enumerator->lpNet continues to be NULL, since it has
1245 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1247 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1248 ret = _enumerateGlobalW(enumerator, lpcCount,
1249 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1250 if (ret == WN_SUCCESS)
1252 /* reflect the fact that we already enumerated "Entire Network" */
1253 (*lpcCount)++;
1254 *lpBufferSize = bufferSize + bytesNeeded;
1256 else
1258 /* the provider enumeration failed, but we already succeeded in
1259 * enumerating "Entire Network"--leave type as global to allow a
1260 * retry, but indicate success with a count of one.
1262 ret = WN_SUCCESS;
1263 *lpcCount = 1;
1264 *lpBufferSize = bytesNeeded;
1267 TRACE("Returning %d\n", ret);
1268 return ret;
1271 static DWORD _copyStringToEnumW(const WCHAR *source, DWORD* left, void** end)
1273 DWORD len;
1274 WCHAR* local = *end;
1276 len = lstrlenW(source) + 1;
1277 len *= sizeof(WCHAR);
1278 if (*left < len)
1279 return WN_MORE_DATA;
1281 local -= (len / sizeof(WCHAR));
1282 memcpy(local, source, len);
1283 *left -= len;
1284 *end = local;
1286 return WN_SUCCESS;
1289 static DWORD _enumerateConnectedW(PWNetEnumerator enumerator, DWORD* user_count,
1290 void* user_buffer, DWORD* user_size)
1292 DWORD ret, index, count, total_count, size, i, left;
1293 void* end;
1294 NETRESOURCEW* curr, * buffer;
1295 HANDLE* handles;
1297 if (!enumerator)
1298 return WN_BAD_POINTER;
1299 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONNECTED)
1300 return WN_BAD_VALUE;
1301 if (!user_count || !user_buffer || !user_size)
1302 return WN_BAD_POINTER;
1303 if (!providerTable)
1304 return WN_NO_NETWORK;
1306 handles = enumerator->specific.handles;
1307 left = *user_size;
1308 size = *user_size;
1309 buffer = HeapAlloc(GetProcessHeap(), 0, *user_size);
1310 if (!buffer)
1311 return WN_NO_NETWORK;
1313 curr = user_buffer;
1314 end = (char *)user_buffer + size;
1315 count = *user_count;
1316 total_count = 0;
1318 ret = WN_NO_MORE_ENTRIES;
1319 for (index = 0; index < providerTable->numProviders; index++)
1321 if (providerTable->table[index].dwEnumScopes)
1323 if (handles[index] == 0)
1325 ret = providerTable->table[index].openEnum(enumerator->dwScope,
1326 enumerator->dwType,
1327 enumerator->dwUsage,
1328 NULL, &handles[index]);
1329 if (ret != WN_SUCCESS)
1330 continue;
1333 ret = providerTable->table[index].enumResource(handles[index],
1334 &count, buffer,
1335 &size);
1336 total_count += count;
1337 if (ret == WN_MORE_DATA)
1338 break;
1340 if (ret == WN_SUCCESS)
1342 for (i = 0; i < count; ++i)
1344 if (left < sizeof(NETRESOURCEW))
1346 ret = WN_MORE_DATA;
1347 break;
1350 memcpy(curr, &buffer[i], sizeof(NETRESOURCEW));
1351 left -= sizeof(NETRESOURCEW);
1353 ret = _copyStringToEnumW(buffer[i].lpLocalName, &left, &end);
1354 if (ret == WN_MORE_DATA)
1355 break;
1356 curr->lpLocalName = end;
1358 ret = _copyStringToEnumW(buffer[i].lpRemoteName, &left, &end);
1359 if (ret == WN_MORE_DATA)
1360 break;
1361 curr->lpRemoteName = end;
1363 ret = _copyStringToEnumW(buffer[i].lpProvider, &left, &end);
1364 if (ret == WN_MORE_DATA)
1365 break;
1366 curr->lpProvider = end;
1368 ++curr;
1371 size = left;
1374 if (*user_count != -1)
1375 count = *user_count - total_count;
1376 else
1377 count = *user_count;
1381 if (total_count == 0)
1382 ret = WN_NO_MORE_ENTRIES;
1384 *user_count = total_count;
1385 if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
1386 ret = WN_SUCCESS;
1388 HeapFree(GetProcessHeap(), 0, buffer);
1390 TRACE("Returning %d\n", ret);
1391 return ret;
1394 static const WCHAR connectionType[] = { 'C','o','n','n','e','c','t','i','o','n','T','y','p','e',0 };
1395 static const WCHAR providerName[] = { 'P','r','o','v','i','d','e','r','N','a','m','e',0 };
1396 static const WCHAR remotePath[] = { 'R','e','m','o','t','e','P','a','t','h',0 };
1398 static WCHAR *get_reg_str(HKEY hkey, const WCHAR *value, DWORD *len)
1400 DWORD type;
1401 WCHAR *ret = NULL;
1403 if (!RegQueryValueExW(hkey, value, NULL, &type, NULL, len) && type == REG_SZ)
1405 if (!(ret = HeapAlloc(GetProcessHeap(), 0, *len))) return NULL;
1406 RegQueryValueExW(hkey, value, 0, 0, (BYTE *)ret, len);
1409 return ret;
1412 static DWORD _enumeratorRememberedW(PWNetEnumerator enumerator, DWORD* user_count,
1413 void* user_buffer, DWORD* user_size)
1415 HKEY registry, connection;
1416 WCHAR buffer[255];
1417 LONG size_left;
1418 DWORD index, ret, type, len, size, registry_size, full_size = 0, total_count;
1419 NETRESOURCEW * net_buffer = user_buffer;
1420 WCHAR * str, * registry_string;
1422 /* we will do the work in a single loop, so here is some things:
1423 * we write netresource at the begin of the user buffer
1424 * we write strings at the end of the user buffer
1426 size_left = *user_size;
1427 total_count = 0;
1428 type = enumerator->dwType;
1429 registry = enumerator->specific.remembered.registry;
1430 str = (WCHAR *)((ULONG_PTR)user_buffer + *user_size - sizeof(WCHAR));
1431 for (index = enumerator->specific.remembered.index; ; ++index)
1433 enumerator->specific.remembered.index = index;
1435 if (*user_count != -1 && total_count == *user_count)
1437 ret = WN_SUCCESS;
1438 break;
1441 len = ARRAY_SIZE(buffer);
1442 ret = RegEnumKeyExW(registry, index, buffer, &len, NULL, NULL, NULL, NULL);
1443 if (ret != ERROR_SUCCESS)
1445 if (ret == ERROR_NO_MORE_ITEMS) ret = WN_SUCCESS;
1446 break;
1449 if (RegOpenKeyExW(registry, buffer, 0, KEY_READ, &connection) != ERROR_SUCCESS)
1451 continue;
1454 full_size = sizeof(NETRESOURCEW);
1455 size_left -= sizeof(NETRESOURCEW);
1457 if (size_left > 0)
1459 size = sizeof(DWORD);
1460 RegQueryValueExW(connection, connectionType, NULL, NULL, (BYTE *)&net_buffer->dwType, &size);
1461 if (type != RESOURCETYPE_ANY && net_buffer->dwType != type)
1463 size_left += sizeof(NETRESOURCEW);
1464 RegCloseKey(connection);
1465 continue;
1468 net_buffer->dwScope = RESOURCE_REMEMBERED;
1469 net_buffer->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
1470 net_buffer->dwUsage = RESOURCEUSAGE_CONNECTABLE;
1472 else
1473 ret = WN_MORE_DATA;
1475 /* FIXME: this only supports drive letters */
1476 full_size += 3 * sizeof(WCHAR);
1477 size_left -= 3 * sizeof(WCHAR);
1478 if (size_left > 0)
1480 str -= 3;
1481 str[0] = buffer[0];
1482 str[1] = ':';
1483 str[2] = 0;
1484 net_buffer->lpLocalName = str;
1487 registry_size = 0;
1488 registry_string = get_reg_str(connection, providerName, &registry_size);
1489 if (registry_string)
1491 full_size += registry_size;
1492 size_left -= registry_size;
1494 if (size_left > 0)
1496 str -= (registry_size / sizeof(WCHAR));
1497 lstrcpyW(str, registry_string);
1498 net_buffer->lpProvider = str;
1500 else
1501 ret = WN_MORE_DATA;
1503 HeapFree(GetProcessHeap(), 0, registry_string);
1506 registry_size = 0;
1507 registry_string = get_reg_str(connection, remotePath, &registry_size);
1508 if (registry_string)
1510 full_size += registry_size;
1511 size_left -= registry_size;
1513 if (size_left > 0)
1515 str -= (registry_size / sizeof(WCHAR));
1516 lstrcpyW(str, registry_string);
1517 net_buffer->lpRemoteName = str;
1519 else
1520 ret = WN_MORE_DATA;
1522 HeapFree(GetProcessHeap(), 0, registry_string);
1525 RegCloseKey(connection);
1527 net_buffer->lpComment = NULL;
1529 if (size_left < 0)
1530 break;
1532 ++total_count;
1533 ++net_buffer;
1536 if (total_count == 0)
1537 ret = WN_NO_MORE_ENTRIES;
1539 *user_count = total_count;
1541 if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
1542 ret = WN_SUCCESS;
1544 if (ret == WN_MORE_DATA)
1545 *user_size = *user_size + full_size;
1547 return ret;
1550 /*********************************************************************
1551 * WNetEnumResourceW [MPR.@]
1553 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1554 LPVOID lpBuffer, LPDWORD lpBufferSize )
1556 DWORD ret;
1558 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1560 if (!hEnum)
1561 ret = WN_BAD_POINTER;
1562 else if (!lpcCount)
1563 ret = WN_BAD_POINTER;
1564 else if (!lpBuffer)
1565 ret = WN_BAD_POINTER;
1566 else if (!lpBufferSize)
1567 ret = WN_BAD_POINTER;
1568 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1570 *lpBufferSize = sizeof(NETRESOURCEW);
1571 ret = WN_MORE_DATA;
1573 else
1575 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1577 switch (enumerator->enumType)
1579 case WNET_ENUMERATOR_TYPE_GLOBAL:
1580 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1581 lpBufferSize);
1582 break;
1583 case WNET_ENUMERATOR_TYPE_PROVIDER:
1584 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1585 lpBufferSize);
1586 break;
1587 case WNET_ENUMERATOR_TYPE_CONTEXT:
1588 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1589 lpBufferSize);
1590 break;
1591 case WNET_ENUMERATOR_TYPE_CONNECTED:
1592 ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer,
1593 lpBufferSize);
1594 break;
1595 case WNET_ENUMERATOR_TYPE_REMEMBERED:
1596 ret = _enumeratorRememberedW(enumerator, lpcCount, lpBuffer,
1597 lpBufferSize);
1598 break;
1599 default:
1600 WARN("bogus enumerator type!\n");
1601 ret = WN_NO_NETWORK;
1604 if (ret)
1605 SetLastError(ret);
1606 TRACE("Returning %d\n", ret);
1607 return ret;
1610 /*********************************************************************
1611 * WNetCloseEnum [MPR.@]
1613 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1615 DWORD ret, index;
1616 HANDLE *handles;
1618 TRACE( "(%p)\n", hEnum );
1620 if (hEnum)
1622 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1624 switch (enumerator->enumType)
1626 case WNET_ENUMERATOR_TYPE_GLOBAL:
1627 if (enumerator->specific.net)
1628 _freeEnumNetResource(enumerator->specific.net);
1629 if (enumerator->handle)
1630 providerTable->table[enumerator->providerIndex].
1631 closeEnum(enumerator->handle);
1632 ret = WN_SUCCESS;
1633 break;
1634 case WNET_ENUMERATOR_TYPE_PROVIDER:
1635 if (enumerator->handle)
1636 providerTable->table[enumerator->providerIndex].
1637 closeEnum(enumerator->handle);
1638 ret = WN_SUCCESS;
1639 break;
1640 case WNET_ENUMERATOR_TYPE_CONNECTED:
1641 handles = enumerator->specific.handles;
1642 for (index = 0; index < providerTable->numProviders; index++)
1644 if (providerTable->table[index].dwEnumScopes && handles[index])
1645 providerTable->table[index].closeEnum(handles[index]);
1647 HeapFree(GetProcessHeap(), 0, handles);
1648 ret = WN_SUCCESS;
1649 break;
1650 case WNET_ENUMERATOR_TYPE_REMEMBERED:
1651 RegCloseKey(enumerator->specific.remembered.registry);
1652 ret = WN_SUCCESS;
1653 break;
1654 default:
1655 WARN("bogus enumerator type!\n");
1656 ret = WN_BAD_HANDLE;
1658 HeapFree(GetProcessHeap(), 0, hEnum);
1660 else
1661 ret = WN_BAD_HANDLE;
1662 if (ret)
1663 SetLastError(ret);
1664 TRACE("Returning %d\n", ret);
1665 return ret;
1668 /*********************************************************************
1669 * WNetGetResourceInformationA [MPR.@]
1671 * See WNetGetResourceInformationW
1673 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1674 LPVOID lpBuffer, LPDWORD cbBuffer,
1675 LPSTR *lplpSystem )
1677 DWORD ret;
1679 TRACE( "(%p, %p, %p, %p)\n",
1680 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1682 if (!providerTable || providerTable->numProviders == 0)
1683 ret = WN_NO_NETWORK;
1684 else if (lpNetResource)
1686 LPNETRESOURCEW lpNetResourceW = NULL;
1687 DWORD size = 1024, count = 1;
1688 DWORD len;
1690 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1691 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1692 if (ret == WN_MORE_DATA)
1694 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1695 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1696 if (lpNetResourceW)
1697 ret = _thunkNetResourceArrayAToW(lpNetResource,
1698 &count, lpNetResourceW, &size);
1699 else
1700 ret = WN_OUT_OF_MEMORY;
1702 if (ret == WN_SUCCESS)
1704 LPWSTR lpSystemW = NULL;
1705 LPVOID lpBufferW;
1706 size = 1024;
1707 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1708 if (lpBufferW)
1710 ret = WNetGetResourceInformationW(lpNetResourceW,
1711 lpBufferW, &size, &lpSystemW);
1712 if (ret == WN_MORE_DATA)
1714 HeapFree(GetProcessHeap(), 0, lpBufferW);
1715 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1716 if (lpBufferW)
1717 ret = WNetGetResourceInformationW(lpNetResourceW,
1718 lpBufferW, &size, &lpSystemW);
1719 else
1720 ret = WN_OUT_OF_MEMORY;
1722 if (ret == WN_SUCCESS)
1724 ret = _thunkNetResourceArrayWToA(lpBufferW,
1725 &count, lpBuffer, cbBuffer);
1726 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1727 lpNetResourceW = lpBufferW;
1728 size = sizeof(NETRESOURCEA);
1729 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1730 -1, NULL, 0, NULL, NULL);
1731 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1732 -1, NULL, 0, NULL, NULL);
1734 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1735 -1, NULL, 0, NULL, NULL);
1736 if ((len) && ( size + len < *cbBuffer))
1738 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1739 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1740 *lplpSystem, len, NULL, NULL);
1741 ret = WN_SUCCESS;
1743 else
1744 ret = WN_MORE_DATA;
1746 else
1747 ret = WN_OUT_OF_MEMORY;
1748 HeapFree(GetProcessHeap(), 0, lpBufferW);
1750 else
1751 ret = WN_OUT_OF_MEMORY;
1752 HeapFree(GetProcessHeap(), 0, lpSystemW);
1754 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1756 else
1757 ret = WN_NO_NETWORK;
1759 if (ret)
1760 SetLastError(ret);
1761 TRACE("Returning %d\n", ret);
1762 return ret;
1765 /*********************************************************************
1766 * WNetGetResourceInformationW [MPR.@]
1768 * WNetGetResourceInformationW function identifies the network provider
1769 * that owns the resource and gets information about the type of the resource.
1771 * PARAMS:
1772 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1773 * defines a network resource.
1774 * lpBuffer [ O] the pointer to buffer, containing result. It
1775 * contains NETRESOURCEW structure and strings to
1776 * which the members of the NETRESOURCEW structure
1777 * point.
1778 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1779 * in bytes.
1780 * lplpSystem [ O] the pointer to string in the output buffer,
1781 * containing the part of the resource name without
1782 * names of the server and share.
1784 * RETURNS:
1785 * NO_ERROR if the function succeeds. System error code if the function fails.
1788 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1789 LPVOID lpBuffer, LPDWORD cbBuffer,
1790 LPWSTR *lplpSystem )
1792 DWORD ret = WN_NO_NETWORK;
1793 DWORD index;
1795 TRACE( "(%p, %p, %p, %p)\n",
1796 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1798 if (!(lpBuffer))
1799 ret = WN_OUT_OF_MEMORY;
1800 else if (providerTable != NULL)
1802 /* FIXME: For function value of a variable is indifferent, it does
1803 * search of all providers in a network.
1805 for (index = 0; index < providerTable->numProviders; index++)
1807 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1808 WNNC_DLG_GETRESOURCEINFORMATION)
1810 if (providerTable->table[index].getResourceInformation)
1811 ret = providerTable->table[index].getResourceInformation(
1812 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1813 else
1814 ret = WN_NO_NETWORK;
1815 if (ret == WN_SUCCESS)
1816 break;
1820 if (ret)
1821 SetLastError(ret);
1822 return ret;
1825 /*********************************************************************
1826 * WNetGetResourceParentA [MPR.@]
1828 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1829 LPVOID lpBuffer, LPDWORD lpBufferSize )
1831 FIXME( "(%p, %p, %p): stub\n",
1832 lpNetResource, lpBuffer, lpBufferSize );
1834 SetLastError(WN_NO_NETWORK);
1835 return WN_NO_NETWORK;
1838 /*********************************************************************
1839 * WNetGetResourceParentW [MPR.@]
1841 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1842 LPVOID lpBuffer, LPDWORD lpBufferSize )
1844 FIXME( "(%p, %p, %p): stub\n",
1845 lpNetResource, lpBuffer, lpBufferSize );
1847 SetLastError(WN_NO_NETWORK);
1848 return WN_NO_NETWORK;
1854 * Connection Functions
1857 /*********************************************************************
1858 * WNetAddConnectionA [MPR.@]
1860 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1861 LPCSTR lpLocalName )
1863 NETRESOURCEA resourcesA;
1865 memset(&resourcesA, 0, sizeof(resourcesA));
1866 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1867 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1868 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1871 /*********************************************************************
1872 * WNetAddConnectionW [MPR.@]
1874 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1875 LPCWSTR lpLocalName )
1877 NETRESOURCEW resourcesW;
1879 memset(&resourcesW, 0, sizeof(resourcesW));
1880 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1881 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1882 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1885 /*********************************************************************
1886 * WNetAddConnection2A [MPR.@]
1888 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1889 LPCSTR lpPassword, LPCSTR lpUserID,
1890 DWORD dwFlags )
1892 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1893 NULL, 0, NULL);
1896 /*********************************************************************
1897 * WNetAddConnection2W [MPR.@]
1899 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1900 LPCWSTR lpPassword, LPCWSTR lpUserID,
1901 DWORD dwFlags )
1903 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1904 NULL, 0, NULL);
1907 /*********************************************************************
1908 * WNetAddConnection3A [MPR.@]
1910 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1911 LPCSTR lpPassword, LPCSTR lpUserID,
1912 DWORD dwFlags )
1914 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1915 dwFlags, NULL, 0, NULL);
1918 /*********************************************************************
1919 * WNetAddConnection3W [MPR.@]
1921 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1922 LPCWSTR lpPassword, LPCWSTR lpUserID,
1923 DWORD dwFlags )
1925 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1926 dwFlags, NULL, 0, NULL);
1929 struct use_connection_context
1931 HWND hwndOwner;
1932 NETRESOURCEW *resource;
1933 NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */
1934 WCHAR *password;
1935 WCHAR *userid;
1936 DWORD flags;
1937 void *accessname;
1938 DWORD *buffer_size;
1939 DWORD *result;
1940 DWORD (*pre_set_accessname)(struct use_connection_context*, WCHAR *);
1941 void (*set_accessname)(struct use_connection_context*, WCHAR *);
1944 static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1946 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1948 DWORD len;
1950 if (local_name)
1951 len = lstrlenW(local_name);
1952 else
1953 len = lstrlenW(ctxt->resource->lpRemoteName);
1955 if (++len > *ctxt->buffer_size)
1957 *ctxt->buffer_size = len;
1958 return ERROR_MORE_DATA;
1961 else
1962 ctxt->accessname = NULL;
1964 return ERROR_SUCCESS;
1967 static void use_connection_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1969 WCHAR *accessname = ctxt->accessname;
1970 if (local_name)
1972 lstrcpyW(accessname, local_name);
1973 if (ctxt->result)
1974 *ctxt->result = CONNECT_LOCALDRIVE;
1976 else
1977 lstrcpyW(accessname, ctxt->resource->lpRemoteName);
1980 static DWORD wnet_use_provider( struct use_connection_context *ctxt, NETRESOURCEW * netres, WNetProvider *provider, BOOLEAN redirect )
1982 DWORD caps, ret;
1984 caps = provider->getCaps(WNNC_CONNECTION);
1985 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1986 return ERROR_BAD_PROVIDER;
1988 ret = WN_ACCESS_DENIED;
1991 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1992 ret = provider->addConnection3(ctxt->hwndOwner, netres, ctxt->password, ctxt->userid, ctxt->flags);
1993 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1994 ret = provider->addConnection(netres, ctxt->password, ctxt->userid);
1996 if (ret == WN_ALREADY_CONNECTED && redirect)
1997 netres->lpLocalName[0] -= 1;
1998 } while (redirect && ret == WN_ALREADY_CONNECTED && netres->lpLocalName[0] >= 'C');
2000 if (ret == WN_SUCCESS && ctxt->accessname)
2001 ctxt->set_accessname(ctxt, netres->lpLocalName);
2003 return ret;
2006 static const WCHAR providerType[] = { 'P','r','o','v','i','d','e','r','T','y','p','e',0 };
2007 static const WCHAR userName[] = { 'U','s','e','r','N','a','m','e',0 };
2009 static DWORD wnet_use_connection( struct use_connection_context *ctxt )
2011 WNetProvider *provider = NULL;
2012 DWORD index, ret = WN_NO_NETWORK;
2013 BOOL redirect = FALSE;
2014 WCHAR letter[3] = {'Z', ':', 0};
2015 NETRESOURCEW netres;
2017 if (!providerTable || providerTable->numProviders == 0)
2018 return WN_NO_NETWORK;
2020 if (!ctxt->resource)
2021 return ERROR_INVALID_PARAMETER;
2022 netres = *ctxt->resource;
2024 if (!netres.lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
2026 if (netres.dwType != RESOURCETYPE_DISK && netres.dwType != RESOURCETYPE_PRINT)
2027 return ERROR_BAD_DEV_TYPE;
2029 if (netres.dwType == RESOURCETYPE_PRINT)
2031 FIXME("Local device selection is not implemented for printers.\n");
2032 return WN_NO_NETWORK;
2035 redirect = TRUE;
2036 netres.lpLocalName = letter;
2039 if (ctxt->flags & CONNECT_INTERACTIVE)
2040 return ERROR_BAD_NET_NAME;
2042 if ((ret = ctxt->pre_set_accessname(ctxt, netres.lpLocalName)))
2043 return ret;
2045 if (netres.lpProvider)
2047 index = _findProviderIndexW(netres.lpProvider);
2048 if (index == BAD_PROVIDER_INDEX)
2049 return ERROR_BAD_PROVIDER;
2051 provider = &providerTable->table[index];
2052 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
2054 else
2056 for (index = 0; index < providerTable->numProviders; index++)
2058 provider = &providerTable->table[index];
2059 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
2060 if (ret == WN_SUCCESS || ret == WN_ALREADY_CONNECTED)
2061 break;
2065 if (ret == WN_SUCCESS && ctxt->flags & CONNECT_UPDATE_PROFILE)
2067 HKEY user_profile;
2069 if (netres.dwType == RESOURCETYPE_PRINT)
2071 FIXME("Persistent connection are not supported for printers\n");
2072 return ret;
2075 if (RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
2077 HKEY network;
2078 WCHAR subkey[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres.lpLocalName[0], 0};
2080 if (RegCreateKeyExW(user_profile, subkey, 0, NULL, REG_OPTION_NON_VOLATILE,
2081 KEY_ALL_ACCESS, NULL, &network, NULL) == ERROR_SUCCESS)
2083 DWORD dword_arg = RESOURCETYPE_DISK;
2084 DWORD len = (lstrlenW(provider->name) + 1) * sizeof(WCHAR);
2085 static const WCHAR empty[1] = {0};
2087 RegSetValueExW(network, connectionType, 0, REG_DWORD, (const BYTE *)&dword_arg, sizeof(DWORD));
2088 RegSetValueExW(network, providerName, 0, REG_SZ, (const BYTE *)provider->name, len);
2089 RegSetValueExW(network, providerType, 0, REG_DWORD, (const BYTE *)&provider->dwNetType, sizeof(DWORD));
2090 len = (lstrlenW(netres.lpRemoteName) + 1) * sizeof(WCHAR);
2091 RegSetValueExW(network, remotePath, 0, REG_SZ, (const BYTE *)netres.lpRemoteName, len);
2092 len = sizeof(empty);
2093 RegSetValueExW(network, userName, 0, REG_SZ, (const BYTE *)empty, len);
2094 RegCloseKey(network);
2097 RegCloseKey(user_profile);
2101 return ret;
2104 /*****************************************************************
2105 * WNetUseConnectionW [MPR.@]
2107 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
2108 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
2110 struct use_connection_context ctxt;
2112 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
2113 hwndOwner, resource, password, debugstr_w(userid), flags,
2114 accessname, buffer_size, result );
2116 ctxt.hwndOwner = hwndOwner;
2117 ctxt.resource = resource;
2118 ctxt.resourceA = NULL;
2119 ctxt.password = (WCHAR*)password;
2120 ctxt.userid = (WCHAR*)userid;
2121 ctxt.flags = flags;
2122 ctxt.accessname = accessname;
2123 ctxt.buffer_size = buffer_size;
2124 ctxt.result = result;
2125 ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
2126 ctxt.set_accessname = use_connection_set_accessnameW;
2128 return wnet_use_connection(&ctxt);
2131 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
2133 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
2135 DWORD len;
2137 if (local_name)
2138 len = WideCharToMultiByte(CP_ACP, 0, local_name, -1, NULL, 0, NULL, NULL) - 1;
2139 else
2140 len = strlen(ctxt->resourceA->lpRemoteName);
2142 if (++len > *ctxt->buffer_size)
2144 *ctxt->buffer_size = len;
2145 return ERROR_MORE_DATA;
2148 else
2149 ctxt->accessname = NULL;
2151 return ERROR_SUCCESS;
2154 static void use_connection_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
2156 char *accessname = ctxt->accessname;
2157 if (local_name)
2159 WideCharToMultiByte(CP_ACP, 0, local_name, -1, accessname, *ctxt->buffer_size, NULL, NULL);
2160 if (ctxt->result)
2161 *ctxt->result = CONNECT_LOCALDRIVE;
2163 else
2164 strcpy(accessname, ctxt->resourceA->lpRemoteName);
2167 static LPWSTR strdupAtoW( LPCSTR str )
2169 LPWSTR ret;
2170 INT len;
2172 if (!str) return NULL;
2173 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
2174 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2175 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
2176 return ret;
2179 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
2181 resourceW->dwScope = resourceA->dwScope;
2182 resourceW->dwType = resourceA->dwType;
2183 resourceW->dwDisplayType = resourceA->dwDisplayType;
2184 resourceW->dwUsage = resourceA->dwUsage;
2185 resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
2186 resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
2187 resourceW->lpComment = strdupAtoW(resourceA->lpComment);
2188 resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
2191 static void free_netresourceW( NETRESOURCEW *resource )
2193 HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
2194 HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
2195 HeapFree(GetProcessHeap(), 0, resource->lpComment);
2196 HeapFree(GetProcessHeap(), 0, resource->lpProvider);
2199 /*****************************************************************
2200 * WNetUseConnectionA [MPR.@]
2202 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
2203 LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
2204 DWORD *buffer_size, DWORD *result )
2206 struct use_connection_context ctxt;
2207 NETRESOURCEW resourceW;
2208 DWORD ret;
2210 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
2211 accessname, buffer_size, result );
2213 netresource_a_to_w(resource, &resourceW);
2215 ctxt.hwndOwner = hwndOwner;
2216 ctxt.resource = &resourceW;
2217 ctxt.resourceA = resource;
2218 ctxt.password = strdupAtoW(password);
2219 ctxt.userid = strdupAtoW(userid);
2220 ctxt.flags = flags;
2221 ctxt.accessname = accessname;
2222 ctxt.buffer_size = buffer_size;
2223 ctxt.result = result;
2224 ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
2225 ctxt.set_accessname = use_connection_set_accessnameA;
2227 ret = wnet_use_connection(&ctxt);
2229 free_netresourceW(&resourceW);
2230 HeapFree(GetProcessHeap(), 0, ctxt.password);
2231 HeapFree(GetProcessHeap(), 0, ctxt.userid);
2233 return ret;
2236 /*********************************************************************
2237 * WNetCancelConnectionA [MPR.@]
2239 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
2241 return WNetCancelConnection2A(lpName, 0, fForce);
2244 /*********************************************************************
2245 * WNetCancelConnectionW [MPR.@]
2247 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
2249 return WNetCancelConnection2W(lpName, 0, fForce);
2252 /*********************************************************************
2253 * WNetCancelConnection2A [MPR.@]
2255 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
2257 DWORD ret;
2258 WCHAR * name = strdupAtoW(lpName);
2259 if (!name)
2260 return ERROR_NOT_CONNECTED;
2262 ret = WNetCancelConnection2W(name, dwFlags, fForce);
2263 HeapFree(GetProcessHeap(), 0, name);
2265 return ret;
2268 /*********************************************************************
2269 * WNetCancelConnection2W [MPR.@]
2271 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
2273 DWORD ret = WN_NO_NETWORK;
2274 DWORD index;
2276 if (providerTable != NULL)
2278 for (index = 0; index < providerTable->numProviders; index++)
2280 if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2281 WNNC_CON_CANCELCONNECTION)
2283 if (providerTable->table[index].cancelConnection)
2284 ret = providerTable->table[index].cancelConnection((LPWSTR)lpName, fForce);
2285 else
2286 ret = WN_NO_NETWORK;
2287 if (ret == WN_SUCCESS || ret == WN_OPEN_FILES)
2288 break;
2293 if (ret == WN_SUCCESS && dwFlags & CONNECT_UPDATE_PROFILE)
2295 HKEY user_profile;
2297 /* FIXME: Only remove it if that's a drive letter */
2298 if (iswalpha(lpName[0]) && lpName[1] == ':' &&
2299 RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
2301 WCHAR subkey[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', lpName[0], 0};
2303 RegDeleteKeyW(user_profile, subkey);
2305 RegCloseKey(user_profile);
2309 return ret;
2312 /*****************************************************************
2313 * WNetRestoreConnectionA [MPR.@]
2315 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
2317 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
2319 SetLastError(WN_NO_NETWORK);
2320 return WN_NO_NETWORK;
2323 /*****************************************************************
2324 * WNetRestoreConnectionW [MPR.@]
2326 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
2328 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
2330 SetLastError(WN_NO_NETWORK);
2331 return WN_NO_NETWORK;
2334 /**************************************************************************
2335 * WNetGetConnectionA [MPR.@]
2337 * RETURNS
2338 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2339 * - WN_NOT_CONNECTED drive is a local drive
2340 * - WN_MORE_DATA buffer isn't big enough
2341 * - WN_SUCCESS success (net path in buffer)
2343 * FIXME: need to test return values under different errors
2345 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
2346 LPSTR lpRemoteName, LPDWORD lpBufferSize )
2348 DWORD ret;
2350 if (!lpLocalName)
2351 ret = WN_BAD_POINTER;
2352 else if (!lpBufferSize)
2353 ret = WN_BAD_POINTER;
2354 else if (!lpRemoteName && *lpBufferSize)
2355 ret = WN_BAD_POINTER;
2356 else
2358 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
2360 if (len)
2362 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2364 if (wideLocalName)
2366 WCHAR wideRemoteStatic[MAX_PATH];
2367 DWORD wideRemoteSize = ARRAY_SIZE(wideRemoteStatic);
2369 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
2371 /* try once without memory allocation */
2372 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
2373 &wideRemoteSize);
2374 if (ret == WN_SUCCESS)
2376 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2377 -1, NULL, 0, NULL, NULL);
2379 if (len <= *lpBufferSize)
2381 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
2382 lpRemoteName, *lpBufferSize, NULL, NULL);
2383 ret = WN_SUCCESS;
2385 else
2387 *lpBufferSize = len;
2388 ret = WN_MORE_DATA;
2391 else if (ret == WN_MORE_DATA)
2393 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
2394 wideRemoteSize * sizeof(WCHAR));
2396 if (wideRemote)
2398 ret = WNetGetConnectionW(wideLocalName, wideRemote,
2399 &wideRemoteSize);
2400 if (ret == WN_SUCCESS)
2402 if (len <= *lpBufferSize)
2404 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2405 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
2406 ret = WN_SUCCESS;
2408 else
2410 *lpBufferSize = len;
2411 ret = WN_MORE_DATA;
2414 HeapFree(GetProcessHeap(), 0, wideRemote);
2416 else
2417 ret = WN_OUT_OF_MEMORY;
2419 HeapFree(GetProcessHeap(), 0, wideLocalName);
2421 else
2422 ret = WN_OUT_OF_MEMORY;
2424 else
2425 ret = WN_BAD_LOCALNAME;
2427 if (ret)
2428 SetLastError(ret);
2429 TRACE("Returning %d\n", ret);
2430 return ret;
2433 /* find the network connection for a given drive; helper for WNetGetConnection */
2434 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
2436 char buffer[1024];
2437 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
2438 HANDLE mgr;
2439 DWORD ret = WN_NOT_CONNECTED;
2440 DWORD bytes_returned;
2442 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
2443 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
2444 0, 0 )) == INVALID_HANDLE_VALUE)
2446 ERR( "failed to open mount manager err %u\n", GetLastError() );
2447 return ret;
2449 memset( data, 0, sizeof(*data) );
2450 data->letter = letter;
2451 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
2452 data, sizeof(buffer), &bytes_returned, NULL ))
2454 char *p, *mount_point = buffer + data->mount_point_offset;
2455 DWORD len;
2457 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
2459 mount_point += 2;
2460 mount_point[0] = '\\';
2461 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
2463 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
2464 if (len > *size)
2466 *size = len;
2467 ret = WN_MORE_DATA;
2469 else
2471 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
2472 ret = WN_SUCCESS;
2476 CloseHandle( mgr );
2477 return ret;
2480 /**************************************************************************
2481 * WNetGetConnectionW [MPR.@]
2483 * FIXME: need to test return values under different errors
2485 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
2486 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
2488 DWORD ret;
2490 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
2491 lpBufferSize);
2493 if (!lpLocalName)
2494 ret = WN_BAD_POINTER;
2495 else if (!lpBufferSize)
2496 ret = WN_BAD_POINTER;
2497 else if (!lpRemoteName && *lpBufferSize)
2498 ret = WN_BAD_POINTER;
2499 else if (!lpLocalName[0])
2500 ret = WN_BAD_LOCALNAME;
2501 else
2503 if (lpLocalName[1] == ':')
2505 switch(GetDriveTypeW(lpLocalName))
2507 case DRIVE_REMOTE:
2508 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
2509 break;
2510 case DRIVE_REMOVABLE:
2511 case DRIVE_FIXED:
2512 case DRIVE_CDROM:
2513 TRACE("file is local\n");
2514 ret = WN_NOT_CONNECTED;
2515 break;
2516 default:
2517 ret = WN_BAD_LOCALNAME;
2520 else
2521 ret = WN_BAD_LOCALNAME;
2523 if (ret)
2524 SetLastError(ret);
2525 TRACE("Returning %d\n", ret);
2526 return ret;
2529 /**************************************************************************
2530 * WNetSetConnectionA [MPR.@]
2532 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
2533 LPVOID pvValue )
2535 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
2537 SetLastError(WN_NO_NETWORK);
2538 return WN_NO_NETWORK;
2541 /**************************************************************************
2542 * WNetSetConnectionW [MPR.@]
2544 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2545 LPVOID pvValue )
2547 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2549 SetLastError(WN_NO_NETWORK);
2550 return WN_NO_NETWORK;
2553 /*****************************************************************
2554 * WNetGetUniversalNameA [MPR.@]
2556 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2557 LPVOID lpBuffer, LPDWORD lpBufferSize )
2559 DWORD err, size;
2561 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2562 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2564 switch (dwInfoLevel)
2566 case UNIVERSAL_NAME_INFO_LEVEL:
2568 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2570 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2572 err = ERROR_NOT_CONNECTED;
2573 break;
2576 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2577 if (*lpBufferSize < size)
2579 err = WN_MORE_DATA;
2580 break;
2582 info->lpUniversalName = (char *)info + sizeof(*info);
2583 lstrcpyA(info->lpUniversalName, lpLocalPath);
2584 err = WN_NO_ERROR;
2585 break;
2587 case REMOTE_NAME_INFO_LEVEL:
2588 err = WN_NOT_CONNECTED;
2589 break;
2591 default:
2592 err = WN_BAD_VALUE;
2593 break;
2596 SetLastError(err);
2597 return err;
2600 /*****************************************************************
2601 * WNetGetUniversalNameW [MPR.@]
2603 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2604 LPVOID lpBuffer, LPDWORD lpBufferSize )
2606 DWORD err, size;
2608 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2609 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2611 switch (dwInfoLevel)
2613 case UNIVERSAL_NAME_INFO_LEVEL:
2615 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2617 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2619 err = ERROR_NOT_CONNECTED;
2620 break;
2623 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2624 if (*lpBufferSize < size)
2626 *lpBufferSize = size;
2627 err = WN_MORE_DATA;
2628 break;
2630 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2631 lstrcpyW(info->lpUniversalName, lpLocalPath);
2632 err = WN_NO_ERROR;
2633 break;
2635 case REMOTE_NAME_INFO_LEVEL:
2636 err = WN_NO_NETWORK;
2637 break;
2639 default:
2640 err = WN_BAD_VALUE;
2641 break;
2644 if (err != WN_NO_ERROR) SetLastError(err);
2645 return err;
2648 /*****************************************************************
2649 * WNetClearConnections [MPR.@]
2651 DWORD WINAPI WNetClearConnections ( HWND owner )
2653 HANDLE connected;
2654 PWSTR connection;
2655 DWORD ret, size, count;
2656 NETRESOURCEW * resources, * iter;
2658 ret = WNetOpenEnumW(RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL, &connected);
2659 if (ret != WN_SUCCESS)
2661 if (ret != WN_NO_NETWORK)
2663 return ret;
2666 /* Means no provider, then, clearing is OK */
2667 return WN_SUCCESS;
2670 size = 0x1000;
2671 resources = HeapAlloc(GetProcessHeap(), 0, size);
2672 if (!resources)
2674 WNetCloseEnum(connected);
2675 return WN_OUT_OF_MEMORY;
2678 for (;;)
2680 size = 0x1000;
2681 count = -1;
2683 memset(resources, 0, size);
2684 ret = WNetEnumResourceW(connected, &count, resources, &size);
2685 if (ret == WN_SUCCESS || ret == WN_MORE_DATA)
2687 for (iter = resources; count; count--, iter++)
2689 if (iter->lpLocalName && iter->lpLocalName[0])
2690 connection = iter->lpLocalName;
2691 else
2692 connection = iter->lpRemoteName;
2694 WNetCancelConnection2W(connection, 0, TRUE);
2697 else
2698 break;
2701 HeapFree(GetProcessHeap(), 0, resources);
2702 WNetCloseEnum(connected);
2704 return ret;
2709 * Other Functions
2712 /**************************************************************************
2713 * WNetGetUserA [MPR.@]
2715 * FIXME: we should not return ourselves, but the owner of the drive lpName
2717 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2719 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2720 return GetLastError();
2723 /*****************************************************************
2724 * WNetGetUserW [MPR.@]
2726 * FIXME: we should not return ourselves, but the owner of the drive lpName
2728 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2730 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2731 return GetLastError();
2734 /*********************************************************************
2735 * WNetConnectionDialog [MPR.@]
2737 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2739 CONNECTDLGSTRUCTW conn_dlg;
2740 NETRESOURCEW net_res;
2742 ZeroMemory(&conn_dlg, sizeof(conn_dlg));
2743 ZeroMemory(&net_res, sizeof(net_res));
2745 conn_dlg.cbStructure = sizeof(conn_dlg);
2746 conn_dlg.lpConnRes = &net_res;
2747 conn_dlg.hwndOwner = hwnd;
2748 net_res.dwType = dwType;
2750 return WNetConnectionDialog1W(&conn_dlg);
2753 /*********************************************************************
2754 * WNetConnectionDialog1A [MPR.@]
2756 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2758 FIXME( "(%p): stub\n", lpConnDlgStruct );
2760 SetLastError(WN_NO_NETWORK);
2761 return WN_NO_NETWORK;
2764 /*********************************************************************
2765 * WNetConnectionDialog1W [MPR.@]
2767 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2769 FIXME( "(%p): stub\n", lpConnDlgStruct );
2771 SetLastError(WN_NO_NETWORK);
2772 return WN_NO_NETWORK;
2775 /*********************************************************************
2776 * WNetDisconnectDialog [MPR.@]
2778 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2780 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2782 SetLastError(WN_NO_NETWORK);
2783 return WN_NO_NETWORK;
2786 /*********************************************************************
2787 * WNetDisconnectDialog1A [MPR.@]
2789 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2791 FIXME( "(%p): stub\n", lpConnDlgStruct );
2793 SetLastError(WN_NO_NETWORK);
2794 return WN_NO_NETWORK;
2797 /*********************************************************************
2798 * WNetDisconnectDialog1W [MPR.@]
2800 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2802 FIXME( "(%p): stub\n", lpConnDlgStruct );
2804 SetLastError(WN_NO_NETWORK);
2805 return WN_NO_NETWORK;
2808 /*********************************************************************
2809 * WNetGetLastErrorA [MPR.@]
2811 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2812 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2813 LPSTR lpNameBuf, DWORD nNameBufSize )
2815 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2816 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2818 SetLastError(WN_NO_NETWORK);
2819 return WN_NO_NETWORK;
2822 /*********************************************************************
2823 * WNetGetLastErrorW [MPR.@]
2825 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2826 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2827 LPWSTR lpNameBuf, DWORD nNameBufSize )
2829 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2830 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2832 SetLastError(WN_NO_NETWORK);
2833 return WN_NO_NETWORK;
2836 /*********************************************************************
2837 * WNetGetNetworkInformationA [MPR.@]
2839 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2840 LPNETINFOSTRUCT lpNetInfoStruct )
2842 DWORD ret;
2844 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2846 if (!lpProvider)
2847 ret = WN_BAD_POINTER;
2848 else
2850 int len;
2852 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2853 if (len)
2855 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2857 if (wideProvider)
2859 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2860 len);
2861 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2862 HeapFree(GetProcessHeap(), 0, wideProvider);
2864 else
2865 ret = WN_OUT_OF_MEMORY;
2867 else
2868 ret = GetLastError();
2870 if (ret)
2871 SetLastError(ret);
2872 TRACE("Returning %d\n", ret);
2873 return ret;
2876 /*********************************************************************
2877 * WNetGetNetworkInformationW [MPR.@]
2879 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2880 LPNETINFOSTRUCT lpNetInfoStruct )
2882 DWORD ret;
2884 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2886 if (!lpProvider)
2887 ret = WN_BAD_POINTER;
2888 else if (!lpNetInfoStruct)
2889 ret = WN_BAD_POINTER;
2890 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2891 ret = WN_BAD_VALUE;
2892 else
2894 if (providerTable && providerTable->numProviders)
2896 DWORD providerIndex = _findProviderIndexW(lpProvider);
2898 if (providerIndex != BAD_PROVIDER_INDEX)
2900 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2901 lpNetInfoStruct->dwProviderVersion =
2902 providerTable->table[providerIndex].dwSpecVersion;
2903 lpNetInfoStruct->dwStatus = NO_ERROR;
2904 lpNetInfoStruct->dwCharacteristics = 0;
2905 lpNetInfoStruct->dwHandle = 0;
2906 lpNetInfoStruct->wNetType =
2907 HIWORD(providerTable->table[providerIndex].dwNetType);
2908 lpNetInfoStruct->dwPrinters = -1;
2909 lpNetInfoStruct->dwDrives = -1;
2910 ret = WN_SUCCESS;
2912 else
2913 ret = WN_BAD_PROVIDER;
2915 else
2916 ret = WN_NO_NETWORK;
2918 if (ret)
2919 SetLastError(ret);
2920 TRACE("Returning %d\n", ret);
2921 return ret;
2924 /*****************************************************************
2925 * WNetGetProviderNameA [MPR.@]
2927 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2928 LPSTR lpProvider, LPDWORD lpBufferSize )
2930 DWORD ret;
2932 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2933 lpBufferSize);
2935 if (!lpProvider)
2936 ret = WN_BAD_POINTER;
2937 else if (!lpBufferSize)
2938 ret = WN_BAD_POINTER;
2939 else
2941 if (providerTable)
2943 DWORD i;
2945 ret = WN_NO_NETWORK;
2946 for (i = 0; i < providerTable->numProviders &&
2947 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2948 i++)
2950 if (i < providerTable->numProviders)
2952 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2953 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2955 if (*lpBufferSize < sizeNeeded)
2957 *lpBufferSize = sizeNeeded;
2958 ret = WN_MORE_DATA;
2960 else
2962 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2963 -1, lpProvider, *lpBufferSize, NULL, NULL);
2964 ret = WN_SUCCESS;
2965 /* FIXME: is *lpBufferSize set to the number of characters
2966 * copied? */
2970 else
2971 ret = WN_NO_NETWORK;
2973 if (ret)
2974 SetLastError(ret);
2975 TRACE("Returning %d\n", ret);
2976 return ret;
2979 /*****************************************************************
2980 * WNetGetProviderNameW [MPR.@]
2982 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2983 LPWSTR lpProvider, LPDWORD lpBufferSize )
2985 DWORD ret;
2987 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2988 lpBufferSize);
2990 if (!lpProvider)
2991 ret = WN_BAD_POINTER;
2992 else if (!lpBufferSize)
2993 ret = WN_BAD_POINTER;
2994 else
2996 if (providerTable)
2998 DWORD i;
3000 ret = WN_NO_NETWORK;
3001 for (i = 0; i < providerTable->numProviders &&
3002 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
3003 i++)
3005 if (i < providerTable->numProviders)
3007 DWORD sizeNeeded = lstrlenW(providerTable->table[i].name) + 1;
3009 if (*lpBufferSize < sizeNeeded)
3011 *lpBufferSize = sizeNeeded;
3012 ret = WN_MORE_DATA;
3014 else
3016 lstrcpyW(lpProvider, providerTable->table[i].name);
3017 ret = WN_SUCCESS;
3018 /* FIXME: is *lpBufferSize set to the number of characters
3019 * copied? */
3023 else
3024 ret = WN_NO_NETWORK;
3026 if (ret)
3027 SetLastError(ret);
3028 TRACE("Returning %d\n", ret);
3029 return ret;