mpr: Set the CONNECT_LOCALDRIVE flag in case a local redirection is made on connection.
[wine.git] / dlls / mpr / wnet.c
blob85dfca1287d5d2747f2af1db7db6200db523b397
1 /*
2 * MPR WNet functions
4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winnls.h"
27 #include "winioctl.h"
28 #include "winnetwk.h"
29 #include "npapi.h"
30 #include "winreg.h"
31 #include "winuser.h"
32 #define WINE_MOUNTMGR_EXTENSIONS
33 #include "ddk/mountmgr.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.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_NULL 0
73 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
74 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
75 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
77 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
78 * the enumeration; it represents one of the following types:
79 * - a 'null' enumeration, one that contains no members
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).
91 typedef struct _WNetEnumerator
93 DWORD enumType;
94 DWORD providerIndex;
95 HANDLE handle;
96 BOOL providerDone;
97 DWORD dwScope;
98 DWORD dwType;
99 DWORD dwUsage;
100 LPNETRESOURCEW lpNet;
101 } WNetEnumerator, *PWNetEnumerator;
103 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
105 /* Returns an index (into the global WNetProviderTable) of the provider with
106 * the given name, or BAD_PROVIDER_INDEX if not found.
108 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
110 static PWNetProviderTable providerTable;
113 * Global provider table functions
116 static void _tryLoadProvider(PCWSTR provider)
118 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
119 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
120 'S','e','r','v','i','c','e','s','\\',0 };
121 static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
122 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
123 WCHAR serviceName[MAX_PATH];
124 HKEY hKey;
126 TRACE("%s\n", debugstr_w(provider));
127 snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt,
128 servicePrefix, provider);
129 serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0';
130 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
131 ERROR_SUCCESS)
133 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
134 'P','a','t','h',0 };
135 WCHAR providerPath[MAX_PATH];
136 DWORD type, size = sizeof(providerPath);
138 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
139 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && (type == REG_SZ || type == REG_EXPAND_SZ))
141 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
142 PWSTR name = NULL;
144 if (type == REG_EXPAND_SZ)
146 WCHAR path[MAX_PATH];
147 if (ExpandEnvironmentStringsW(providerPath, path, MAX_PATH)) lstrcpyW( providerPath, path );
150 size = 0;
151 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
152 if (size)
154 name = HeapAlloc(GetProcessHeap(), 0, size);
155 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
156 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
158 HeapFree(GetProcessHeap(), 0, name);
159 name = NULL;
162 if (name)
164 HMODULE hLib = LoadLibraryW(providerPath);
166 if (hLib)
168 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
170 PF_NPGetCaps getCaps = MPR_GETPROC(NPGetCaps);
172 TRACE("loaded lib %p\n", hLib);
173 if (getCaps)
175 PWNetProvider provider =
176 &providerTable->table[providerTable->numProviders];
178 provider->hLib = hLib;
179 provider->name = name;
180 TRACE("name is %s\n", debugstr_w(name));
181 provider->getCaps = getCaps;
182 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
183 provider->dwNetType = getCaps(WNNC_NET_TYPE);
184 TRACE("net type is 0x%08x\n", provider->dwNetType);
185 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
186 if (provider->dwEnumScopes)
188 TRACE("supports enumeration\n");
189 provider->openEnum = MPR_GETPROC(NPOpenEnum);
190 TRACE("NPOpenEnum %p\n", provider->openEnum);
191 provider->enumResource = MPR_GETPROC(NPEnumResource);
192 TRACE("NPEnumResource %p\n", provider->enumResource);
193 provider->closeEnum = MPR_GETPROC(NPCloseEnum);
194 TRACE("NPCloseEnum %p\n", provider->closeEnum);
195 provider->getResourceInformation = MPR_GETPROC(NPGetResourceInformation);
196 TRACE("NPGetResourceInformation %p\n", provider->getResourceInformation);
197 if (!provider->openEnum ||
198 !provider->enumResource ||
199 !provider->closeEnum)
201 provider->openEnum = NULL;
202 provider->enumResource = NULL;
203 provider->closeEnum = NULL;
204 provider->dwEnumScopes = 0;
205 WARN("Couldn't load enumeration functions\n");
208 provider->addConnection = MPR_GETPROC(NPAddConnection);
209 provider->addConnection3 = MPR_GETPROC(NPAddConnection3);
210 provider->cancelConnection = MPR_GETPROC(NPCancelConnection);
211 TRACE("NPAddConnection %p\n", provider->addConnection);
212 TRACE("NPAddConnection3 %p\n", provider->addConnection3);
213 TRACE("NPCancelConnection %p\n", provider->cancelConnection);
214 providerTable->numProviders++;
216 else
218 WARN("Provider %s didn't export NPGetCaps\n",
219 debugstr_w(provider));
220 HeapFree(GetProcessHeap(), 0, name);
221 FreeLibrary(hLib);
224 #undef MPR_GETPROC
226 else
228 WARN("Couldn't load library %s for provider %s\n",
229 debugstr_w(providerPath), debugstr_w(provider));
230 HeapFree(GetProcessHeap(), 0, name);
233 else
235 WARN("Couldn't get provider name for provider %s\n",
236 debugstr_w(provider));
239 else
240 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
241 RegCloseKey(hKey);
243 else
244 WARN("Couldn't open service key for provider %s\n",
245 debugstr_w(provider));
248 void wnetInit(HINSTANCE hInstDll)
250 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
251 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
252 'C','o','n','t','r','o','l','\\',
253 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
254 'O','r','d','e','r',0 };
255 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
256 'O','r','d','e','r',0 };
257 HKEY hKey;
259 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
260 == ERROR_SUCCESS)
262 DWORD size = 0;
264 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
265 if (size)
267 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
269 if (providers)
271 DWORD type;
273 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
274 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
276 PWSTR ptr;
277 DWORD numToAllocate;
279 TRACE("provider order is %s\n", debugstr_w(providers));
280 /* first count commas as a heuristic for how many to
281 * allocate space for */
282 for (ptr = providers, numToAllocate = 1; ptr; )
284 ptr = strchrW(ptr, ',');
285 if (ptr) {
286 numToAllocate++;
287 ptr++;
290 providerTable =
291 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
292 sizeof(WNetProviderTable)
293 + (numToAllocate - 1) * sizeof(WNetProvider));
294 if (providerTable)
296 PWSTR ptrPrev;
297 int entireNetworkLen;
298 LPCWSTR stringresource;
300 entireNetworkLen = LoadStringW(hInstDll,
301 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
302 providerTable->entireNetwork = HeapAlloc(
303 GetProcessHeap(), 0, (entireNetworkLen + 1) *
304 sizeof(WCHAR));
305 if (providerTable->entireNetwork)
307 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
308 providerTable->entireNetwork[entireNetworkLen] = 0;
310 providerTable->numAllocated = numToAllocate;
311 for (ptr = providers; ptr; )
313 ptrPrev = ptr;
314 ptr = strchrW(ptr, ',');
315 if (ptr)
316 *ptr++ = '\0';
317 _tryLoadProvider(ptrPrev);
321 HeapFree(GetProcessHeap(), 0, providers);
324 RegCloseKey(hKey);
328 void wnetFree(void)
330 if (providerTable)
332 DWORD i;
334 for (i = 0; i < providerTable->numProviders; i++)
336 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
337 FreeModule(providerTable->table[i].hLib);
339 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
340 HeapFree(GetProcessHeap(), 0, providerTable);
341 providerTable = NULL;
345 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
347 DWORD ret = BAD_PROVIDER_INDEX;
349 if (providerTable && providerTable->numProviders)
351 DWORD i;
353 for (i = 0; i < providerTable->numProviders &&
354 ret == BAD_PROVIDER_INDEX; i++)
355 if (!strcmpW(lpProvider, providerTable->table[i].name))
356 ret = i;
358 return ret;
362 * Browsing Functions
365 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
367 LPNETRESOURCEW ret;
369 if (lpNet)
371 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
372 if (ret)
374 size_t len;
376 *ret = *lpNet;
377 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
378 if (lpNet->lpRemoteName)
380 len = strlenW(lpNet->lpRemoteName) + 1;
381 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
382 if (ret->lpRemoteName)
383 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
387 else
388 ret = NULL;
389 return ret;
392 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
394 if (lpNet)
396 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
397 HeapFree(GetProcessHeap(), 0, lpNet);
401 static PWNetEnumerator _createNullEnumerator(void)
403 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
404 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
406 if (ret)
407 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
408 return ret;
411 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
412 DWORD dwUsage, LPNETRESOURCEW lpNet)
414 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
415 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
417 if (ret)
419 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
420 ret->dwScope = dwScope;
421 ret->dwType = dwType;
422 ret->dwUsage = dwUsage;
423 ret->lpNet = _copyNetResourceForEnumW(lpNet);
425 return ret;
428 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
429 DWORD dwUsage, DWORD index, HANDLE handle)
431 PWNetEnumerator ret;
433 if (!providerTable || index >= providerTable->numProviders)
434 ret = NULL;
435 else
437 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
438 if (ret)
440 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
441 ret->providerIndex = index;
442 ret->dwScope = dwScope;
443 ret->dwType = dwType;
444 ret->dwUsage = dwUsage;
445 ret->handle = handle;
448 return ret;
451 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
452 DWORD dwUsage)
454 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
455 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
457 if (ret)
459 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
460 ret->dwScope = dwScope;
461 ret->dwType = dwType;
462 ret->dwUsage = dwUsage;
464 return ret;
467 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
468 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
469 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
470 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
471 * if not all members of the array could be thunked, and something else on
472 * failure.
474 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
475 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
477 DWORD i, numToThunk, totalBytes, ret;
478 LPSTR strNext;
480 if (!lpNetArrayIn)
481 return WN_BAD_POINTER;
482 if (!lpcCount)
483 return WN_BAD_POINTER;
484 if (*lpcCount == -1)
485 return WN_BAD_VALUE;
486 if (!lpBuffer)
487 return WN_BAD_POINTER;
488 if (!lpBufferSize)
489 return WN_BAD_POINTER;
491 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
493 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
495 totalBytes += sizeof(NETRESOURCEA);
496 if (lpNet->lpLocalName)
497 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
498 -1, NULL, 0, NULL, NULL);
499 if (lpNet->lpRemoteName)
500 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
501 -1, NULL, 0, NULL, NULL);
502 if (lpNet->lpComment)
503 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
504 -1, NULL, 0, NULL, NULL);
505 if (lpNet->lpProvider)
506 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
507 -1, NULL, 0, NULL, NULL);
508 if (totalBytes < *lpBufferSize)
509 numToThunk = i + 1;
511 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
512 for (i = 0; i < numToThunk; i++)
514 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
515 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
517 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
518 /* lie about string lengths, we already verified how many
519 * we have space for above
521 if (lpNetIn->lpLocalName)
523 lpNetOut->lpLocalName = strNext;
524 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
525 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
527 if (lpNetIn->lpRemoteName)
529 lpNetOut->lpRemoteName = strNext;
530 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
531 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
533 if (lpNetIn->lpComment)
535 lpNetOut->lpComment = strNext;
536 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
537 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
539 if (lpNetIn->lpProvider)
541 lpNetOut->lpProvider = strNext;
542 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
543 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
546 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
547 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
548 *lpcCount, ret);
549 return ret;
552 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
553 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
554 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
555 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
556 * if not all members of the array could be thunked, and something else on
557 * failure.
559 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
560 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
562 DWORD i, numToThunk, totalBytes, ret;
563 LPWSTR strNext;
565 if (!lpNetArrayIn)
566 return WN_BAD_POINTER;
567 if (!lpcCount)
568 return WN_BAD_POINTER;
569 if (*lpcCount == -1)
570 return WN_BAD_VALUE;
571 if (!lpBuffer)
572 return WN_BAD_POINTER;
573 if (!lpBufferSize)
574 return WN_BAD_POINTER;
576 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
578 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
580 totalBytes += sizeof(NETRESOURCEW);
581 if (lpNet->lpLocalName)
582 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
583 -1, NULL, 0) * sizeof(WCHAR);
584 if (lpNet->lpRemoteName)
585 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
586 -1, NULL, 0) * sizeof(WCHAR);
587 if (lpNet->lpComment)
588 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
589 -1, NULL, 0) * sizeof(WCHAR);
590 if (lpNet->lpProvider)
591 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
592 -1, NULL, 0) * sizeof(WCHAR);
593 if (totalBytes < *lpBufferSize)
594 numToThunk = i + 1;
596 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
597 for (i = 0; i < numToThunk; i++)
599 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
600 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
602 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
603 /* lie about string lengths, we already verified how many
604 * we have space for above
606 if (lpNetIn->lpLocalName)
608 lpNetOut->lpLocalName = strNext;
609 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
610 -1, lpNetOut->lpLocalName, *lpBufferSize);
612 if (lpNetIn->lpRemoteName)
614 lpNetOut->lpRemoteName = strNext;
615 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
616 -1, lpNetOut->lpRemoteName, *lpBufferSize);
618 if (lpNetIn->lpComment)
620 lpNetOut->lpComment = strNext;
621 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
622 -1, lpNetOut->lpComment, *lpBufferSize);
624 if (lpNetIn->lpProvider)
626 lpNetOut->lpProvider = strNext;
627 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
628 -1, lpNetOut->lpProvider, *lpBufferSize);
631 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
632 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
633 *lpcCount, ret);
634 return ret;
637 /*********************************************************************
638 * WNetOpenEnumA [MPR.@]
640 * See comments for WNetOpenEnumW.
642 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
643 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
645 DWORD ret;
647 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
648 dwScope, dwType, dwUsage, lpNet, lphEnum );
650 if (!lphEnum)
651 ret = WN_BAD_POINTER;
652 else if (!providerTable || providerTable->numProviders == 0)
654 *lphEnum = NULL;
655 ret = WN_NO_NETWORK;
657 else
659 if (lpNet)
661 LPNETRESOURCEW lpNetWide = NULL;
662 BYTE buf[1024];
663 DWORD size = sizeof(buf), count = 1;
664 BOOL allocated = FALSE;
666 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
667 if (ret == WN_MORE_DATA)
669 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
670 size);
671 if (lpNetWide)
673 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
674 &size);
675 allocated = TRUE;
677 else
678 ret = WN_OUT_OF_MEMORY;
680 else if (ret == WN_SUCCESS)
681 lpNetWide = (LPNETRESOURCEW)buf;
682 if (ret == WN_SUCCESS)
683 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
684 lphEnum);
685 if (allocated)
686 HeapFree(GetProcessHeap(), 0, lpNetWide);
688 else
689 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
691 if (ret)
692 SetLastError(ret);
693 TRACE("Returning %d\n", ret);
694 return ret;
697 /*********************************************************************
698 * WNetOpenEnumW [MPR.@]
700 * Network enumeration has way too many parameters, so I'm not positive I got
701 * them right. What I've got so far:
703 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
704 * all the network providers should be enumerated.
706 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
707 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
708 * lpProvider is set, all the network providers should be enumerated.
709 * (This means the enumeration is a list of network providers, not that the
710 * enumeration is passed on to the providers.)
712 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
713 * resource matches the "Entire Network" resource (no remote name, no
714 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
715 * enumeration is done on every network provider.
717 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
718 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
719 * only to the given network provider.
721 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
722 * no lpProvider is set, enumeration will be tried on every network provider,
723 * in the order in which they're loaded.
725 * - The LPNETRESOURCE should be disregarded for scopes besides
726 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
727 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
729 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
730 * resource in the enumerated list, as well as any machines in your
731 * workgroup. The machines in your workgroup come from doing a
732 * RESOURCE_CONTEXT enumeration of every Network Provider.
734 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
735 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
737 DWORD ret;
739 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
740 dwScope, dwType, dwUsage, lpNet, lphEnum );
742 if (!lphEnum)
743 ret = WN_BAD_POINTER;
744 else if (!providerTable || providerTable->numProviders == 0)
746 *lphEnum = NULL;
747 ret = WN_NO_NETWORK;
749 else
751 switch (dwScope)
753 case RESOURCE_GLOBALNET:
754 if (lpNet)
756 if (lpNet->lpProvider)
758 DWORD index = _findProviderIndexW(lpNet->lpProvider);
760 if (index != BAD_PROVIDER_INDEX)
762 if (providerTable->table[index].openEnum &&
763 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
765 HANDLE handle;
766 PWSTR RemoteName = lpNet->lpRemoteName;
768 if ((lpNet->dwUsage & RESOURCEUSAGE_CONTAINER) &&
769 RemoteName && !strcmpW(RemoteName, lpNet->lpProvider))
770 lpNet->lpRemoteName = NULL;
772 ret = providerTable->table[index].openEnum(
773 dwScope, dwType, dwUsage, lpNet, &handle);
774 if (ret == WN_SUCCESS)
776 *lphEnum = _createProviderEnumerator(
777 dwScope, dwType, dwUsage, index, handle);
778 ret = *lphEnum ? WN_SUCCESS :
779 WN_OUT_OF_MEMORY;
782 lpNet->lpRemoteName = RemoteName;
784 else
785 ret = WN_NOT_SUPPORTED;
787 else
788 ret = WN_BAD_PROVIDER;
790 else if (lpNet->lpRemoteName)
792 *lphEnum = _createGlobalEnumeratorW(dwScope,
793 dwType, dwUsage, lpNet);
794 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
796 else
798 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
799 providerTable->entireNetwork))
801 /* comment matches the "Entire Network", enumerate
802 * global scope of every provider
804 *lphEnum = _createGlobalEnumeratorW(dwScope,
805 dwType, dwUsage, lpNet);
807 else
809 /* this is the same as not having passed lpNet */
810 *lphEnum = _createGlobalEnumeratorW(dwScope,
811 dwType, dwUsage, NULL);
813 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
816 else
818 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
819 dwUsage, lpNet);
820 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
822 break;
823 case RESOURCE_CONTEXT:
824 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
825 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
826 break;
827 case RESOURCE_REMEMBERED:
828 case RESOURCE_CONNECTED:
829 *lphEnum = _createNullEnumerator();
830 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
831 break;
832 default:
833 WARN("unknown scope 0x%08x\n", dwScope);
834 ret = WN_BAD_VALUE;
837 if (ret)
838 SetLastError(ret);
839 TRACE("Returning %d\n", ret);
840 return ret;
843 /*********************************************************************
844 * WNetEnumResourceA [MPR.@]
846 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
847 LPVOID lpBuffer, LPDWORD lpBufferSize )
849 DWORD ret;
851 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
853 if (!hEnum)
854 ret = WN_BAD_POINTER;
855 else if (!lpcCount)
856 ret = WN_BAD_POINTER;
857 else if (!lpBuffer)
858 ret = WN_BAD_POINTER;
859 else if (!lpBufferSize)
860 ret = WN_BAD_POINTER;
861 else if (*lpBufferSize < sizeof(NETRESOURCEA))
863 *lpBufferSize = sizeof(NETRESOURCEA);
864 ret = WN_MORE_DATA;
866 else
868 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
869 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
871 if (localBuffer)
873 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
874 &localSize);
875 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
877 /* FIXME: this isn't necessarily going to work in the case of
878 * WN_MORE_DATA, because our enumerator may have moved on to
879 * the next provider. MSDN states that a large (16KB) buffer
880 * size is the appropriate usage of this function, so
881 * hopefully it won't be an issue.
883 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
884 lpBuffer, lpBufferSize);
885 *lpcCount = localCount;
887 HeapFree(GetProcessHeap(), 0, localBuffer);
889 else
890 ret = WN_OUT_OF_MEMORY;
892 if (ret)
893 SetLastError(ret);
894 TRACE("Returning %d\n", ret);
895 return ret;
898 static DWORD _countProviderBytesW(PWNetProvider provider)
900 DWORD ret;
902 if (provider)
904 ret = sizeof(NETRESOURCEW);
905 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
907 else
908 ret = 0;
909 return ret;
912 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
913 LPVOID lpBuffer, const DWORD *lpBufferSize)
915 DWORD ret;
917 if (!enumerator)
918 return WN_BAD_POINTER;
919 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
920 return WN_BAD_VALUE;
921 if (!lpcCount)
922 return WN_BAD_POINTER;
923 if (!lpBuffer)
924 return WN_BAD_POINTER;
925 if (!lpBufferSize)
926 return WN_BAD_POINTER;
927 if (*lpBufferSize < sizeof(NETRESOURCEA))
928 return WN_MORE_DATA;
930 if (!providerTable || enumerator->providerIndex >=
931 providerTable->numProviders)
932 ret = WN_NO_MORE_ENTRIES;
933 else
935 DWORD bytes = 0, count = 0, countLimit, i;
936 LPNETRESOURCEW resource;
937 LPWSTR strNext;
939 countLimit = *lpcCount == -1 ?
940 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
941 while (count < countLimit && bytes < *lpBufferSize)
943 DWORD bytesNext = _countProviderBytesW(
944 &providerTable->table[count + enumerator->providerIndex]);
946 if (bytes + bytesNext < *lpBufferSize)
948 bytes += bytesNext;
949 count++;
952 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
953 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
955 resource->dwScope = RESOURCE_GLOBALNET;
956 resource->dwType = RESOURCETYPE_ANY;
957 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
958 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
959 RESOURCEUSAGE_RESERVED;
960 resource->lpLocalName = NULL;
961 resource->lpRemoteName = strNext;
962 strcpyW(resource->lpRemoteName,
963 providerTable->table[i + enumerator->providerIndex].name);
964 strNext += strlenW(resource->lpRemoteName) + 1;
965 resource->lpComment = NULL;
966 resource->lpProvider = strNext;
967 strcpyW(resource->lpProvider,
968 providerTable->table[i + enumerator->providerIndex].name);
969 strNext += strlenW(resource->lpProvider) + 1;
971 enumerator->providerIndex += count;
972 *lpcCount = count;
973 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
975 TRACE("Returning %d\n", ret);
976 return ret;
979 /* Advances the enumerator (assumed to be a global enumerator) to the next
980 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
981 * not open a handle with the next provider.
982 * If the existing handle is NULL, may leave the enumerator unchanged, since
983 * the current provider may support the desired scope.
984 * If the existing handle is not NULL, closes it before moving on.
985 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
986 * provider, and another error on failure.
988 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
990 if (!enumerator)
991 return WN_BAD_POINTER;
992 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
993 return WN_BAD_VALUE;
994 if (!providerTable || enumerator->providerIndex >=
995 providerTable->numProviders)
996 return WN_NO_MORE_ENTRIES;
998 if (enumerator->providerDone)
1000 DWORD dwEnum = 0;
1001 enumerator->providerDone = FALSE;
1002 if (enumerator->handle)
1004 providerTable->table[enumerator->providerIndex].closeEnum(
1005 enumerator->handle);
1006 enumerator->handle = NULL;
1007 enumerator->providerIndex++;
1009 if (enumerator->dwScope == RESOURCE_CONNECTED)
1010 dwEnum = WNNC_ENUM_LOCAL;
1011 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
1012 dwEnum = WNNC_ENUM_GLOBAL;
1013 else if (enumerator->dwScope == RESOURCE_CONTEXT)
1014 dwEnum = WNNC_ENUM_CONTEXT;
1015 for (; enumerator->providerIndex < providerTable->numProviders &&
1016 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
1017 & dwEnum); enumerator->providerIndex++)
1020 return enumerator->providerIndex < providerTable->numProviders ?
1021 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1024 /* "Passes through" call to the next provider that supports the enumeration
1025 * type.
1026 * FIXME: if one call to a provider's enumerator succeeds while there's still
1027 * space in lpBuffer, I don't call to the next provider. The caller may not
1028 * expect that it should call EnumResourceW again with a return value of
1029 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1030 * may have to be moved around a bit, ick.
1032 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1033 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1035 DWORD ret;
1037 if (!enumerator)
1038 return WN_BAD_POINTER;
1039 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1040 return WN_BAD_VALUE;
1041 if (!lpcCount)
1042 return WN_BAD_POINTER;
1043 if (!lpBuffer)
1044 return WN_BAD_POINTER;
1045 if (!lpBufferSize)
1046 return WN_BAD_POINTER;
1047 if (*lpBufferSize < sizeof(NETRESOURCEW))
1048 return WN_MORE_DATA;
1050 ret = _globalEnumeratorAdvance(enumerator);
1051 if (ret == WN_SUCCESS)
1053 ret = providerTable->table[enumerator->providerIndex].
1054 openEnum(enumerator->dwScope, enumerator->dwType,
1055 enumerator->dwUsage, enumerator->lpNet,
1056 &enumerator->handle);
1057 if (ret == WN_SUCCESS)
1059 ret = providerTable->table[enumerator->providerIndex].
1060 enumResource(enumerator->handle, lpcCount, lpBuffer,
1061 lpBufferSize);
1062 if (ret != WN_MORE_DATA)
1063 enumerator->providerDone = TRUE;
1066 TRACE("Returning %d\n", ret);
1067 return ret;
1070 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1071 LPVOID lpBuffer, LPDWORD lpBufferSize)
1073 DWORD ret;
1075 if (!enumerator)
1076 return WN_BAD_POINTER;
1077 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1078 return WN_BAD_VALUE;
1079 if (!lpcCount)
1080 return WN_BAD_POINTER;
1081 if (!lpBuffer)
1082 return WN_BAD_POINTER;
1083 if (!lpBufferSize)
1084 return WN_BAD_POINTER;
1085 if (*lpBufferSize < sizeof(NETRESOURCEW))
1086 return WN_MORE_DATA;
1087 if (!providerTable)
1088 return WN_NO_NETWORK;
1090 switch (enumerator->dwScope)
1092 case RESOURCE_GLOBALNET:
1093 if (enumerator->lpNet)
1094 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1095 lpBuffer, lpBufferSize);
1096 else
1097 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1098 lpBufferSize);
1099 break;
1100 case RESOURCE_CONTEXT:
1101 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1102 lpBufferSize);
1103 break;
1104 default:
1105 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1106 ret = WN_NO_MORE_ENTRIES;
1108 TRACE("Returning %d\n", ret);
1109 return ret;
1112 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1113 LPVOID lpBuffer, LPDWORD lpBufferSize)
1115 if (!enumerator)
1116 return WN_BAD_POINTER;
1117 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1118 return WN_BAD_VALUE;
1119 if (!enumerator->handle)
1120 return WN_BAD_VALUE;
1121 if (!lpcCount)
1122 return WN_BAD_POINTER;
1123 if (!lpBuffer)
1124 return WN_BAD_POINTER;
1125 if (!lpBufferSize)
1126 return WN_BAD_POINTER;
1127 if (!providerTable)
1128 return WN_NO_NETWORK;
1129 if (enumerator->providerIndex >= providerTable->numProviders)
1130 return WN_NO_MORE_ENTRIES;
1131 if (!providerTable->table[enumerator->providerIndex].enumResource)
1132 return WN_BAD_VALUE;
1133 return providerTable->table[enumerator->providerIndex].enumResource(
1134 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1137 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1138 LPVOID lpBuffer, LPDWORD lpBufferSize)
1140 DWORD ret;
1141 size_t cchEntireNetworkLen, bytesNeeded;
1143 if (!enumerator)
1144 return WN_BAD_POINTER;
1145 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1146 return WN_BAD_VALUE;
1147 if (!lpcCount)
1148 return WN_BAD_POINTER;
1149 if (!lpBuffer)
1150 return WN_BAD_POINTER;
1151 if (!lpBufferSize)
1152 return WN_BAD_POINTER;
1153 if (!providerTable)
1154 return WN_NO_NETWORK;
1156 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1157 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1158 if (*lpBufferSize < bytesNeeded)
1160 *lpBufferSize = bytesNeeded;
1161 ret = WN_MORE_DATA;
1163 else
1165 LPNETRESOURCEW lpNet = lpBuffer;
1167 lpNet->dwScope = RESOURCE_GLOBALNET;
1168 lpNet->dwType = enumerator->dwType;
1169 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1170 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1171 lpNet->lpLocalName = NULL;
1172 lpNet->lpRemoteName = NULL;
1173 lpNet->lpProvider = NULL;
1174 /* odd, but correct: put comment at end of buffer, so it won't get
1175 * overwritten by subsequent calls to a provider's enumResource
1177 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1178 (cchEntireNetworkLen * sizeof(WCHAR)));
1179 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1180 ret = WN_SUCCESS;
1182 if (ret == WN_SUCCESS)
1184 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1186 /* "Entire Network" entry enumerated--morph this into a global
1187 * enumerator. enumerator->lpNet continues to be NULL, since it has
1188 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1190 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1191 ret = _enumerateGlobalW(enumerator, lpcCount,
1192 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1193 if (ret == WN_SUCCESS)
1195 /* reflect the fact that we already enumerated "Entire Network" */
1196 (*lpcCount)++;
1197 *lpBufferSize = bufferSize + bytesNeeded;
1199 else
1201 /* the provider enumeration failed, but we already succeeded in
1202 * enumerating "Entire Network"--leave type as global to allow a
1203 * retry, but indicate success with a count of one.
1205 ret = WN_SUCCESS;
1206 *lpcCount = 1;
1207 *lpBufferSize = bytesNeeded;
1210 TRACE("Returning %d\n", ret);
1211 return ret;
1214 /*********************************************************************
1215 * WNetEnumResourceW [MPR.@]
1217 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1218 LPVOID lpBuffer, LPDWORD lpBufferSize )
1220 DWORD ret;
1222 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1224 if (!hEnum)
1225 ret = WN_BAD_POINTER;
1226 else if (!lpcCount)
1227 ret = WN_BAD_POINTER;
1228 else if (!lpBuffer)
1229 ret = WN_BAD_POINTER;
1230 else if (!lpBufferSize)
1231 ret = WN_BAD_POINTER;
1232 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1234 *lpBufferSize = sizeof(NETRESOURCEW);
1235 ret = WN_MORE_DATA;
1237 else
1239 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1241 switch (enumerator->enumType)
1243 case WNET_ENUMERATOR_TYPE_NULL:
1244 ret = WN_NO_MORE_ENTRIES;
1245 break;
1246 case WNET_ENUMERATOR_TYPE_GLOBAL:
1247 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1248 lpBufferSize);
1249 break;
1250 case WNET_ENUMERATOR_TYPE_PROVIDER:
1251 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1252 lpBufferSize);
1253 break;
1254 case WNET_ENUMERATOR_TYPE_CONTEXT:
1255 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1256 lpBufferSize);
1257 break;
1258 default:
1259 WARN("bogus enumerator type!\n");
1260 ret = WN_NO_NETWORK;
1263 if (ret)
1264 SetLastError(ret);
1265 TRACE("Returning %d\n", ret);
1266 return ret;
1269 /*********************************************************************
1270 * WNetCloseEnum [MPR.@]
1272 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1274 DWORD ret;
1276 TRACE( "(%p)\n", hEnum );
1278 if (hEnum)
1280 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1282 switch (enumerator->enumType)
1284 case WNET_ENUMERATOR_TYPE_NULL:
1285 ret = WN_SUCCESS;
1286 break;
1287 case WNET_ENUMERATOR_TYPE_GLOBAL:
1288 if (enumerator->lpNet)
1289 _freeEnumNetResource(enumerator->lpNet);
1290 if (enumerator->handle)
1291 providerTable->table[enumerator->providerIndex].
1292 closeEnum(enumerator->handle);
1293 ret = WN_SUCCESS;
1294 break;
1295 case WNET_ENUMERATOR_TYPE_PROVIDER:
1296 if (enumerator->handle)
1297 providerTable->table[enumerator->providerIndex].
1298 closeEnum(enumerator->handle);
1299 ret = WN_SUCCESS;
1300 break;
1301 default:
1302 WARN("bogus enumerator type!\n");
1303 ret = WN_BAD_HANDLE;
1305 HeapFree(GetProcessHeap(), 0, hEnum);
1307 else
1308 ret = WN_BAD_HANDLE;
1309 if (ret)
1310 SetLastError(ret);
1311 TRACE("Returning %d\n", ret);
1312 return ret;
1315 /*********************************************************************
1316 * WNetGetResourceInformationA [MPR.@]
1318 * See WNetGetResourceInformationW
1320 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1321 LPVOID lpBuffer, LPDWORD cbBuffer,
1322 LPSTR *lplpSystem )
1324 DWORD ret;
1326 TRACE( "(%p, %p, %p, %p)\n",
1327 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1329 if (!providerTable || providerTable->numProviders == 0)
1330 ret = WN_NO_NETWORK;
1331 else if (lpNetResource)
1333 LPNETRESOURCEW lpNetResourceW = NULL;
1334 DWORD size = 1024, count = 1;
1335 DWORD len;
1337 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1338 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1339 if (ret == WN_MORE_DATA)
1341 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1342 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1343 if (lpNetResourceW)
1344 ret = _thunkNetResourceArrayAToW(lpNetResource,
1345 &count, lpNetResourceW, &size);
1346 else
1347 ret = WN_OUT_OF_MEMORY;
1349 if (ret == WN_SUCCESS)
1351 LPWSTR lpSystemW = NULL;
1352 LPVOID lpBufferW;
1353 size = 1024;
1354 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1355 if (lpBufferW)
1357 ret = WNetGetResourceInformationW(lpNetResourceW,
1358 lpBufferW, &size, &lpSystemW);
1359 if (ret == WN_MORE_DATA)
1361 HeapFree(GetProcessHeap(), 0, lpBufferW);
1362 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1363 if (lpBufferW)
1364 ret = WNetGetResourceInformationW(lpNetResourceW,
1365 lpBufferW, &size, &lpSystemW);
1366 else
1367 ret = WN_OUT_OF_MEMORY;
1369 if (ret == WN_SUCCESS)
1371 ret = _thunkNetResourceArrayWToA(lpBufferW,
1372 &count, lpBuffer, cbBuffer);
1373 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1374 lpNetResourceW = lpBufferW;
1375 size = sizeof(NETRESOURCEA);
1376 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1377 -1, NULL, 0, NULL, NULL);
1378 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1379 -1, NULL, 0, NULL, NULL);
1381 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1382 -1, NULL, 0, NULL, NULL);
1383 if ((len) && ( size + len < *cbBuffer))
1385 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1386 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1387 *lplpSystem, len, NULL, NULL);
1388 ret = WN_SUCCESS;
1390 else
1391 ret = WN_MORE_DATA;
1393 else
1394 ret = WN_OUT_OF_MEMORY;
1395 HeapFree(GetProcessHeap(), 0, lpBufferW);
1397 else
1398 ret = WN_OUT_OF_MEMORY;
1399 HeapFree(GetProcessHeap(), 0, lpSystemW);
1401 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1403 else
1404 ret = WN_NO_NETWORK;
1406 if (ret)
1407 SetLastError(ret);
1408 TRACE("Returning %d\n", ret);
1409 return ret;
1412 /*********************************************************************
1413 * WNetGetResourceInformationW [MPR.@]
1415 * WNetGetResourceInformationW function identifies the network provider
1416 * that owns the resource and gets information about the type of the resource.
1418 * PARAMS:
1419 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1420 * defines a network resource.
1421 * lpBuffer [ O] the pointer to buffer, containing result. It
1422 * contains NETRESOURCEW structure and strings to
1423 * which the members of the NETRESOURCEW structure
1424 * point.
1425 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1426 * in bytes.
1427 * lplpSystem [ O] the pointer to string in the output buffer,
1428 * containing the part of the resource name without
1429 * names of the server and share.
1431 * RETURNS:
1432 * NO_ERROR if the function succeeds. System error code if the function fails.
1435 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1436 LPVOID lpBuffer, LPDWORD cbBuffer,
1437 LPWSTR *lplpSystem )
1439 DWORD ret = WN_NO_NETWORK;
1440 DWORD index;
1442 TRACE( "(%p, %p, %p, %p)\n",
1443 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1445 if (!(lpBuffer))
1446 ret = WN_OUT_OF_MEMORY;
1447 else if (providerTable != NULL)
1449 /* FIXME: For function value of a variable is indifferent, it does
1450 * search of all providers in a network.
1452 for (index = 0; index < providerTable->numProviders; index++)
1454 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1455 WNNC_DLG_GETRESOURCEINFORMATION)
1457 if (providerTable->table[index].getResourceInformation)
1458 ret = providerTable->table[index].getResourceInformation(
1459 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1460 else
1461 ret = WN_NO_NETWORK;
1462 if (ret == WN_SUCCESS)
1463 break;
1467 if (ret)
1468 SetLastError(ret);
1469 return ret;
1472 /*********************************************************************
1473 * WNetGetResourceParentA [MPR.@]
1475 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1476 LPVOID lpBuffer, LPDWORD lpBufferSize )
1478 FIXME( "(%p, %p, %p): stub\n",
1479 lpNetResource, lpBuffer, lpBufferSize );
1481 SetLastError(WN_NO_NETWORK);
1482 return WN_NO_NETWORK;
1485 /*********************************************************************
1486 * WNetGetResourceParentW [MPR.@]
1488 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1489 LPVOID lpBuffer, LPDWORD lpBufferSize )
1491 FIXME( "(%p, %p, %p): stub\n",
1492 lpNetResource, lpBuffer, lpBufferSize );
1494 SetLastError(WN_NO_NETWORK);
1495 return WN_NO_NETWORK;
1501 * Connection Functions
1504 /*********************************************************************
1505 * WNetAddConnectionA [MPR.@]
1507 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1508 LPCSTR lpLocalName )
1510 NETRESOURCEA resourcesA;
1512 memset(&resourcesA, 0, sizeof(resourcesA));
1513 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1514 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1515 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1518 /*********************************************************************
1519 * WNetAddConnectionW [MPR.@]
1521 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1522 LPCWSTR lpLocalName )
1524 NETRESOURCEW resourcesW;
1526 memset(&resourcesW, 0, sizeof(resourcesW));
1527 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1528 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1529 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1532 /*********************************************************************
1533 * WNetAddConnection2A [MPR.@]
1535 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1536 LPCSTR lpPassword, LPCSTR lpUserID,
1537 DWORD dwFlags )
1539 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1540 NULL, 0, NULL);
1543 /*********************************************************************
1544 * WNetAddConnection2W [MPR.@]
1546 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1547 LPCWSTR lpPassword, LPCWSTR lpUserID,
1548 DWORD dwFlags )
1550 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1551 NULL, 0, NULL);
1554 /*********************************************************************
1555 * WNetAddConnection3A [MPR.@]
1557 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1558 LPCSTR lpPassword, LPCSTR lpUserID,
1559 DWORD dwFlags )
1561 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1562 dwFlags, NULL, 0, NULL);
1565 /*********************************************************************
1566 * WNetAddConnection3W [MPR.@]
1568 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1569 LPCWSTR lpPassword, LPCWSTR lpUserID,
1570 DWORD dwFlags )
1572 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1573 dwFlags, NULL, 0, NULL);
1576 struct use_connection_context
1578 HWND hwndOwner;
1579 NETRESOURCEW *resource;
1580 NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */
1581 WCHAR *password;
1582 WCHAR *userid;
1583 DWORD flags;
1584 void *accessname;
1585 DWORD *buffer_size;
1586 DWORD *result;
1587 DWORD (*pre_set_accessname)(struct use_connection_context*, WCHAR *);
1588 void (*set_accessname)(struct use_connection_context*, WCHAR *);
1591 static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1593 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1595 DWORD len;
1597 if (local_name)
1598 len = strlenW(local_name);
1599 else
1600 len = strlenW(ctxt->resource->lpRemoteName);
1602 if (++len > *ctxt->buffer_size)
1604 *ctxt->buffer_size = len;
1605 return ERROR_MORE_DATA;
1608 else
1609 ctxt->accessname = NULL;
1611 return ERROR_SUCCESS;
1614 static void use_connection_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1616 WCHAR *accessname = ctxt->accessname;
1617 if (local_name)
1619 strcpyW(accessname, local_name);
1620 if (ctxt->result)
1621 *ctxt->result = CONNECT_LOCALDRIVE;
1623 else
1624 strcpyW(accessname, ctxt->resource->lpRemoteName);
1627 static DWORD wnet_use_provider( struct use_connection_context *ctxt, NETRESOURCEW * netres, WNetProvider *provider, BOOLEAN redirect )
1629 DWORD caps, ret;
1631 caps = provider->getCaps(WNNC_CONNECTION);
1632 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1633 return ERROR_BAD_PROVIDER;
1635 ret = WN_ACCESS_DENIED;
1638 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1639 ret = provider->addConnection3(ctxt->hwndOwner, netres, ctxt->password, ctxt->userid, ctxt->flags);
1640 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1641 ret = provider->addConnection(netres, ctxt->password, ctxt->userid);
1643 if (ret == WN_ALREADY_CONNECTED && redirect)
1644 netres->lpLocalName[0] -= 1;
1645 } while (redirect && ret == WN_ALREADY_CONNECTED && netres->lpLocalName[0] >= 'C');
1647 if (ret == WN_SUCCESS && ctxt->accessname)
1648 ctxt->set_accessname(ctxt, netres->lpLocalName);
1650 return ret;
1653 static DWORD wnet_use_connection( struct use_connection_context *ctxt )
1655 WNetProvider *provider;
1656 DWORD index, ret = WN_NO_NETWORK;
1657 BOOL redirect = FALSE;
1658 WCHAR letter[3] = {'Z', ':', 0};
1659 NETRESOURCEW netres;
1661 if (!providerTable || providerTable->numProviders == 0)
1662 return WN_NO_NETWORK;
1664 if (!ctxt->resource)
1665 return ERROR_INVALID_PARAMETER;
1666 netres = *ctxt->resource;
1668 if (!netres.lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
1670 if (netres.dwType != RESOURCETYPE_DISK && netres.dwType != RESOURCETYPE_PRINT)
1671 return ERROR_BAD_DEV_TYPE;
1673 if (netres.dwType == RESOURCETYPE_PRINT)
1675 FIXME("Local device selection is not implemented for printers.\n");
1676 return WN_NO_NETWORK;
1679 redirect = TRUE;
1680 netres.lpLocalName = letter;
1683 if (ctxt->flags & CONNECT_INTERACTIVE)
1684 return ERROR_BAD_NET_NAME;
1686 if ((ret = ctxt->pre_set_accessname(ctxt, netres.lpLocalName)))
1687 return ret;
1689 if (netres.lpProvider)
1691 index = _findProviderIndexW(netres.lpProvider);
1692 if (index == BAD_PROVIDER_INDEX)
1693 return ERROR_BAD_PROVIDER;
1695 provider = &providerTable->table[index];
1696 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
1698 else
1700 for (index = 0; index < providerTable->numProviders; index++)
1702 provider = &providerTable->table[index];
1703 ret = wnet_use_provider(ctxt, &netres, provider, redirect);
1704 if (ret == WN_SUCCESS || ret == WN_ALREADY_CONNECTED)
1705 break;
1709 return ret;
1712 /*****************************************************************
1713 * WNetUseConnectionW [MPR.@]
1715 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
1716 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
1718 struct use_connection_context ctxt;
1720 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1721 hwndOwner, resource, password, debugstr_w(userid), flags,
1722 accessname, buffer_size, result );
1724 ctxt.hwndOwner = hwndOwner;
1725 ctxt.resource = resource;
1726 ctxt.resourceA = NULL;
1727 ctxt.password = (WCHAR*)password;
1728 ctxt.userid = (WCHAR*)userid;
1729 ctxt.flags = flags;
1730 ctxt.accessname = accessname;
1731 ctxt.buffer_size = buffer_size;
1732 ctxt.result = result;
1733 ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
1734 ctxt.set_accessname = use_connection_set_accessnameW;
1736 return wnet_use_connection(&ctxt);
1739 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
1741 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1743 DWORD len;
1745 if (local_name)
1746 len = WideCharToMultiByte(CP_ACP, 0, local_name, -1, NULL, 0, NULL, NULL) - 1;
1747 else
1748 len = strlen(ctxt->resourceA->lpRemoteName);
1750 if (++len > *ctxt->buffer_size)
1752 *ctxt->buffer_size = len;
1753 return ERROR_MORE_DATA;
1756 else
1757 ctxt->accessname = NULL;
1759 return ERROR_SUCCESS;
1762 static void use_connection_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
1764 char *accessname = ctxt->accessname;
1765 if (local_name)
1767 WideCharToMultiByte(CP_ACP, 0, local_name, -1, accessname, *ctxt->buffer_size, NULL, NULL);
1768 if (ctxt->result)
1769 *ctxt->result = CONNECT_LOCALDRIVE;
1771 else
1772 strcpy(accessname, ctxt->resourceA->lpRemoteName);
1775 static LPWSTR strdupAtoW( LPCSTR str )
1777 LPWSTR ret;
1778 INT len;
1780 if (!str) return NULL;
1781 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
1782 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1783 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
1784 return ret;
1787 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
1789 resourceW->dwScope = resourceA->dwScope;
1790 resourceW->dwType = resourceA->dwType;
1791 resourceW->dwDisplayType = resourceA->dwDisplayType;
1792 resourceW->dwUsage = resourceA->dwUsage;
1793 resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
1794 resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
1795 resourceW->lpComment = strdupAtoW(resourceA->lpComment);
1796 resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
1799 static void free_netresourceW( NETRESOURCEW *resource )
1801 HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
1802 HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
1803 HeapFree(GetProcessHeap(), 0, resource->lpComment);
1804 HeapFree(GetProcessHeap(), 0, resource->lpProvider);
1807 /*****************************************************************
1808 * WNetUseConnectionA [MPR.@]
1810 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
1811 LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
1812 DWORD *buffer_size, DWORD *result )
1814 struct use_connection_context ctxt;
1815 NETRESOURCEW resourceW;
1816 DWORD ret;
1818 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
1819 accessname, buffer_size, result );
1821 netresource_a_to_w(resource, &resourceW);
1823 ctxt.hwndOwner = hwndOwner;
1824 ctxt.resource = &resourceW;
1825 ctxt.resourceA = resource;
1826 ctxt.password = strdupAtoW(password);
1827 ctxt.userid = strdupAtoW(userid);
1828 ctxt.flags = flags;
1829 ctxt.accessname = accessname;
1830 ctxt.buffer_size = buffer_size;
1831 ctxt.result = result;
1832 ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
1833 ctxt.set_accessname = use_connection_set_accessnameA;
1835 ret = wnet_use_connection(&ctxt);
1837 free_netresourceW(&resourceW);
1838 HeapFree(GetProcessHeap(), 0, ctxt.password);
1839 HeapFree(GetProcessHeap(), 0, ctxt.userid);
1841 return ret;
1844 /*********************************************************************
1845 * WNetCancelConnectionA [MPR.@]
1847 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1849 return WNetCancelConnection2A(lpName, 0, fForce);
1852 /*********************************************************************
1853 * WNetCancelConnectionW [MPR.@]
1855 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1857 return WNetCancelConnection2W(lpName, 0, fForce);
1860 /*********************************************************************
1861 * WNetCancelConnection2A [MPR.@]
1863 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1865 DWORD ret;
1866 WCHAR * name = strdupAtoW(lpName);
1867 if (!name)
1868 return ERROR_NOT_CONNECTED;
1870 ret = WNetCancelConnection2W(name, dwFlags, fForce);
1871 HeapFree(GetProcessHeap(), 0, name);
1873 return ret;
1876 /*********************************************************************
1877 * WNetCancelConnection2W [MPR.@]
1879 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1881 DWORD ret = WN_NO_NETWORK;
1882 DWORD index;
1884 if (providerTable != NULL)
1886 for (index = 0; index < providerTable->numProviders; index++)
1888 if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
1889 WNNC_CON_CANCELCONNECTION)
1891 if (providerTable->table[index].cancelConnection)
1892 ret = providerTable->table[index].cancelConnection((LPWSTR)lpName, fForce);
1893 else
1894 ret = WN_NO_NETWORK;
1895 if (ret == WN_SUCCESS || ret == WN_OPEN_FILES)
1896 break;
1900 return ret;
1903 /*****************************************************************
1904 * WNetRestoreConnectionA [MPR.@]
1906 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
1908 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1910 SetLastError(WN_NO_NETWORK);
1911 return WN_NO_NETWORK;
1914 /*****************************************************************
1915 * WNetRestoreConnectionW [MPR.@]
1917 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
1919 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1921 SetLastError(WN_NO_NETWORK);
1922 return WN_NO_NETWORK;
1925 /**************************************************************************
1926 * WNetGetConnectionA [MPR.@]
1928 * RETURNS
1929 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1930 * - WN_NOT_CONNECTED drive is a local drive
1931 * - WN_MORE_DATA buffer isn't big enough
1932 * - WN_SUCCESS success (net path in buffer)
1934 * FIXME: need to test return values under different errors
1936 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1937 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1939 DWORD ret;
1941 if (!lpLocalName)
1942 ret = WN_BAD_POINTER;
1943 else if (!lpBufferSize)
1944 ret = WN_BAD_POINTER;
1945 else if (!lpRemoteName && *lpBufferSize)
1946 ret = WN_BAD_POINTER;
1947 else
1949 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1951 if (len)
1953 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1955 if (wideLocalName)
1957 WCHAR wideRemoteStatic[MAX_PATH];
1958 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1960 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1962 /* try once without memory allocation */
1963 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1964 &wideRemoteSize);
1965 if (ret == WN_SUCCESS)
1967 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1968 -1, NULL, 0, NULL, NULL);
1970 if (len <= *lpBufferSize)
1972 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1973 lpRemoteName, *lpBufferSize, NULL, NULL);
1974 ret = WN_SUCCESS;
1976 else
1978 *lpBufferSize = len;
1979 ret = WN_MORE_DATA;
1982 else if (ret == WN_MORE_DATA)
1984 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1985 wideRemoteSize * sizeof(WCHAR));
1987 if (wideRemote)
1989 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1990 &wideRemoteSize);
1991 if (ret == WN_SUCCESS)
1993 if (len <= *lpBufferSize)
1995 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1996 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1997 ret = WN_SUCCESS;
1999 else
2001 *lpBufferSize = len;
2002 ret = WN_MORE_DATA;
2005 HeapFree(GetProcessHeap(), 0, wideRemote);
2007 else
2008 ret = WN_OUT_OF_MEMORY;
2010 HeapFree(GetProcessHeap(), 0, wideLocalName);
2012 else
2013 ret = WN_OUT_OF_MEMORY;
2015 else
2016 ret = WN_BAD_LOCALNAME;
2018 if (ret)
2019 SetLastError(ret);
2020 TRACE("Returning %d\n", ret);
2021 return ret;
2024 /* find the network connection for a given drive; helper for WNetGetConnection */
2025 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
2027 char buffer[1024];
2028 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
2029 HANDLE mgr;
2030 DWORD ret = WN_NOT_CONNECTED;
2031 DWORD bytes_returned;
2033 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
2034 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
2035 0, 0 )) == INVALID_HANDLE_VALUE)
2037 ERR( "failed to open mount manager err %u\n", GetLastError() );
2038 return ret;
2040 memset( data, 0, sizeof(*data) );
2041 data->letter = letter;
2042 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
2043 data, sizeof(buffer), &bytes_returned, NULL ))
2045 char *p, *mount_point = buffer + data->mount_point_offset;
2046 DWORD len;
2048 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
2050 mount_point += 2;
2051 mount_point[0] = '\\';
2052 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
2054 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
2055 if (len > *size)
2057 *size = len;
2058 ret = WN_MORE_DATA;
2060 else
2062 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
2063 ret = WN_SUCCESS;
2067 CloseHandle( mgr );
2068 return ret;
2071 /**************************************************************************
2072 * WNetGetConnectionW [MPR.@]
2074 * FIXME: need to test return values under different errors
2076 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
2077 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
2079 DWORD ret;
2081 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
2082 lpBufferSize);
2084 if (!lpLocalName)
2085 ret = WN_BAD_POINTER;
2086 else if (!lpBufferSize)
2087 ret = WN_BAD_POINTER;
2088 else if (!lpRemoteName && *lpBufferSize)
2089 ret = WN_BAD_POINTER;
2090 else if (!lpLocalName[0])
2091 ret = WN_BAD_LOCALNAME;
2092 else
2094 if (lpLocalName[1] == ':')
2096 switch(GetDriveTypeW(lpLocalName))
2098 case DRIVE_REMOTE:
2099 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
2100 break;
2101 case DRIVE_REMOVABLE:
2102 case DRIVE_FIXED:
2103 case DRIVE_CDROM:
2104 TRACE("file is local\n");
2105 ret = WN_NOT_CONNECTED;
2106 break;
2107 default:
2108 ret = WN_BAD_LOCALNAME;
2111 else
2112 ret = WN_BAD_LOCALNAME;
2114 if (ret)
2115 SetLastError(ret);
2116 TRACE("Returning %d\n", ret);
2117 return ret;
2120 /**************************************************************************
2121 * WNetSetConnectionA [MPR.@]
2123 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
2124 LPVOID pvValue )
2126 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
2128 SetLastError(WN_NO_NETWORK);
2129 return WN_NO_NETWORK;
2132 /**************************************************************************
2133 * WNetSetConnectionW [MPR.@]
2135 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2136 LPVOID pvValue )
2138 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2140 SetLastError(WN_NO_NETWORK);
2141 return WN_NO_NETWORK;
2144 /*****************************************************************
2145 * WNetGetUniversalNameA [MPR.@]
2147 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2148 LPVOID lpBuffer, LPDWORD lpBufferSize )
2150 DWORD err, size;
2152 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2153 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2155 switch (dwInfoLevel)
2157 case UNIVERSAL_NAME_INFO_LEVEL:
2159 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2161 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2163 err = ERROR_NOT_CONNECTED;
2164 break;
2167 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2168 if (*lpBufferSize < size)
2170 err = WN_MORE_DATA;
2171 break;
2173 info->lpUniversalName = (char *)info + sizeof(*info);
2174 lstrcpyA(info->lpUniversalName, lpLocalPath);
2175 err = WN_NO_ERROR;
2176 break;
2178 case REMOTE_NAME_INFO_LEVEL:
2179 err = WN_NO_NETWORK;
2180 break;
2182 default:
2183 err = WN_BAD_VALUE;
2184 break;
2187 SetLastError(err);
2188 return err;
2191 /*****************************************************************
2192 * WNetGetUniversalNameW [MPR.@]
2194 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2195 LPVOID lpBuffer, LPDWORD lpBufferSize )
2197 DWORD err, size;
2199 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2200 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2202 switch (dwInfoLevel)
2204 case UNIVERSAL_NAME_INFO_LEVEL:
2206 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2208 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2210 err = ERROR_NOT_CONNECTED;
2211 break;
2214 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2215 if (*lpBufferSize < size)
2217 err = WN_MORE_DATA;
2218 break;
2220 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2221 lstrcpyW(info->lpUniversalName, lpLocalPath);
2222 err = WN_NO_ERROR;
2223 break;
2225 case REMOTE_NAME_INFO_LEVEL:
2226 err = WN_NO_NETWORK;
2227 break;
2229 default:
2230 err = WN_BAD_VALUE;
2231 break;
2234 if (err != WN_NO_ERROR) SetLastError(err);
2235 return err;
2241 * Other Functions
2244 /**************************************************************************
2245 * WNetGetUserA [MPR.@]
2247 * FIXME: we should not return ourselves, but the owner of the drive lpName
2249 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2251 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2252 return GetLastError();
2255 /*****************************************************************
2256 * WNetGetUserW [MPR.@]
2258 * FIXME: we should not return ourselves, but the owner of the drive lpName
2260 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2262 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2263 return GetLastError();
2266 /*********************************************************************
2267 * WNetConnectionDialog [MPR.@]
2269 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2271 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2273 SetLastError(WN_NO_NETWORK);
2274 return WN_NO_NETWORK;
2277 /*********************************************************************
2278 * WNetConnectionDialog1A [MPR.@]
2280 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2282 FIXME( "(%p): stub\n", lpConnDlgStruct );
2284 SetLastError(WN_NO_NETWORK);
2285 return WN_NO_NETWORK;
2288 /*********************************************************************
2289 * WNetConnectionDialog1W [MPR.@]
2291 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2293 FIXME( "(%p): stub\n", lpConnDlgStruct );
2295 SetLastError(WN_NO_NETWORK);
2296 return WN_NO_NETWORK;
2299 /*********************************************************************
2300 * WNetDisconnectDialog [MPR.@]
2302 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2304 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2306 SetLastError(WN_NO_NETWORK);
2307 return WN_NO_NETWORK;
2310 /*********************************************************************
2311 * WNetDisconnectDialog1A [MPR.@]
2313 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2315 FIXME( "(%p): stub\n", lpConnDlgStruct );
2317 SetLastError(WN_NO_NETWORK);
2318 return WN_NO_NETWORK;
2321 /*********************************************************************
2322 * WNetDisconnectDialog1W [MPR.@]
2324 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2326 FIXME( "(%p): stub\n", lpConnDlgStruct );
2328 SetLastError(WN_NO_NETWORK);
2329 return WN_NO_NETWORK;
2332 /*********************************************************************
2333 * WNetGetLastErrorA [MPR.@]
2335 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2336 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2337 LPSTR lpNameBuf, DWORD nNameBufSize )
2339 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2340 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2342 SetLastError(WN_NO_NETWORK);
2343 return WN_NO_NETWORK;
2346 /*********************************************************************
2347 * WNetGetLastErrorW [MPR.@]
2349 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2350 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2351 LPWSTR lpNameBuf, DWORD nNameBufSize )
2353 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2354 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2356 SetLastError(WN_NO_NETWORK);
2357 return WN_NO_NETWORK;
2360 /*********************************************************************
2361 * WNetGetNetworkInformationA [MPR.@]
2363 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2364 LPNETINFOSTRUCT lpNetInfoStruct )
2366 DWORD ret;
2368 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2370 if (!lpProvider)
2371 ret = WN_BAD_POINTER;
2372 else
2374 int len;
2376 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2377 if (len)
2379 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2381 if (wideProvider)
2383 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2384 len);
2385 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2386 HeapFree(GetProcessHeap(), 0, wideProvider);
2388 else
2389 ret = WN_OUT_OF_MEMORY;
2391 else
2392 ret = GetLastError();
2394 if (ret)
2395 SetLastError(ret);
2396 TRACE("Returning %d\n", ret);
2397 return ret;
2400 /*********************************************************************
2401 * WNetGetNetworkInformationW [MPR.@]
2403 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2404 LPNETINFOSTRUCT lpNetInfoStruct )
2406 DWORD ret;
2408 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2410 if (!lpProvider)
2411 ret = WN_BAD_POINTER;
2412 else if (!lpNetInfoStruct)
2413 ret = WN_BAD_POINTER;
2414 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2415 ret = WN_BAD_VALUE;
2416 else
2418 if (providerTable && providerTable->numProviders)
2420 DWORD providerIndex = _findProviderIndexW(lpProvider);
2422 if (providerIndex != BAD_PROVIDER_INDEX)
2424 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2425 lpNetInfoStruct->dwProviderVersion =
2426 providerTable->table[providerIndex].dwSpecVersion;
2427 lpNetInfoStruct->dwStatus = NO_ERROR;
2428 lpNetInfoStruct->dwCharacteristics = 0;
2429 lpNetInfoStruct->dwHandle = 0;
2430 lpNetInfoStruct->wNetType =
2431 HIWORD(providerTable->table[providerIndex].dwNetType);
2432 lpNetInfoStruct->dwPrinters = -1;
2433 lpNetInfoStruct->dwDrives = -1;
2434 ret = WN_SUCCESS;
2436 else
2437 ret = WN_BAD_PROVIDER;
2439 else
2440 ret = WN_NO_NETWORK;
2442 if (ret)
2443 SetLastError(ret);
2444 TRACE("Returning %d\n", ret);
2445 return ret;
2448 /*****************************************************************
2449 * WNetGetProviderNameA [MPR.@]
2451 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2452 LPSTR lpProvider, LPDWORD lpBufferSize )
2454 DWORD ret;
2456 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2457 lpBufferSize);
2459 if (!lpProvider)
2460 ret = WN_BAD_POINTER;
2461 else if (!lpBufferSize)
2462 ret = WN_BAD_POINTER;
2463 else
2465 if (providerTable)
2467 DWORD i;
2469 ret = WN_NO_NETWORK;
2470 for (i = 0; i < providerTable->numProviders &&
2471 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2472 i++)
2474 if (i < providerTable->numProviders)
2476 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2477 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2479 if (*lpBufferSize < sizeNeeded)
2481 *lpBufferSize = sizeNeeded;
2482 ret = WN_MORE_DATA;
2484 else
2486 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2487 -1, lpProvider, *lpBufferSize, NULL, NULL);
2488 ret = WN_SUCCESS;
2489 /* FIXME: is *lpBufferSize set to the number of characters
2490 * copied? */
2494 else
2495 ret = WN_NO_NETWORK;
2497 if (ret)
2498 SetLastError(ret);
2499 TRACE("Returning %d\n", ret);
2500 return ret;
2503 /*****************************************************************
2504 * WNetGetProviderNameW [MPR.@]
2506 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2507 LPWSTR lpProvider, LPDWORD lpBufferSize )
2509 DWORD ret;
2511 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2512 lpBufferSize);
2514 if (!lpProvider)
2515 ret = WN_BAD_POINTER;
2516 else if (!lpBufferSize)
2517 ret = WN_BAD_POINTER;
2518 else
2520 if (providerTable)
2522 DWORD i;
2524 ret = WN_NO_NETWORK;
2525 for (i = 0; i < providerTable->numProviders &&
2526 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2527 i++)
2529 if (i < providerTable->numProviders)
2531 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2533 if (*lpBufferSize < sizeNeeded)
2535 *lpBufferSize = sizeNeeded;
2536 ret = WN_MORE_DATA;
2538 else
2540 strcpyW(lpProvider, providerTable->table[i].name);
2541 ret = WN_SUCCESS;
2542 /* FIXME: is *lpBufferSize set to the number of characters
2543 * copied? */
2547 else
2548 ret = WN_NO_NETWORK;
2550 if (ret)
2551 SetLastError(ret);
2552 TRACE("Returning %d\n", ret);
2553 return ret;