ntoskrnl.exe/tests: Fix path buffer allocation size.
[wine.git] / dlls / mpr / wnet.c
blobdf8aef260800b28ff1bf4ecdc0eeae3cd72b2a26
1 /*
2 * MPR WNet functions
4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
7 * Copyright 2016-2018 Pierre Schweitzer
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnls.h"
28 #include "winioctl.h"
29 #include "winnetwk.h"
30 #include "npapi.h"
31 #include "winreg.h"
32 #include "winuser.h"
33 #define WINE_MOUNTMGR_EXTENSIONS
34 #include "ddk/mountmgr.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "mprres.h"
38 #include "wnetpriv.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(mpr);
42 /* Data structures representing network service providers. Assumes only one
43 * thread creates them, and that they are constant for the life of the process
44 * (and therefore doesn't synchronize access).
45 * FIXME: only basic provider data and enumeration-related data are implemented
46 * so far, need to implement the rest too.
48 typedef struct _WNetProvider
50 HMODULE hLib;
51 PWSTR name;
52 PF_NPGetCaps getCaps;
53 DWORD dwSpecVersion;
54 DWORD dwNetType;
55 DWORD dwEnumScopes;
56 PF_NPOpenEnum openEnum;
57 PF_NPEnumResource enumResource;
58 PF_NPCloseEnum closeEnum;
59 PF_NPGetResourceInformation getResourceInformation;
60 PF_NPAddConnection addConnection;
61 PF_NPAddConnection3 addConnection3;
62 PF_NPCancelConnection cancelConnection;
63 } WNetProvider, *PWNetProvider;
65 typedef struct _WNetProviderTable
67 LPWSTR entireNetwork;
68 DWORD numAllocated;
69 DWORD numProviders;
70 WNetProvider table[1];
71 } WNetProviderTable, *PWNetProviderTable;
73 #define WNET_ENUMERATOR_TYPE_GLOBAL 0
74 #define WNET_ENUMERATOR_TYPE_PROVIDER 1
75 #define WNET_ENUMERATOR_TYPE_CONTEXT 2
76 #define WNET_ENUMERATOR_TYPE_CONNECTED 3
77 #define WNET_ENUMERATOR_TYPE_REMEMBERED 4
79 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
80 * the enumeration; it represents one of the following types:
81 * - a global enumeration, one that's executed across all providers
82 * - a provider-specific enumeration, one that's only executed by a single
83 * provider
84 * - a context enumeration. I know this contradicts what I just said about
85 * there being no correspondence between the scope and the type, but it's
86 * necessary for the special case that a "Entire Network" entry needs to
87 * be enumerated in an enumeration of the context scope. Thus an enumeration
88 * of the context scope results in a context type enumerator, which morphs
89 * into a global enumeration (so the enumeration continues across all
90 * providers).
91 * - a remembered enumeration, not related to providers themselves, but it
92 * is a registry enumeration for saved connections
94 typedef struct _WNetEnumerator
96 DWORD enumType;
97 DWORD providerIndex;
98 HANDLE handle;
99 BOOL providerDone;
100 DWORD dwScope;
101 DWORD dwType;
102 DWORD dwUsage;
103 union
105 NETRESOURCEW* net;
106 HANDLE* handles;
107 struct
109 HKEY registry;
110 DWORD index;
111 } remembered;
112 } specific;
113 } WNetEnumerator, *PWNetEnumerator;
115 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
117 /* Returns an index (into the global WNetProviderTable) of the provider with
118 * the given name, or BAD_PROVIDER_INDEX if not found.
120 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
122 static PWNetProviderTable providerTable;
125 * Global provider table functions
128 static void _tryLoadProvider(PCWSTR provider)
130 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
131 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'S','e','r','v','i','c','e','s','\\',0 };
133 static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
134 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
135 WCHAR serviceName[MAX_PATH];
136 HKEY hKey;
138 TRACE("%s\n", debugstr_w(provider));
139 snprintfW(serviceName, ARRAY_SIZE(serviceName), serviceFmt, servicePrefix, provider);
140 serviceName[ARRAY_SIZE(serviceName) - 1] = '\0';
141 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
142 ERROR_SUCCESS)
144 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
145 'P','a','t','h',0 };
146 WCHAR providerPath[MAX_PATH];
147 DWORD type, size = sizeof(providerPath);
149 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
150 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && (type == REG_SZ || type == REG_EXPAND_SZ))
152 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
153 PWSTR name = NULL;
155 if (type == REG_EXPAND_SZ)
157 WCHAR path[MAX_PATH];
158 if (ExpandEnvironmentStringsW(providerPath, path, MAX_PATH)) lstrcpyW( providerPath, path );
161 size = 0;
162 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
163 if (size)
165 name = HeapAlloc(GetProcessHeap(), 0, size);
166 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
167 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
169 HeapFree(GetProcessHeap(), 0, name);
170 name = NULL;
173 if (name)
175 HMODULE hLib = LoadLibraryW(providerPath);
177 if (hLib)
179 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
181 PF_NPGetCaps getCaps = MPR_GETPROC(NPGetCaps);
183 TRACE("loaded lib %p\n", hLib);
184 if (getCaps)
186 DWORD connectCap;
187 PWNetProvider provider =
188 &providerTable->table[providerTable->numProviders];
190 provider->hLib = hLib;
191 provider->name = name;
192 TRACE("name is %s\n", debugstr_w(name));
193 provider->getCaps = getCaps;
194 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
195 provider->dwNetType = getCaps(WNNC_NET_TYPE);
196 TRACE("net type is 0x%08x\n", provider->dwNetType);
197 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
198 if (provider->dwEnumScopes)
200 TRACE("supports enumeration\n");
201 provider->openEnum = MPR_GETPROC(NPOpenEnum);
202 TRACE("NPOpenEnum %p\n", provider->openEnum);
203 provider->enumResource = MPR_GETPROC(NPEnumResource);
204 TRACE("NPEnumResource %p\n", provider->enumResource);
205 provider->closeEnum = MPR_GETPROC(NPCloseEnum);
206 TRACE("NPCloseEnum %p\n", provider->closeEnum);
207 provider->getResourceInformation = MPR_GETPROC(NPGetResourceInformation);
208 TRACE("NPGetResourceInformation %p\n", provider->getResourceInformation);
209 if (!provider->openEnum ||
210 !provider->enumResource ||
211 !provider->closeEnum)
213 provider->openEnum = NULL;
214 provider->enumResource = NULL;
215 provider->closeEnum = NULL;
216 provider->dwEnumScopes = 0;
217 WARN("Couldn't load enumeration functions\n");
220 connectCap = getCaps(WNNC_CONNECTION);
221 if (connectCap & WNNC_CON_ADDCONNECTION)
222 provider->addConnection = MPR_GETPROC(NPAddConnection);
223 if (connectCap & WNNC_CON_ADDCONNECTION3)
224 provider->addConnection3 = MPR_GETPROC(NPAddConnection3);
225 if (connectCap & WNNC_CON_CANCELCONNECTION)
226 provider->cancelConnection = MPR_GETPROC(NPCancelConnection);
227 TRACE("NPAddConnection %p\n", provider->addConnection);
228 TRACE("NPAddConnection3 %p\n", provider->addConnection3);
229 TRACE("NPCancelConnection %p\n", provider->cancelConnection);
230 providerTable->numProviders++;
232 else
234 WARN("Provider %s didn't export NPGetCaps\n",
235 debugstr_w(provider));
236 HeapFree(GetProcessHeap(), 0, name);
237 FreeLibrary(hLib);
240 #undef MPR_GETPROC
242 else
244 WARN("Couldn't load library %s for provider %s\n",
245 debugstr_w(providerPath), debugstr_w(provider));
246 HeapFree(GetProcessHeap(), 0, name);
249 else
251 WARN("Couldn't get provider name for provider %s\n",
252 debugstr_w(provider));
255 else
256 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
257 RegCloseKey(hKey);
259 else
260 WARN("Couldn't open service key for provider %s\n",
261 debugstr_w(provider));
264 void wnetInit(HINSTANCE hInstDll)
266 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
267 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
268 'C','o','n','t','r','o','l','\\',
269 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
270 'O','r','d','e','r',0 };
271 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
272 'O','r','d','e','r',0 };
273 HKEY hKey;
275 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
276 == ERROR_SUCCESS)
278 DWORD size = 0;
280 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
281 if (size)
283 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
285 if (providers)
287 DWORD type;
289 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
290 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
292 PWSTR ptr;
293 DWORD numToAllocate;
295 TRACE("provider order is %s\n", debugstr_w(providers));
296 /* first count commas as a heuristic for how many to
297 * allocate space for */
298 for (ptr = providers, numToAllocate = 1; ptr; )
300 ptr = strchrW(ptr, ',');
301 if (ptr) {
302 numToAllocate++;
303 ptr++;
306 providerTable =
307 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
308 sizeof(WNetProviderTable)
309 + (numToAllocate - 1) * sizeof(WNetProvider));
310 if (providerTable)
312 PWSTR ptrPrev;
313 int entireNetworkLen;
314 LPCWSTR stringresource;
316 entireNetworkLen = LoadStringW(hInstDll,
317 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
318 providerTable->entireNetwork = HeapAlloc(
319 GetProcessHeap(), 0, (entireNetworkLen + 1) *
320 sizeof(WCHAR));
321 if (providerTable->entireNetwork)
323 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
324 providerTable->entireNetwork[entireNetworkLen] = 0;
326 providerTable->numAllocated = numToAllocate;
327 for (ptr = providers; ptr; )
329 ptrPrev = ptr;
330 ptr = strchrW(ptr, ',');
331 if (ptr)
332 *ptr++ = '\0';
333 _tryLoadProvider(ptrPrev);
337 HeapFree(GetProcessHeap(), 0, providers);
340 RegCloseKey(hKey);
344 void wnetFree(void)
346 if (providerTable)
348 DWORD i;
350 for (i = 0; i < providerTable->numProviders; i++)
352 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
353 FreeModule(providerTable->table[i].hLib);
355 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
356 HeapFree(GetProcessHeap(), 0, providerTable);
357 providerTable = NULL;
361 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
363 DWORD ret = BAD_PROVIDER_INDEX;
365 if (providerTable && providerTable->numProviders)
367 DWORD i;
369 for (i = 0; i < providerTable->numProviders &&
370 ret == BAD_PROVIDER_INDEX; i++)
371 if (!strcmpW(lpProvider, providerTable->table[i].name))
372 ret = i;
374 return ret;
378 * Browsing Functions
381 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
383 LPNETRESOURCEW ret;
385 if (lpNet)
387 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
388 if (ret)
390 size_t len;
392 *ret = *lpNet;
393 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
394 if (lpNet->lpRemoteName)
396 len = strlenW(lpNet->lpRemoteName) + 1;
397 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
398 if (ret->lpRemoteName)
399 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
403 else
404 ret = NULL;
405 return ret;
408 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
410 if (lpNet)
412 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
413 HeapFree(GetProcessHeap(), 0, lpNet);
417 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
418 DWORD dwUsage, LPNETRESOURCEW lpNet)
420 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
421 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
423 if (ret)
425 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
426 ret->dwScope = dwScope;
427 ret->dwType = dwType;
428 ret->dwUsage = dwUsage;
429 ret->specific.net = _copyNetResourceForEnumW(lpNet);
431 return ret;
434 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
435 DWORD dwUsage, DWORD index, HANDLE handle)
437 PWNetEnumerator ret;
439 if (!providerTable || index >= providerTable->numProviders)
440 ret = NULL;
441 else
443 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
444 if (ret)
446 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
447 ret->providerIndex = index;
448 ret->dwScope = dwScope;
449 ret->dwType = dwType;
450 ret->dwUsage = dwUsage;
451 ret->handle = handle;
454 return ret;
457 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
458 DWORD dwUsage)
460 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
461 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
463 if (ret)
465 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
466 ret->dwScope = dwScope;
467 ret->dwType = dwType;
468 ret->dwUsage = dwUsage;
470 return ret;
473 static PWNetEnumerator _createConnectedEnumerator(DWORD dwScope, DWORD dwType,
474 DWORD dwUsage)
476 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
477 if (ret)
479 ret->enumType = WNET_ENUMERATOR_TYPE_CONNECTED;
480 ret->dwScope = dwScope;
481 ret->dwType = dwType;
482 ret->dwUsage = dwUsage;
483 ret->specific.handles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HANDLE) * providerTable->numProviders);
484 if (!ret->specific.handles)
486 HeapFree(GetProcessHeap(), 0, ret);
487 ret = NULL;
490 return ret;
493 static PWNetEnumerator _createRememberedEnumerator(DWORD dwScope, DWORD dwType,
494 HKEY remembered)
496 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
497 if (ret)
499 ret->enumType = WNET_ENUMERATOR_TYPE_REMEMBERED;
500 ret->dwScope = dwScope;
501 ret->dwType = dwType;
502 ret->specific.remembered.registry = remembered;
504 return ret;
507 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
508 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
509 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
510 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
511 * if not all members of the array could be thunked, and something else on
512 * failure.
514 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
515 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
517 DWORD i, numToThunk, totalBytes, ret;
518 LPSTR strNext;
520 if (!lpNetArrayIn)
521 return WN_BAD_POINTER;
522 if (!lpcCount)
523 return WN_BAD_POINTER;
524 if (*lpcCount == -1)
525 return WN_BAD_VALUE;
526 if (!lpBuffer)
527 return WN_BAD_POINTER;
528 if (!lpBufferSize)
529 return WN_BAD_POINTER;
531 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
533 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
535 totalBytes += sizeof(NETRESOURCEA);
536 if (lpNet->lpLocalName)
537 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
538 -1, NULL, 0, NULL, NULL);
539 if (lpNet->lpRemoteName)
540 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
541 -1, NULL, 0, NULL, NULL);
542 if (lpNet->lpComment)
543 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
544 -1, NULL, 0, NULL, NULL);
545 if (lpNet->lpProvider)
546 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
547 -1, NULL, 0, NULL, NULL);
548 if (totalBytes < *lpBufferSize)
549 numToThunk = i + 1;
551 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
552 for (i = 0; i < numToThunk; i++)
554 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
555 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
557 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
558 /* lie about string lengths, we already verified how many
559 * we have space for above
561 if (lpNetIn->lpLocalName)
563 lpNetOut->lpLocalName = strNext;
564 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
565 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
567 if (lpNetIn->lpRemoteName)
569 lpNetOut->lpRemoteName = strNext;
570 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
571 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
573 if (lpNetIn->lpComment)
575 lpNetOut->lpComment = strNext;
576 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
577 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
579 if (lpNetIn->lpProvider)
581 lpNetOut->lpProvider = strNext;
582 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
583 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
586 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
587 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
588 *lpcCount, ret);
589 return ret;
592 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
593 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
594 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
595 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
596 * if not all members of the array could be thunked, and something else on
597 * failure.
599 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
600 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
602 DWORD i, numToThunk, totalBytes, ret;
603 LPWSTR strNext;
605 if (!lpNetArrayIn)
606 return WN_BAD_POINTER;
607 if (!lpcCount)
608 return WN_BAD_POINTER;
609 if (*lpcCount == -1)
610 return WN_BAD_VALUE;
611 if (!lpBuffer)
612 return WN_BAD_POINTER;
613 if (!lpBufferSize)
614 return WN_BAD_POINTER;
616 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
618 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
620 totalBytes += sizeof(NETRESOURCEW);
621 if (lpNet->lpLocalName)
622 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
623 -1, NULL, 0) * sizeof(WCHAR);
624 if (lpNet->lpRemoteName)
625 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
626 -1, NULL, 0) * sizeof(WCHAR);
627 if (lpNet->lpComment)
628 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
629 -1, NULL, 0) * sizeof(WCHAR);
630 if (lpNet->lpProvider)
631 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
632 -1, NULL, 0) * sizeof(WCHAR);
633 if (totalBytes < *lpBufferSize)
634 numToThunk = i + 1;
636 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
637 for (i = 0; i < numToThunk; i++)
639 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
640 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
642 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
643 /* lie about string lengths, we already verified how many
644 * we have space for above
646 if (lpNetIn->lpLocalName)
648 lpNetOut->lpLocalName = strNext;
649 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
650 -1, lpNetOut->lpLocalName, *lpBufferSize);
652 if (lpNetIn->lpRemoteName)
654 lpNetOut->lpRemoteName = strNext;
655 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
656 -1, lpNetOut->lpRemoteName, *lpBufferSize);
658 if (lpNetIn->lpComment)
660 lpNetOut->lpComment = strNext;
661 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
662 -1, lpNetOut->lpComment, *lpBufferSize);
664 if (lpNetIn->lpProvider)
666 lpNetOut->lpProvider = strNext;
667 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
668 -1, lpNetOut->lpProvider, *lpBufferSize);
671 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
672 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
673 *lpcCount, ret);
674 return ret;
677 /*********************************************************************
678 * WNetOpenEnumA [MPR.@]
680 * See comments for WNetOpenEnumW.
682 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
683 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
685 DWORD ret;
687 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
688 dwScope, dwType, dwUsage, lpNet, lphEnum );
690 if (!lphEnum)
691 ret = WN_BAD_POINTER;
692 else if (!providerTable || providerTable->numProviders == 0)
694 *lphEnum = NULL;
695 ret = WN_NO_NETWORK;
697 else
699 if (lpNet)
701 LPNETRESOURCEW lpNetWide = NULL;
702 BYTE buf[1024];
703 DWORD size = sizeof(buf), count = 1;
704 BOOL allocated = FALSE;
706 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
707 if (ret == WN_MORE_DATA)
709 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
710 size);
711 if (lpNetWide)
713 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
714 &size);
715 allocated = TRUE;
717 else
718 ret = WN_OUT_OF_MEMORY;
720 else if (ret == WN_SUCCESS)
721 lpNetWide = (LPNETRESOURCEW)buf;
722 if (ret == WN_SUCCESS)
723 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
724 lphEnum);
725 if (allocated)
726 HeapFree(GetProcessHeap(), 0, lpNetWide);
728 else
729 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
731 if (ret)
732 SetLastError(ret);
733 TRACE("Returning %d\n", ret);
734 return ret;
737 /*********************************************************************
738 * WNetOpenEnumW [MPR.@]
740 * Network enumeration has way too many parameters, so I'm not positive I got
741 * them right. What I've got so far:
743 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
744 * all the network providers should be enumerated.
746 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
747 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
748 * lpProvider is set, all the network providers should be enumerated.
749 * (This means the enumeration is a list of network providers, not that the
750 * enumeration is passed on to the providers.)
752 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
753 * resource matches the "Entire Network" resource (no remote name, no
754 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
755 * enumeration is done on every network provider.
757 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
758 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
759 * only to the given network provider.
761 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
762 * no lpProvider is set, enumeration will be tried on every network provider,
763 * in the order in which they're loaded.
765 * - The LPNETRESOURCE should be disregarded for scopes besides
766 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
767 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
769 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
770 * resource in the enumerated list, as well as any machines in your
771 * workgroup. The machines in your workgroup come from doing a
772 * RESOURCE_CONTEXT enumeration of every Network Provider.
774 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
775 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
777 DWORD ret;
779 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
780 dwScope, dwType, dwUsage, lpNet, lphEnum );
782 if (!lphEnum)
783 ret = WN_BAD_POINTER;
784 else if (!providerTable || providerTable->numProviders == 0)
786 *lphEnum = NULL;
787 ret = WN_NO_NETWORK;
789 else
791 switch (dwScope)
793 case RESOURCE_GLOBALNET:
794 if (lpNet)
796 if (lpNet->lpProvider)
798 DWORD index = _findProviderIndexW(lpNet->lpProvider);
800 if (index != BAD_PROVIDER_INDEX)
802 if (providerTable->table[index].openEnum &&
803 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
805 HANDLE handle;
806 PWSTR RemoteName = lpNet->lpRemoteName;
808 if ((lpNet->dwUsage & RESOURCEUSAGE_CONTAINER) &&
809 RemoteName && !strcmpW(RemoteName, lpNet->lpProvider))
810 lpNet->lpRemoteName = NULL;
812 ret = providerTable->table[index].openEnum(
813 dwScope, dwType, dwUsage, lpNet, &handle);
814 if (ret == WN_SUCCESS)
816 *lphEnum = _createProviderEnumerator(
817 dwScope, dwType, dwUsage, index, handle);
818 ret = *lphEnum ? WN_SUCCESS :
819 WN_OUT_OF_MEMORY;
822 lpNet->lpRemoteName = RemoteName;
824 else
825 ret = WN_NOT_SUPPORTED;
827 else
828 ret = WN_BAD_PROVIDER;
830 else if (lpNet->lpRemoteName)
832 *lphEnum = _createGlobalEnumeratorW(dwScope,
833 dwType, dwUsage, lpNet);
834 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
836 else
838 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
839 providerTable->entireNetwork))
841 /* comment matches the "Entire Network", enumerate
842 * global scope of every provider
844 *lphEnum = _createGlobalEnumeratorW(dwScope,
845 dwType, dwUsage, lpNet);
847 else
849 /* this is the same as not having passed lpNet */
850 *lphEnum = _createGlobalEnumeratorW(dwScope,
851 dwType, dwUsage, NULL);
853 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
856 else
858 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
859 dwUsage, lpNet);
860 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
862 break;
863 case RESOURCE_CONTEXT:
864 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
865 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
866 break;
867 case RESOURCE_CONNECTED:
868 *lphEnum = _createConnectedEnumerator(dwScope, dwType, dwUsage);
869 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
870 break;
871 case RESOURCE_REMEMBERED:
873 HKEY remembered, user_profile;
875 ret = WN_OUT_OF_MEMORY;
876 if (RegOpenCurrentUser(KEY_READ, &user_profile) == ERROR_SUCCESS)
878 WCHAR subkey[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
880 if (RegOpenKeyExW(user_profile, subkey, 0, KEY_READ, &remembered) == ERROR_SUCCESS)
882 *lphEnum = _createRememberedEnumerator(dwScope, dwType, remembered);
883 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
886 RegCloseKey(user_profile);
889 break;
890 default:
891 WARN("unknown scope 0x%08x\n", dwScope);
892 ret = WN_BAD_VALUE;
895 if (ret)
896 SetLastError(ret);
897 TRACE("Returning %d\n", ret);
898 return ret;
901 /*********************************************************************
902 * WNetEnumResourceA [MPR.@]
904 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
905 LPVOID lpBuffer, LPDWORD lpBufferSize )
907 DWORD ret;
909 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
911 if (!hEnum)
912 ret = WN_BAD_POINTER;
913 else if (!lpcCount)
914 ret = WN_BAD_POINTER;
915 else if (!lpBuffer)
916 ret = WN_BAD_POINTER;
917 else if (!lpBufferSize)
918 ret = WN_BAD_POINTER;
919 else if (*lpBufferSize < sizeof(NETRESOURCEA))
921 *lpBufferSize = sizeof(NETRESOURCEA);
922 ret = WN_MORE_DATA;
924 else
926 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
927 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
929 if (localBuffer)
931 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
932 &localSize);
933 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
935 /* FIXME: this isn't necessarily going to work in the case of
936 * WN_MORE_DATA, because our enumerator may have moved on to
937 * the next provider. MSDN states that a large (16KB) buffer
938 * size is the appropriate usage of this function, so
939 * hopefully it won't be an issue.
941 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
942 lpBuffer, lpBufferSize);
943 *lpcCount = localCount;
945 HeapFree(GetProcessHeap(), 0, localBuffer);
947 else
948 ret = WN_OUT_OF_MEMORY;
950 if (ret)
951 SetLastError(ret);
952 TRACE("Returning %d\n", ret);
953 return ret;
956 static DWORD _countProviderBytesW(PWNetProvider provider)
958 DWORD ret;
960 if (provider)
962 ret = sizeof(NETRESOURCEW);
963 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
965 else
966 ret = 0;
967 return ret;
970 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
971 LPVOID lpBuffer, const DWORD *lpBufferSize)
973 DWORD ret;
975 if (!enumerator)
976 return WN_BAD_POINTER;
977 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
978 return WN_BAD_VALUE;
979 if (!lpcCount)
980 return WN_BAD_POINTER;
981 if (!lpBuffer)
982 return WN_BAD_POINTER;
983 if (!lpBufferSize)
984 return WN_BAD_POINTER;
985 if (*lpBufferSize < sizeof(NETRESOURCEA))
986 return WN_MORE_DATA;
988 if (!providerTable || enumerator->providerIndex >=
989 providerTable->numProviders)
990 ret = WN_NO_MORE_ENTRIES;
991 else
993 DWORD bytes = 0, count = 0, countLimit, i;
994 LPNETRESOURCEW resource;
995 LPWSTR strNext;
997 countLimit = *lpcCount == -1 ?
998 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
999 while (count < countLimit && bytes < *lpBufferSize)
1001 DWORD bytesNext = _countProviderBytesW(
1002 &providerTable->table[count + enumerator->providerIndex]);
1004 if (bytes + bytesNext < *lpBufferSize)
1006 bytes += bytesNext;
1007 count++;
1010 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
1011 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
1013 resource->dwScope = RESOURCE_GLOBALNET;
1014 resource->dwType = RESOURCETYPE_ANY;
1015 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
1016 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
1017 RESOURCEUSAGE_RESERVED;
1018 resource->lpLocalName = NULL;
1019 resource->lpRemoteName = strNext;
1020 strcpyW(resource->lpRemoteName,
1021 providerTable->table[i + enumerator->providerIndex].name);
1022 strNext += strlenW(resource->lpRemoteName) + 1;
1023 resource->lpComment = NULL;
1024 resource->lpProvider = strNext;
1025 strcpyW(resource->lpProvider,
1026 providerTable->table[i + enumerator->providerIndex].name);
1027 strNext += strlenW(resource->lpProvider) + 1;
1029 enumerator->providerIndex += count;
1030 *lpcCount = count;
1031 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
1033 TRACE("Returning %d\n", ret);
1034 return ret;
1037 /* Advances the enumerator (assumed to be a global enumerator) to the next
1038 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1039 * not open a handle with the next provider.
1040 * If the existing handle is NULL, may leave the enumerator unchanged, since
1041 * the current provider may support the desired scope.
1042 * If the existing handle is not NULL, closes it before moving on.
1043 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1044 * provider, and another error on failure.
1046 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
1048 if (!enumerator)
1049 return WN_BAD_POINTER;
1050 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1051 return WN_BAD_VALUE;
1052 if (!providerTable || enumerator->providerIndex >=
1053 providerTable->numProviders)
1054 return WN_NO_MORE_ENTRIES;
1056 if (enumerator->providerDone)
1058 DWORD dwEnum = 0;
1059 enumerator->providerDone = FALSE;
1060 if (enumerator->handle)
1062 providerTable->table[enumerator->providerIndex].closeEnum(
1063 enumerator->handle);
1064 enumerator->handle = NULL;
1065 enumerator->providerIndex++;
1067 if (enumerator->dwScope == RESOURCE_CONNECTED)
1068 dwEnum = WNNC_ENUM_LOCAL;
1069 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
1070 dwEnum = WNNC_ENUM_GLOBAL;
1071 else if (enumerator->dwScope == RESOURCE_CONTEXT)
1072 dwEnum = WNNC_ENUM_CONTEXT;
1073 for (; enumerator->providerIndex < providerTable->numProviders &&
1074 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
1075 & dwEnum); enumerator->providerIndex++)
1078 return enumerator->providerIndex < providerTable->numProviders ?
1079 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1082 /* "Passes through" call to the next provider that supports the enumeration
1083 * type.
1084 * FIXME: if one call to a provider's enumerator succeeds while there's still
1085 * space in lpBuffer, I don't call to the next provider. The caller may not
1086 * expect that it should call EnumResourceW again with a return value of
1087 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1088 * may have to be moved around a bit, ick.
1090 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1091 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1093 DWORD ret;
1095 if (!enumerator)
1096 return WN_BAD_POINTER;
1097 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1098 return WN_BAD_VALUE;
1099 if (!lpcCount)
1100 return WN_BAD_POINTER;
1101 if (!lpBuffer)
1102 return WN_BAD_POINTER;
1103 if (!lpBufferSize)
1104 return WN_BAD_POINTER;
1105 if (*lpBufferSize < sizeof(NETRESOURCEW))
1106 return WN_MORE_DATA;
1108 ret = _globalEnumeratorAdvance(enumerator);
1109 if (ret == WN_SUCCESS)
1111 ret = providerTable->table[enumerator->providerIndex].
1112 openEnum(enumerator->dwScope, enumerator->dwType,
1113 enumerator->dwUsage, enumerator->specific.net,
1114 &enumerator->handle);
1115 if (ret == WN_SUCCESS)
1117 ret = providerTable->table[enumerator->providerIndex].
1118 enumResource(enumerator->handle, lpcCount, lpBuffer,
1119 lpBufferSize);
1120 if (ret != WN_MORE_DATA)
1121 enumerator->providerDone = TRUE;
1124 TRACE("Returning %d\n", ret);
1125 return ret;
1128 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1129 LPVOID lpBuffer, LPDWORD lpBufferSize)
1131 DWORD ret;
1133 if (!enumerator)
1134 return WN_BAD_POINTER;
1135 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1136 return WN_BAD_VALUE;
1137 if (!lpcCount)
1138 return WN_BAD_POINTER;
1139 if (!lpBuffer)
1140 return WN_BAD_POINTER;
1141 if (!lpBufferSize)
1142 return WN_BAD_POINTER;
1143 if (*lpBufferSize < sizeof(NETRESOURCEW))
1144 return WN_MORE_DATA;
1145 if (!providerTable)
1146 return WN_NO_NETWORK;
1148 switch (enumerator->dwScope)
1150 case RESOURCE_GLOBALNET:
1151 if (enumerator->specific.net)
1152 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1153 lpBuffer, lpBufferSize);
1154 else
1155 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1156 lpBufferSize);
1157 break;
1158 case RESOURCE_CONTEXT:
1159 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1160 lpBufferSize);
1161 break;
1162 default:
1163 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1164 ret = WN_NO_MORE_ENTRIES;
1166 TRACE("Returning %d\n", ret);
1167 return ret;
1170 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1171 LPVOID lpBuffer, LPDWORD lpBufferSize)
1173 if (!enumerator)
1174 return WN_BAD_POINTER;
1175 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1176 return WN_BAD_VALUE;
1177 if (!enumerator->handle)
1178 return WN_BAD_VALUE;
1179 if (!lpcCount)
1180 return WN_BAD_POINTER;
1181 if (!lpBuffer)
1182 return WN_BAD_POINTER;
1183 if (!lpBufferSize)
1184 return WN_BAD_POINTER;
1185 if (!providerTable)
1186 return WN_NO_NETWORK;
1187 if (enumerator->providerIndex >= providerTable->numProviders)
1188 return WN_NO_MORE_ENTRIES;
1189 if (!providerTable->table[enumerator->providerIndex].enumResource)
1190 return WN_BAD_VALUE;
1191 return providerTable->table[enumerator->providerIndex].enumResource(
1192 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1195 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1196 LPVOID lpBuffer, LPDWORD lpBufferSize)
1198 DWORD ret;
1199 size_t cchEntireNetworkLen, bytesNeeded;
1201 if (!enumerator)
1202 return WN_BAD_POINTER;
1203 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1204 return WN_BAD_VALUE;
1205 if (!lpcCount)
1206 return WN_BAD_POINTER;
1207 if (!lpBuffer)
1208 return WN_BAD_POINTER;
1209 if (!lpBufferSize)
1210 return WN_BAD_POINTER;
1211 if (!providerTable)
1212 return WN_NO_NETWORK;
1214 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1215 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1216 if (*lpBufferSize < bytesNeeded)
1218 *lpBufferSize = bytesNeeded;
1219 ret = WN_MORE_DATA;
1221 else
1223 LPNETRESOURCEW lpNet = lpBuffer;
1225 lpNet->dwScope = RESOURCE_GLOBALNET;
1226 lpNet->dwType = enumerator->dwType;
1227 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1228 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1229 lpNet->lpLocalName = NULL;
1230 lpNet->lpRemoteName = NULL;
1231 lpNet->lpProvider = NULL;
1232 /* odd, but correct: put comment at end of buffer, so it won't get
1233 * overwritten by subsequent calls to a provider's enumResource
1235 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1236 (cchEntireNetworkLen * sizeof(WCHAR)));
1237 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1238 ret = WN_SUCCESS;
1240 if (ret == WN_SUCCESS)
1242 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1244 /* "Entire Network" entry enumerated--morph this into a global
1245 * enumerator. enumerator->lpNet continues to be NULL, since it has
1246 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1248 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1249 ret = _enumerateGlobalW(enumerator, lpcCount,
1250 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1251 if (ret == WN_SUCCESS)
1253 /* reflect the fact that we already enumerated "Entire Network" */
1254 (*lpcCount)++;
1255 *lpBufferSize = bufferSize + bytesNeeded;
1257 else
1259 /* the provider enumeration failed, but we already succeeded in
1260 * enumerating "Entire Network"--leave type as global to allow a
1261 * retry, but indicate success with a count of one.
1263 ret = WN_SUCCESS;
1264 *lpcCount = 1;
1265 *lpBufferSize = bytesNeeded;
1268 TRACE("Returning %d\n", ret);
1269 return ret;
1272 static DWORD _copyStringToEnumW(const WCHAR *source, DWORD* left, void** end)
1274 DWORD len;
1275 WCHAR* local = *end;
1277 len = strlenW(source) + 1;
1278 len *= sizeof(WCHAR);
1279 if (*left < len)
1280 return WN_MORE_DATA;
1282 local -= (len / sizeof(WCHAR));
1283 memcpy(local, source, len);
1284 *left -= len;
1285 *end = local;
1287 return WN_SUCCESS;
1290 static DWORD _enumerateConnectedW(PWNetEnumerator enumerator, DWORD* user_count,
1291 void* user_buffer, DWORD* user_size)
1293 DWORD ret, index, count, total_count, size, i, left;
1294 void* end;
1295 NETRESOURCEW* curr, * buffer;
1296 HANDLE* handles;
1298 if (!enumerator)
1299 return WN_BAD_POINTER;
1300 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONNECTED)
1301 return WN_BAD_VALUE;
1302 if (!user_count || !user_buffer || !user_size)
1303 return WN_BAD_POINTER;
1304 if (!providerTable)
1305 return WN_NO_NETWORK;
1307 handles = enumerator->specific.handles;
1308 left = *user_size;
1309 size = *user_size;
1310 buffer = HeapAlloc(GetProcessHeap(), 0, *user_size);
1311 if (!buffer)
1312 return WN_NO_NETWORK;
1314 curr = user_buffer;
1315 end = (char *)user_buffer + size;
1316 count = *user_count;
1317 total_count = 0;
1319 ret = WN_NO_MORE_ENTRIES;
1320 for (index = 0; index < providerTable->numProviders; index++)
1322 if (providerTable->table[index].dwEnumScopes)
1324 if (handles[index] == 0)
1326 ret = providerTable->table[index].openEnum(enumerator->dwScope,
1327 enumerator->dwType,
1328 enumerator->dwUsage,
1329 NULL, &handles[index]);
1330 if (ret != WN_SUCCESS)
1331 continue;
1334 ret = providerTable->table[index].enumResource(handles[index],
1335 &count, buffer,
1336 &size);
1337 total_count += count;
1338 if (ret == WN_MORE_DATA)
1339 break;
1341 if (ret == WN_SUCCESS)
1343 for (i = 0; i < count; ++i)
1345 if (left < sizeof(NETRESOURCEW))
1347 ret = WN_MORE_DATA;
1348 break;
1351 memcpy(curr, &buffer[i], sizeof(NETRESOURCEW));
1352 left -= sizeof(NETRESOURCEW);
1354 ret = _copyStringToEnumW(buffer[i].lpLocalName, &left, &end);
1355 if (ret == WN_MORE_DATA)
1356 break;
1357 curr->lpLocalName = end;
1359 ret = _copyStringToEnumW(buffer[i].lpRemoteName, &left, &end);
1360 if (ret == WN_MORE_DATA)
1361 break;
1362 curr->lpRemoteName = end;
1364 ret = _copyStringToEnumW(buffer[i].lpProvider, &left, &end);
1365 if (ret == WN_MORE_DATA)
1366 break;
1367 curr->lpProvider = end;
1369 ++curr;
1372 size = left;
1375 if (*user_count != -1)
1376 count = *user_count - total_count;
1377 else
1378 count = *user_count;
1382 if (total_count == 0)
1383 ret = WN_NO_MORE_ENTRIES;
1385 *user_count = total_count;
1386 if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
1387 ret = WN_SUCCESS;
1389 HeapFree(GetProcessHeap(), 0, buffer);
1391 TRACE("Returning %d\n", ret);
1392 return ret;
1395 static const WCHAR connectionType[] = { 'C','o','n','n','e','c','t','i','o','n','T','y','p','e',0 };
1396 static const WCHAR providerName[] = { 'P','r','o','v','i','d','e','r','N','a','m','e',0 };
1397 static const WCHAR remotePath[] = { 'R','e','m','o','t','e','P','a','t','h',0 };
1399 static WCHAR *get_reg_str(HKEY hkey, const WCHAR *value, DWORD *len)
1401 DWORD type;
1402 WCHAR *ret = NULL;
1404 if (!RegQueryValueExW(hkey, value, NULL, &type, NULL, len) && type == REG_SZ)
1406 if (!(ret = HeapAlloc(GetProcessHeap(), 0, *len))) return NULL;
1407 RegQueryValueExW(hkey, value, 0, 0, (BYTE *)ret, len);
1410 return ret;
1413 static DWORD _enumeratorRememberedW(PWNetEnumerator enumerator, DWORD* user_count,
1414 void* user_buffer, DWORD* user_size)
1416 HKEY registry, connection;
1417 WCHAR buffer[255];
1418 LONG size_left;
1419 DWORD index, ret, type, len, size, registry_size, full_size = 0, total_count;
1420 NETRESOURCEW * net_buffer = user_buffer;
1421 WCHAR * str, * registry_string;
1423 /* we will do the work in a single loop, so here is some things:
1424 * we write netresource at the begin of the user buffer
1425 * we write strings at the end of the user buffer
1427 size_left = *user_size;
1428 total_count = 0;
1429 type = enumerator->dwType;
1430 registry = enumerator->specific.remembered.registry;
1431 str = (WCHAR *)((ULONG_PTR)user_buffer + *user_size - sizeof(WCHAR));
1432 for (index = enumerator->specific.remembered.index; ; ++index)
1434 enumerator->specific.remembered.index = index;
1436 if (*user_count != -1 && total_count == *user_count)
1438 ret = WN_SUCCESS;
1439 break;
1442 len = ARRAY_SIZE(buffer);
1443 ret = RegEnumKeyExW(registry, index, buffer, &len, NULL, NULL, NULL, NULL);
1444 if (ret != ERROR_SUCCESS)
1446 if (ret == ERROR_NO_MORE_ITEMS) ret = WN_SUCCESS;
1447 break;
1450 if (RegOpenKeyExW(registry, buffer, 0, KEY_READ, &connection) != ERROR_SUCCESS)
1452 continue;
1455 full_size = sizeof(NETRESOURCEW);
1456 size_left -= sizeof(NETRESOURCEW);
1458 if (size_left > 0)
1460 size = sizeof(DWORD);
1461 RegQueryValueExW(connection, connectionType, NULL, NULL, (BYTE *)&net_buffer->dwType, &size);
1462 if (type != RESOURCETYPE_ANY && net_buffer->dwType != type)
1464 size_left += sizeof(NETRESOURCEW);
1465 RegCloseKey(connection);
1466 continue;
1469 net_buffer->dwScope = RESOURCE_REMEMBERED;
1470 net_buffer->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
1471 net_buffer->dwUsage = RESOURCEUSAGE_CONNECTABLE;
1473 else
1474 ret = WN_MORE_DATA;
1476 /* FIXME: this only supports drive letters */
1477 full_size += 3 * sizeof(WCHAR);
1478 size_left -= 3 * sizeof(WCHAR);
1479 if (size_left > 0)
1481 str -= 3;
1482 str[0] = buffer[0];
1483 str[1] = ':';
1484 str[2] = 0;
1485 net_buffer->lpLocalName = str;
1488 registry_size = 0;
1489 registry_string = get_reg_str(connection, providerName, &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->lpProvider = str;
1501 else
1502 ret = WN_MORE_DATA;
1504 HeapFree(GetProcessHeap(), 0, registry_string);
1507 registry_size = 0;
1508 registry_string = get_reg_str(connection, remotePath, &registry_size);
1509 if (registry_string)
1511 full_size += registry_size;
1512 size_left -= registry_size;
1514 if (size_left > 0)
1516 str -= (registry_size / sizeof(WCHAR));
1517 lstrcpyW(str, registry_string);
1518 net_buffer->lpRemoteName = str;
1520 else
1521 ret = WN_MORE_DATA;
1523 HeapFree(GetProcessHeap(), 0, registry_string);
1526 RegCloseKey(connection);
1528 net_buffer->lpComment = NULL;
1530 if (size_left < 0)
1531 break;
1533 ++total_count;
1534 ++net_buffer;
1537 if (total_count == 0)
1538 ret = WN_NO_MORE_ENTRIES;
1540 *user_count = total_count;
1542 if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
1543 ret = WN_SUCCESS;
1545 if (ret == WN_MORE_DATA)
1546 *user_size = *user_size + full_size;
1548 return ret;
1551 /*********************************************************************
1552 * WNetEnumResourceW [MPR.@]
1554 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1555 LPVOID lpBuffer, LPDWORD lpBufferSize )
1557 DWORD ret;
1559 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1561 if (!hEnum)
1562 ret = WN_BAD_POINTER;
1563 else if (!lpcCount)
1564 ret = WN_BAD_POINTER;
1565 else if (!lpBuffer)
1566 ret = WN_BAD_POINTER;
1567 else if (!lpBufferSize)
1568 ret = WN_BAD_POINTER;
1569 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1571 *lpBufferSize = sizeof(NETRESOURCEW);
1572 ret = WN_MORE_DATA;
1574 else
1576 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1578 switch (enumerator->enumType)
1580 case WNET_ENUMERATOR_TYPE_GLOBAL:
1581 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1582 lpBufferSize);
1583 break;
1584 case WNET_ENUMERATOR_TYPE_PROVIDER:
1585 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1586 lpBufferSize);
1587 break;
1588 case WNET_ENUMERATOR_TYPE_CONTEXT:
1589 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1590 lpBufferSize);
1591 break;
1592 case WNET_ENUMERATOR_TYPE_CONNECTED:
1593 ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer,
1594 lpBufferSize);
1595 break;
1596 case WNET_ENUMERATOR_TYPE_REMEMBERED:
1597 ret = _enumeratorRememberedW(enumerator, lpcCount, lpBuffer,
1598 lpBufferSize);
1599 break;
1600 default:
1601 WARN("bogus enumerator type!\n");
1602 ret = WN_NO_NETWORK;
1605 if (ret)
1606 SetLastError(ret);
1607 TRACE("Returning %d\n", ret);
1608 return ret;
1611 /*********************************************************************
1612 * WNetCloseEnum [MPR.@]
1614 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1616 DWORD ret, index;
1617 HANDLE *handles;
1619 TRACE( "(%p)\n", hEnum );
1621 if (hEnum)
1623 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1625 switch (enumerator->enumType)
1627 case WNET_ENUMERATOR_TYPE_GLOBAL:
1628 if (enumerator->specific.net)
1629 _freeEnumNetResource(enumerator->specific.net);
1630 if (enumerator->handle)
1631 providerTable->table[enumerator->providerIndex].
1632 closeEnum(enumerator->handle);
1633 ret = WN_SUCCESS;
1634 break;
1635 case WNET_ENUMERATOR_TYPE_PROVIDER:
1636 if (enumerator->handle)
1637 providerTable->table[enumerator->providerIndex].
1638 closeEnum(enumerator->handle);
1639 ret = WN_SUCCESS;
1640 break;
1641 case WNET_ENUMERATOR_TYPE_CONNECTED:
1642 handles = enumerator->specific.handles;
1643 for (index = 0; index < providerTable->numProviders; index++)
1645 if (providerTable->table[index].dwEnumScopes && handles[index])
1646 providerTable->table[index].closeEnum(handles[index]);
1648 HeapFree(GetProcessHeap(), 0, handles);
1649 ret = WN_SUCCESS;
1650 break;
1651 case WNET_ENUMERATOR_TYPE_REMEMBERED:
1652 RegCloseKey(enumerator->specific.remembered.registry);
1653 ret = WN_SUCCESS;
1654 break;
1655 default:
1656 WARN("bogus enumerator type!\n");
1657 ret = WN_BAD_HANDLE;
1659 HeapFree(GetProcessHeap(), 0, hEnum);
1661 else
1662 ret = WN_BAD_HANDLE;
1663 if (ret)
1664 SetLastError(ret);
1665 TRACE("Returning %d\n", ret);
1666 return ret;
1669 /*********************************************************************
1670 * WNetGetResourceInformationA [MPR.@]
1672 * See WNetGetResourceInformationW
1674 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1675 LPVOID lpBuffer, LPDWORD cbBuffer,
1676 LPSTR *lplpSystem )
1678 DWORD ret;
1680 TRACE( "(%p, %p, %p, %p)\n",
1681 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1683 if (!providerTable || providerTable->numProviders == 0)
1684 ret = WN_NO_NETWORK;
1685 else if (lpNetResource)
1687 LPNETRESOURCEW lpNetResourceW = NULL;
1688 DWORD size = 1024, count = 1;
1689 DWORD len;
1691 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1692 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1693 if (ret == WN_MORE_DATA)
1695 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1696 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1697 if (lpNetResourceW)
1698 ret = _thunkNetResourceArrayAToW(lpNetResource,
1699 &count, lpNetResourceW, &size);
1700 else
1701 ret = WN_OUT_OF_MEMORY;
1703 if (ret == WN_SUCCESS)
1705 LPWSTR lpSystemW = NULL;
1706 LPVOID lpBufferW;
1707 size = 1024;
1708 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1709 if (lpBufferW)
1711 ret = WNetGetResourceInformationW(lpNetResourceW,
1712 lpBufferW, &size, &lpSystemW);
1713 if (ret == WN_MORE_DATA)
1715 HeapFree(GetProcessHeap(), 0, lpBufferW);
1716 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1717 if (lpBufferW)
1718 ret = WNetGetResourceInformationW(lpNetResourceW,
1719 lpBufferW, &size, &lpSystemW);
1720 else
1721 ret = WN_OUT_OF_MEMORY;
1723 if (ret == WN_SUCCESS)
1725 ret = _thunkNetResourceArrayWToA(lpBufferW,
1726 &count, lpBuffer, cbBuffer);
1727 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1728 lpNetResourceW = lpBufferW;
1729 size = sizeof(NETRESOURCEA);
1730 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1731 -1, NULL, 0, NULL, NULL);
1732 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1733 -1, NULL, 0, NULL, NULL);
1735 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1736 -1, NULL, 0, NULL, NULL);
1737 if ((len) && ( size + len < *cbBuffer))
1739 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1740 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1741 *lplpSystem, len, NULL, NULL);
1742 ret = WN_SUCCESS;
1744 else
1745 ret = WN_MORE_DATA;
1747 else
1748 ret = WN_OUT_OF_MEMORY;
1749 HeapFree(GetProcessHeap(), 0, lpBufferW);
1751 else
1752 ret = WN_OUT_OF_MEMORY;
1753 HeapFree(GetProcessHeap(), 0, lpSystemW);
1755 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1757 else
1758 ret = WN_NO_NETWORK;
1760 if (ret)
1761 SetLastError(ret);
1762 TRACE("Returning %d\n", ret);
1763 return ret;
1766 /*********************************************************************
1767 * WNetGetResourceInformationW [MPR.@]
1769 * WNetGetResourceInformationW function identifies the network provider
1770 * that owns the resource and gets information about the type of the resource.
1772 * PARAMS:
1773 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1774 * defines a network resource.
1775 * lpBuffer [ O] the pointer to buffer, containing result. It
1776 * contains NETRESOURCEW structure and strings to
1777 * which the members of the NETRESOURCEW structure
1778 * point.
1779 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1780 * in bytes.
1781 * lplpSystem [ O] the pointer to string in the output buffer,
1782 * containing the part of the resource name without
1783 * names of the server and share.
1785 * RETURNS:
1786 * NO_ERROR if the function succeeds. System error code if the function fails.
1789 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1790 LPVOID lpBuffer, LPDWORD cbBuffer,
1791 LPWSTR *lplpSystem )
1793 DWORD ret = WN_NO_NETWORK;
1794 DWORD index;
1796 TRACE( "(%p, %p, %p, %p)\n",
1797 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1799 if (!(lpBuffer))
1800 ret = WN_OUT_OF_MEMORY;
1801 else if (providerTable != NULL)
1803 /* FIXME: For function value of a variable is indifferent, it does
1804 * search of all providers in a network.
1806 for (index = 0; index < providerTable->numProviders; index++)
1808 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1809 WNNC_DLG_GETRESOURCEINFORMATION)
1811 if (providerTable->table[index].getResourceInformation)
1812 ret = providerTable->table[index].getResourceInformation(
1813 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1814 else
1815 ret = WN_NO_NETWORK;
1816 if (ret == WN_SUCCESS)
1817 break;
1821 if (ret)
1822 SetLastError(ret);
1823 return ret;
1826 /*********************************************************************
1827 * WNetGetResourceParentA [MPR.@]
1829 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1830 LPVOID lpBuffer, LPDWORD lpBufferSize )
1832 FIXME( "(%p, %p, %p): stub\n",
1833 lpNetResource, lpBuffer, lpBufferSize );
1835 SetLastError(WN_NO_NETWORK);
1836 return WN_NO_NETWORK;
1839 /*********************************************************************
1840 * WNetGetResourceParentW [MPR.@]
1842 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1843 LPVOID lpBuffer, LPDWORD lpBufferSize )
1845 FIXME( "(%p, %p, %p): stub\n",
1846 lpNetResource, lpBuffer, lpBufferSize );
1848 SetLastError(WN_NO_NETWORK);
1849 return WN_NO_NETWORK;
1855 * Connection Functions
1858 /*********************************************************************
1859 * WNetAddConnectionA [MPR.@]
1861 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1862 LPCSTR lpLocalName )
1864 NETRESOURCEA resourcesA;
1866 memset(&resourcesA, 0, sizeof(resourcesA));
1867 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1868 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1869 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1872 /*********************************************************************
1873 * WNetAddConnectionW [MPR.@]
1875 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1876 LPCWSTR lpLocalName )
1878 NETRESOURCEW resourcesW;
1880 memset(&resourcesW, 0, sizeof(resourcesW));
1881 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1882 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1883 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1886 /*********************************************************************
1887 * WNetAddConnection2A [MPR.@]
1889 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1890 LPCSTR lpPassword, LPCSTR lpUserID,
1891 DWORD dwFlags )
1893 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1894 NULL, 0, NULL);
1897 /*********************************************************************
1898 * WNetAddConnection2W [MPR.@]
1900 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1901 LPCWSTR lpPassword, LPCWSTR lpUserID,
1902 DWORD dwFlags )
1904 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1905 NULL, 0, NULL);
1908 /*********************************************************************
1909 * WNetAddConnection3A [MPR.@]
1911 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1912 LPCSTR lpPassword, LPCSTR lpUserID,
1913 DWORD dwFlags )
1915 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1916 dwFlags, NULL, 0, NULL);
1919 /*********************************************************************
1920 * WNetAddConnection3W [MPR.@]
1922 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1923 LPCWSTR lpPassword, LPCWSTR lpUserID,
1924 DWORD dwFlags )
1926 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1927 dwFlags, NULL, 0, NULL);
1930 struct use_connection_context
1932 HWND hwndOwner;
1933 NETRESOURCEW *resource;
1934 NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */
1935 WCHAR *password;
1936 WCHAR *userid;
1937 DWORD flags;
1938 void *accessname;
1939 DWORD *buffer_size;
1940 DWORD *result;
1941 DWORD (*pre_set_accessname)(struct use_connection_context*, WCHAR *);
1942 void (*set_accessname)(struct use_connection_context*, WCHAR *);
1945 static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1947 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1949 DWORD len;
1951 if (local_name)
1952 len = strlenW(local_name);
1953 else
1954 len = strlenW(ctxt->resource->lpRemoteName);
1956 if (++len > *ctxt->buffer_size)
1958 *ctxt->buffer_size = len;
1959 return ERROR_MORE_DATA;
1962 else
1963 ctxt->accessname = NULL;
1965 return ERROR_SUCCESS;
1968 static void use_connection_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1970 WCHAR *accessname = ctxt->accessname;
1971 if (local_name)
1973 strcpyW(accessname, local_name);
1974 if (ctxt->result)
1975 *ctxt->result = CONNECT_LOCALDRIVE;
1977 else
1978 strcpyW(accessname, ctxt->resource->lpRemoteName);
1981 static DWORD wnet_use_provider( struct use_connection_context *ctxt, NETRESOURCEW * netres, WNetProvider *provider, BOOLEAN redirect )
1983 DWORD caps, ret;
1985 caps = provider->getCaps(WNNC_CONNECTION);
1986 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1987 return ERROR_BAD_PROVIDER;
1989 ret = WN_ACCESS_DENIED;
1992 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1993 ret = provider->addConnection3(ctxt->hwndOwner, netres, ctxt->password, ctxt->userid, ctxt->flags);
1994 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1995 ret = provider->addConnection(netres, ctxt->password, ctxt->userid);
1997 if (ret == WN_ALREADY_CONNECTED && redirect)
1998 netres->lpLocalName[0] -= 1;
1999 } while (redirect && ret == WN_ALREADY_CONNECTED && netres->lpLocalName[0] >= 'C');
2001 if (ret == WN_SUCCESS && ctxt->accessname)
2002 ctxt->set_accessname(ctxt, netres->lpLocalName);
2004 return ret;
2007 static const WCHAR providerType[] = { 'P','r','o','v','i','d','e','r','T','y','p','e',0 };
2008 static const WCHAR userName[] = { 'U','s','e','r','N','a','m','e',0 };
2010 static DWORD wnet_use_connection( struct use_connection_context *ctxt )
2012 WNetProvider *provider = NULL;
2013 DWORD index, ret = WN_NO_NETWORK;
2014 BOOL redirect = FALSE;
2015 WCHAR letter[3] = {'Z', ':', 0};
2016 NETRESOURCEW netres;
2018 if (!providerTable || providerTable->numProviders == 0)
2019 return WN_NO_NETWORK;
2021 if (!ctxt->resource)
2022 return ERROR_INVALID_PARAMETER;
2023 netres = *ctxt->resource;
2025 if (!netres.lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
2027 if (netres.dwType != RESOURCETYPE_DISK && netres.dwType != RESOURCETYPE_PRINT)
2028 return ERROR_BAD_DEV_TYPE;
2030 if (netres.dwType == RESOURCETYPE_PRINT)
2032 FIXME("Local device selection is not implemented for printers.\n");
2033 return WN_NO_NETWORK;
2036 redirect = TRUE;
2037 netres.lpLocalName = letter;
2040 if (ctxt->flags & CONNECT_INTERACTIVE)
2041 return ERROR_BAD_NET_NAME;
2043 if ((ret = ctxt->pre_set_accessname(ctxt, netres.lpLocalName)))
2044 return ret;
2046 if (netres.lpProvider)
2048 index = _findProviderIndexW(netres.lpProvider);
2049 if (index == BAD_PROVIDER_INDEX)
2050 return ERROR_BAD_PROVIDER;
2052 provider = &providerTable->table[index];
2053 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
2055 else
2057 for (index = 0; index < providerTable->numProviders; index++)
2059 provider = &providerTable->table[index];
2060 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
2061 if (ret == WN_SUCCESS || ret == WN_ALREADY_CONNECTED)
2062 break;
2066 if (ret == WN_SUCCESS && ctxt->flags & CONNECT_UPDATE_PROFILE)
2068 HKEY user_profile;
2070 if (netres.dwType == RESOURCETYPE_PRINT)
2072 FIXME("Persistent connection are not supported for printers\n");
2073 return ret;
2076 if (RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
2078 HKEY network;
2079 WCHAR subkey[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres.lpLocalName[0], 0};
2081 if (RegCreateKeyExW(user_profile, subkey, 0, NULL, REG_OPTION_NON_VOLATILE,
2082 KEY_ALL_ACCESS, NULL, &network, NULL) == ERROR_SUCCESS)
2084 DWORD dword_arg = RESOURCETYPE_DISK;
2085 DWORD len = (strlenW(provider->name) + 1) * sizeof(WCHAR);
2086 static const WCHAR empty[1] = {0};
2088 RegSetValueExW(network, connectionType, 0, REG_DWORD, (const BYTE *)&dword_arg, sizeof(DWORD));
2089 RegSetValueExW(network, providerName, 0, REG_SZ, (const BYTE *)provider->name, len);
2090 RegSetValueExW(network, providerType, 0, REG_DWORD, (const BYTE *)&provider->dwNetType, sizeof(DWORD));
2091 len = (strlenW(netres.lpRemoteName) + 1) * sizeof(WCHAR);
2092 RegSetValueExW(network, remotePath, 0, REG_SZ, (const BYTE *)netres.lpRemoteName, len);
2093 len = sizeof(empty);
2094 RegSetValueExW(network, userName, 0, REG_SZ, (const BYTE *)empty, len);
2095 RegCloseKey(network);
2098 RegCloseKey(user_profile);
2102 return ret;
2105 /*****************************************************************
2106 * WNetUseConnectionW [MPR.@]
2108 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
2109 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
2111 struct use_connection_context ctxt;
2113 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
2114 hwndOwner, resource, password, debugstr_w(userid), flags,
2115 accessname, buffer_size, result );
2117 ctxt.hwndOwner = hwndOwner;
2118 ctxt.resource = resource;
2119 ctxt.resourceA = NULL;
2120 ctxt.password = (WCHAR*)password;
2121 ctxt.userid = (WCHAR*)userid;
2122 ctxt.flags = flags;
2123 ctxt.accessname = accessname;
2124 ctxt.buffer_size = buffer_size;
2125 ctxt.result = result;
2126 ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
2127 ctxt.set_accessname = use_connection_set_accessnameW;
2129 return wnet_use_connection(&ctxt);
2132 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
2134 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
2136 DWORD len;
2138 if (local_name)
2139 len = WideCharToMultiByte(CP_ACP, 0, local_name, -1, NULL, 0, NULL, NULL) - 1;
2140 else
2141 len = strlen(ctxt->resourceA->lpRemoteName);
2143 if (++len > *ctxt->buffer_size)
2145 *ctxt->buffer_size = len;
2146 return ERROR_MORE_DATA;
2149 else
2150 ctxt->accessname = NULL;
2152 return ERROR_SUCCESS;
2155 static void use_connection_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
2157 char *accessname = ctxt->accessname;
2158 if (local_name)
2160 WideCharToMultiByte(CP_ACP, 0, local_name, -1, accessname, *ctxt->buffer_size, NULL, NULL);
2161 if (ctxt->result)
2162 *ctxt->result = CONNECT_LOCALDRIVE;
2164 else
2165 strcpy(accessname, ctxt->resourceA->lpRemoteName);
2168 static LPWSTR strdupAtoW( LPCSTR str )
2170 LPWSTR ret;
2171 INT len;
2173 if (!str) return NULL;
2174 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
2175 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2176 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
2177 return ret;
2180 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
2182 resourceW->dwScope = resourceA->dwScope;
2183 resourceW->dwType = resourceA->dwType;
2184 resourceW->dwDisplayType = resourceA->dwDisplayType;
2185 resourceW->dwUsage = resourceA->dwUsage;
2186 resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
2187 resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
2188 resourceW->lpComment = strdupAtoW(resourceA->lpComment);
2189 resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
2192 static void free_netresourceW( NETRESOURCEW *resource )
2194 HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
2195 HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
2196 HeapFree(GetProcessHeap(), 0, resource->lpComment);
2197 HeapFree(GetProcessHeap(), 0, resource->lpProvider);
2200 /*****************************************************************
2201 * WNetUseConnectionA [MPR.@]
2203 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
2204 LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
2205 DWORD *buffer_size, DWORD *result )
2207 struct use_connection_context ctxt;
2208 NETRESOURCEW resourceW;
2209 DWORD ret;
2211 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
2212 accessname, buffer_size, result );
2214 netresource_a_to_w(resource, &resourceW);
2216 ctxt.hwndOwner = hwndOwner;
2217 ctxt.resource = &resourceW;
2218 ctxt.resourceA = resource;
2219 ctxt.password = strdupAtoW(password);
2220 ctxt.userid = strdupAtoW(userid);
2221 ctxt.flags = flags;
2222 ctxt.accessname = accessname;
2223 ctxt.buffer_size = buffer_size;
2224 ctxt.result = result;
2225 ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
2226 ctxt.set_accessname = use_connection_set_accessnameA;
2228 ret = wnet_use_connection(&ctxt);
2230 free_netresourceW(&resourceW);
2231 HeapFree(GetProcessHeap(), 0, ctxt.password);
2232 HeapFree(GetProcessHeap(), 0, ctxt.userid);
2234 return ret;
2237 /*********************************************************************
2238 * WNetCancelConnectionA [MPR.@]
2240 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
2242 return WNetCancelConnection2A(lpName, 0, fForce);
2245 /*********************************************************************
2246 * WNetCancelConnectionW [MPR.@]
2248 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
2250 return WNetCancelConnection2W(lpName, 0, fForce);
2253 /*********************************************************************
2254 * WNetCancelConnection2A [MPR.@]
2256 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
2258 DWORD ret;
2259 WCHAR * name = strdupAtoW(lpName);
2260 if (!name)
2261 return ERROR_NOT_CONNECTED;
2263 ret = WNetCancelConnection2W(name, dwFlags, fForce);
2264 HeapFree(GetProcessHeap(), 0, name);
2266 return ret;
2269 /*********************************************************************
2270 * WNetCancelConnection2W [MPR.@]
2272 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
2274 DWORD ret = WN_NO_NETWORK;
2275 DWORD index;
2277 if (providerTable != NULL)
2279 for (index = 0; index < providerTable->numProviders; index++)
2281 if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2282 WNNC_CON_CANCELCONNECTION)
2284 if (providerTable->table[index].cancelConnection)
2285 ret = providerTable->table[index].cancelConnection((LPWSTR)lpName, fForce);
2286 else
2287 ret = WN_NO_NETWORK;
2288 if (ret == WN_SUCCESS || ret == WN_OPEN_FILES)
2289 break;
2294 if (ret == WN_SUCCESS && dwFlags & CONNECT_UPDATE_PROFILE)
2296 HKEY user_profile;
2298 /* FIXME: Only remove it if that's a drive letter */
2299 if (isalphaW(lpName[0]) && lpName[1] == ':' &&
2300 RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
2302 WCHAR subkey[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', lpName[0], 0};
2304 RegDeleteKeyW(user_profile, subkey);
2306 RegCloseKey(user_profile);
2310 return ret;
2313 /*****************************************************************
2314 * WNetRestoreConnectionA [MPR.@]
2316 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
2318 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
2320 SetLastError(WN_NO_NETWORK);
2321 return WN_NO_NETWORK;
2324 /*****************************************************************
2325 * WNetRestoreConnectionW [MPR.@]
2327 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
2329 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
2331 SetLastError(WN_NO_NETWORK);
2332 return WN_NO_NETWORK;
2335 /**************************************************************************
2336 * WNetGetConnectionA [MPR.@]
2338 * RETURNS
2339 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2340 * - WN_NOT_CONNECTED drive is a local drive
2341 * - WN_MORE_DATA buffer isn't big enough
2342 * - WN_SUCCESS success (net path in buffer)
2344 * FIXME: need to test return values under different errors
2346 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
2347 LPSTR lpRemoteName, LPDWORD lpBufferSize )
2349 DWORD ret;
2351 if (!lpLocalName)
2352 ret = WN_BAD_POINTER;
2353 else if (!lpBufferSize)
2354 ret = WN_BAD_POINTER;
2355 else if (!lpRemoteName && *lpBufferSize)
2356 ret = WN_BAD_POINTER;
2357 else
2359 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
2361 if (len)
2363 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2365 if (wideLocalName)
2367 WCHAR wideRemoteStatic[MAX_PATH];
2368 DWORD wideRemoteSize = ARRAY_SIZE(wideRemoteStatic);
2370 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
2372 /* try once without memory allocation */
2373 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
2374 &wideRemoteSize);
2375 if (ret == WN_SUCCESS)
2377 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2378 -1, NULL, 0, NULL, NULL);
2380 if (len <= *lpBufferSize)
2382 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
2383 lpRemoteName, *lpBufferSize, NULL, NULL);
2384 ret = WN_SUCCESS;
2386 else
2388 *lpBufferSize = len;
2389 ret = WN_MORE_DATA;
2392 else if (ret == WN_MORE_DATA)
2394 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
2395 wideRemoteSize * sizeof(WCHAR));
2397 if (wideRemote)
2399 ret = WNetGetConnectionW(wideLocalName, wideRemote,
2400 &wideRemoteSize);
2401 if (ret == WN_SUCCESS)
2403 if (len <= *lpBufferSize)
2405 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2406 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
2407 ret = WN_SUCCESS;
2409 else
2411 *lpBufferSize = len;
2412 ret = WN_MORE_DATA;
2415 HeapFree(GetProcessHeap(), 0, wideRemote);
2417 else
2418 ret = WN_OUT_OF_MEMORY;
2420 HeapFree(GetProcessHeap(), 0, wideLocalName);
2422 else
2423 ret = WN_OUT_OF_MEMORY;
2425 else
2426 ret = WN_BAD_LOCALNAME;
2428 if (ret)
2429 SetLastError(ret);
2430 TRACE("Returning %d\n", ret);
2431 return ret;
2434 /* find the network connection for a given drive; helper for WNetGetConnection */
2435 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
2437 char buffer[1024];
2438 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
2439 HANDLE mgr;
2440 DWORD ret = WN_NOT_CONNECTED;
2441 DWORD bytes_returned;
2443 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
2444 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
2445 0, 0 )) == INVALID_HANDLE_VALUE)
2447 ERR( "failed to open mount manager err %u\n", GetLastError() );
2448 return ret;
2450 memset( data, 0, sizeof(*data) );
2451 data->letter = letter;
2452 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
2453 data, sizeof(buffer), &bytes_returned, NULL ))
2455 char *p, *mount_point = buffer + data->mount_point_offset;
2456 DWORD len;
2458 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
2460 mount_point += 2;
2461 mount_point[0] = '\\';
2462 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
2464 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
2465 if (len > *size)
2467 *size = len;
2468 ret = WN_MORE_DATA;
2470 else
2472 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
2473 ret = WN_SUCCESS;
2477 CloseHandle( mgr );
2478 return ret;
2481 /**************************************************************************
2482 * WNetGetConnectionW [MPR.@]
2484 * FIXME: need to test return values under different errors
2486 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
2487 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
2489 DWORD ret;
2491 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
2492 lpBufferSize);
2494 if (!lpLocalName)
2495 ret = WN_BAD_POINTER;
2496 else if (!lpBufferSize)
2497 ret = WN_BAD_POINTER;
2498 else if (!lpRemoteName && *lpBufferSize)
2499 ret = WN_BAD_POINTER;
2500 else if (!lpLocalName[0])
2501 ret = WN_BAD_LOCALNAME;
2502 else
2504 if (lpLocalName[1] == ':')
2506 switch(GetDriveTypeW(lpLocalName))
2508 case DRIVE_REMOTE:
2509 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
2510 break;
2511 case DRIVE_REMOVABLE:
2512 case DRIVE_FIXED:
2513 case DRIVE_CDROM:
2514 TRACE("file is local\n");
2515 ret = WN_NOT_CONNECTED;
2516 break;
2517 default:
2518 ret = WN_BAD_LOCALNAME;
2521 else
2522 ret = WN_BAD_LOCALNAME;
2524 if (ret)
2525 SetLastError(ret);
2526 TRACE("Returning %d\n", ret);
2527 return ret;
2530 /**************************************************************************
2531 * WNetSetConnectionA [MPR.@]
2533 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
2534 LPVOID pvValue )
2536 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
2538 SetLastError(WN_NO_NETWORK);
2539 return WN_NO_NETWORK;
2542 /**************************************************************************
2543 * WNetSetConnectionW [MPR.@]
2545 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2546 LPVOID pvValue )
2548 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2550 SetLastError(WN_NO_NETWORK);
2551 return WN_NO_NETWORK;
2554 /*****************************************************************
2555 * WNetGetUniversalNameA [MPR.@]
2557 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2558 LPVOID lpBuffer, LPDWORD lpBufferSize )
2560 DWORD err, size;
2562 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2563 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2565 switch (dwInfoLevel)
2567 case UNIVERSAL_NAME_INFO_LEVEL:
2569 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2571 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2573 err = ERROR_NOT_CONNECTED;
2574 break;
2577 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2578 if (*lpBufferSize < size)
2580 err = WN_MORE_DATA;
2581 break;
2583 info->lpUniversalName = (char *)info + sizeof(*info);
2584 lstrcpyA(info->lpUniversalName, lpLocalPath);
2585 err = WN_NO_ERROR;
2586 break;
2588 case REMOTE_NAME_INFO_LEVEL:
2589 err = WN_NOT_CONNECTED;
2590 break;
2592 default:
2593 err = WN_BAD_VALUE;
2594 break;
2597 SetLastError(err);
2598 return err;
2601 /*****************************************************************
2602 * WNetGetUniversalNameW [MPR.@]
2604 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2605 LPVOID lpBuffer, LPDWORD lpBufferSize )
2607 DWORD err, size;
2609 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2610 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2612 switch (dwInfoLevel)
2614 case UNIVERSAL_NAME_INFO_LEVEL:
2616 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2618 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2620 err = ERROR_NOT_CONNECTED;
2621 break;
2624 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2625 if (*lpBufferSize < size)
2627 *lpBufferSize = size;
2628 err = WN_MORE_DATA;
2629 break;
2631 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2632 lstrcpyW(info->lpUniversalName, lpLocalPath);
2633 err = WN_NO_ERROR;
2634 break;
2636 case REMOTE_NAME_INFO_LEVEL:
2637 err = WN_NO_NETWORK;
2638 break;
2640 default:
2641 err = WN_BAD_VALUE;
2642 break;
2645 if (err != WN_NO_ERROR) SetLastError(err);
2646 return err;
2649 /*****************************************************************
2650 * WNetClearConnections [MPR.@]
2652 DWORD WINAPI WNetClearConnections ( HWND owner )
2654 HANDLE connected;
2655 PWSTR connection;
2656 DWORD ret, size, count;
2657 NETRESOURCEW * resources, * iter;
2659 ret = WNetOpenEnumW(RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL, &connected);
2660 if (ret != WN_SUCCESS)
2662 if (ret != WN_NO_NETWORK)
2664 return ret;
2667 /* Means no provider, then, clearing is OK */
2668 return WN_SUCCESS;
2671 size = 0x1000;
2672 resources = HeapAlloc(GetProcessHeap(), 0, size);
2673 if (!resources)
2675 WNetCloseEnum(connected);
2676 return WN_OUT_OF_MEMORY;
2679 for (;;)
2681 size = 0x1000;
2682 count = -1;
2684 memset(resources, 0, size);
2685 ret = WNetEnumResourceW(connected, &count, resources, &size);
2686 if (ret == WN_SUCCESS || ret == WN_MORE_DATA)
2688 for (iter = resources; count; count--, iter++)
2690 if (iter->lpLocalName && iter->lpLocalName[0])
2691 connection = iter->lpLocalName;
2692 else
2693 connection = iter->lpRemoteName;
2695 WNetCancelConnection2W(connection, 0, TRUE);
2698 else
2699 break;
2702 HeapFree(GetProcessHeap(), 0, resources);
2703 WNetCloseEnum(connected);
2705 return ret;
2710 * Other Functions
2713 /**************************************************************************
2714 * WNetGetUserA [MPR.@]
2716 * FIXME: we should not return ourselves, but the owner of the drive lpName
2718 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2720 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2721 return GetLastError();
2724 /*****************************************************************
2725 * WNetGetUserW [MPR.@]
2727 * FIXME: we should not return ourselves, but the owner of the drive lpName
2729 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2731 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2732 return GetLastError();
2735 /*********************************************************************
2736 * WNetConnectionDialog [MPR.@]
2738 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2740 CONNECTDLGSTRUCTW conn_dlg;
2741 NETRESOURCEW net_res;
2743 ZeroMemory(&conn_dlg, sizeof(conn_dlg));
2744 ZeroMemory(&net_res, sizeof(net_res));
2746 conn_dlg.cbStructure = sizeof(conn_dlg);
2747 conn_dlg.lpConnRes = &net_res;
2748 conn_dlg.hwndOwner = hwnd;
2749 net_res.dwType = dwType;
2751 return WNetConnectionDialog1W(&conn_dlg);
2754 /*********************************************************************
2755 * WNetConnectionDialog1A [MPR.@]
2757 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2759 FIXME( "(%p): stub\n", lpConnDlgStruct );
2761 SetLastError(WN_NO_NETWORK);
2762 return WN_NO_NETWORK;
2765 /*********************************************************************
2766 * WNetConnectionDialog1W [MPR.@]
2768 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2770 FIXME( "(%p): stub\n", lpConnDlgStruct );
2772 SetLastError(WN_NO_NETWORK);
2773 return WN_NO_NETWORK;
2776 /*********************************************************************
2777 * WNetDisconnectDialog [MPR.@]
2779 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2781 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2783 SetLastError(WN_NO_NETWORK);
2784 return WN_NO_NETWORK;
2787 /*********************************************************************
2788 * WNetDisconnectDialog1A [MPR.@]
2790 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2792 FIXME( "(%p): stub\n", lpConnDlgStruct );
2794 SetLastError(WN_NO_NETWORK);
2795 return WN_NO_NETWORK;
2798 /*********************************************************************
2799 * WNetDisconnectDialog1W [MPR.@]
2801 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2803 FIXME( "(%p): stub\n", lpConnDlgStruct );
2805 SetLastError(WN_NO_NETWORK);
2806 return WN_NO_NETWORK;
2809 /*********************************************************************
2810 * WNetGetLastErrorA [MPR.@]
2812 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2813 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2814 LPSTR lpNameBuf, DWORD nNameBufSize )
2816 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2817 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2819 SetLastError(WN_NO_NETWORK);
2820 return WN_NO_NETWORK;
2823 /*********************************************************************
2824 * WNetGetLastErrorW [MPR.@]
2826 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2827 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2828 LPWSTR lpNameBuf, DWORD nNameBufSize )
2830 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2831 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2833 SetLastError(WN_NO_NETWORK);
2834 return WN_NO_NETWORK;
2837 /*********************************************************************
2838 * WNetGetNetworkInformationA [MPR.@]
2840 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2841 LPNETINFOSTRUCT lpNetInfoStruct )
2843 DWORD ret;
2845 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2847 if (!lpProvider)
2848 ret = WN_BAD_POINTER;
2849 else
2851 int len;
2853 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2854 if (len)
2856 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2858 if (wideProvider)
2860 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2861 len);
2862 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2863 HeapFree(GetProcessHeap(), 0, wideProvider);
2865 else
2866 ret = WN_OUT_OF_MEMORY;
2868 else
2869 ret = GetLastError();
2871 if (ret)
2872 SetLastError(ret);
2873 TRACE("Returning %d\n", ret);
2874 return ret;
2877 /*********************************************************************
2878 * WNetGetNetworkInformationW [MPR.@]
2880 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2881 LPNETINFOSTRUCT lpNetInfoStruct )
2883 DWORD ret;
2885 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2887 if (!lpProvider)
2888 ret = WN_BAD_POINTER;
2889 else if (!lpNetInfoStruct)
2890 ret = WN_BAD_POINTER;
2891 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2892 ret = WN_BAD_VALUE;
2893 else
2895 if (providerTable && providerTable->numProviders)
2897 DWORD providerIndex = _findProviderIndexW(lpProvider);
2899 if (providerIndex != BAD_PROVIDER_INDEX)
2901 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2902 lpNetInfoStruct->dwProviderVersion =
2903 providerTable->table[providerIndex].dwSpecVersion;
2904 lpNetInfoStruct->dwStatus = NO_ERROR;
2905 lpNetInfoStruct->dwCharacteristics = 0;
2906 lpNetInfoStruct->dwHandle = 0;
2907 lpNetInfoStruct->wNetType =
2908 HIWORD(providerTable->table[providerIndex].dwNetType);
2909 lpNetInfoStruct->dwPrinters = -1;
2910 lpNetInfoStruct->dwDrives = -1;
2911 ret = WN_SUCCESS;
2913 else
2914 ret = WN_BAD_PROVIDER;
2916 else
2917 ret = WN_NO_NETWORK;
2919 if (ret)
2920 SetLastError(ret);
2921 TRACE("Returning %d\n", ret);
2922 return ret;
2925 /*****************************************************************
2926 * WNetGetProviderNameA [MPR.@]
2928 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2929 LPSTR lpProvider, LPDWORD lpBufferSize )
2931 DWORD ret;
2933 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2934 lpBufferSize);
2936 if (!lpProvider)
2937 ret = WN_BAD_POINTER;
2938 else if (!lpBufferSize)
2939 ret = WN_BAD_POINTER;
2940 else
2942 if (providerTable)
2944 DWORD i;
2946 ret = WN_NO_NETWORK;
2947 for (i = 0; i < providerTable->numProviders &&
2948 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2949 i++)
2951 if (i < providerTable->numProviders)
2953 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2954 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2956 if (*lpBufferSize < sizeNeeded)
2958 *lpBufferSize = sizeNeeded;
2959 ret = WN_MORE_DATA;
2961 else
2963 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2964 -1, lpProvider, *lpBufferSize, NULL, NULL);
2965 ret = WN_SUCCESS;
2966 /* FIXME: is *lpBufferSize set to the number of characters
2967 * copied? */
2971 else
2972 ret = WN_NO_NETWORK;
2974 if (ret)
2975 SetLastError(ret);
2976 TRACE("Returning %d\n", ret);
2977 return ret;
2980 /*****************************************************************
2981 * WNetGetProviderNameW [MPR.@]
2983 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2984 LPWSTR lpProvider, LPDWORD lpBufferSize )
2986 DWORD ret;
2988 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2989 lpBufferSize);
2991 if (!lpProvider)
2992 ret = WN_BAD_POINTER;
2993 else if (!lpBufferSize)
2994 ret = WN_BAD_POINTER;
2995 else
2997 if (providerTable)
2999 DWORD i;
3001 ret = WN_NO_NETWORK;
3002 for (i = 0; i < providerTable->numProviders &&
3003 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
3004 i++)
3006 if (i < providerTable->numProviders)
3008 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
3010 if (*lpBufferSize < sizeNeeded)
3012 *lpBufferSize = sizeNeeded;
3013 ret = WN_MORE_DATA;
3015 else
3017 strcpyW(lpProvider, providerTable->table[i].name);
3018 ret = WN_SUCCESS;
3019 /* FIXME: is *lpBufferSize set to the number of characters
3020 * copied? */
3024 else
3025 ret = WN_NO_NETWORK;
3027 if (ret)
3028 SetLastError(ret);
3029 TRACE("Returning %d\n", ret);
3030 return ret;