wined3d: Get resource info from the texture in surface_load_renderbuffer().
[wine.git] / dlls / mpr / wnet.c
blob0d4209c1d39074439b617a96e4e6b45ca017141a
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 } WNetProvider, *PWNetProvider;
63 typedef struct _WNetProviderTable
65 LPWSTR entireNetwork;
66 DWORD numAllocated;
67 DWORD numProviders;
68 WNetProvider table[1];
69 } WNetProviderTable, *PWNetProviderTable;
71 #define WNET_ENUMERATOR_TYPE_NULL 0
72 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
73 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
74 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
76 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
77 * the enumeration; it represents one of the following types:
78 * - a 'null' enumeration, one that contains no members
79 * - a global enumeration, one that's executed across all providers
80 * - a provider-specific enumeration, one that's only executed by a single
81 * provider
82 * - a context enumeration. I know this contradicts what I just said about
83 * there being no correspondence between the scope and the type, but it's
84 * necessary for the special case that a "Entire Network" entry needs to
85 * be enumerated in an enumeration of the context scope. Thus an enumeration
86 * of the context scope results in a context type enumerator, which morphs
87 * into a global enumeration (so the enumeration continues across all
88 * providers).
90 typedef struct _WNetEnumerator
92 DWORD enumType;
93 DWORD providerIndex;
94 HANDLE handle;
95 BOOL providerDone;
96 DWORD dwScope;
97 DWORD dwType;
98 DWORD dwUsage;
99 LPNETRESOURCEW lpNet;
100 } WNetEnumerator, *PWNetEnumerator;
102 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
104 /* Returns an index (into the global WNetProviderTable) of the provider with
105 * the given name, or BAD_PROVIDER_INDEX if not found.
107 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
109 static PWNetProviderTable providerTable;
112 * Global provider table functions
115 static void _tryLoadProvider(PCWSTR provider)
117 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
118 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
119 'S','e','r','v','i','c','e','s','\\',0 };
120 static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
121 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
122 WCHAR serviceName[MAX_PATH];
123 HKEY hKey;
125 TRACE("%s\n", debugstr_w(provider));
126 snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt,
127 servicePrefix, provider);
128 serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0';
129 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
130 ERROR_SUCCESS)
132 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
133 'P','a','t','h',0 };
134 WCHAR providerPath[MAX_PATH];
135 DWORD type, size = sizeof(providerPath);
137 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
138 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && (type == REG_SZ || type == REG_EXPAND_SZ))
140 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
141 PWSTR name = NULL;
143 if (type == REG_EXPAND_SZ)
145 WCHAR path[MAX_PATH];
146 if (ExpandEnvironmentStringsW(providerPath, path, MAX_PATH)) lstrcpyW( providerPath, path );
149 size = 0;
150 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
151 if (size)
153 name = HeapAlloc(GetProcessHeap(), 0, size);
154 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
155 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
157 HeapFree(GetProcessHeap(), 0, name);
158 name = NULL;
161 if (name)
163 HMODULE hLib = LoadLibraryW(providerPath);
165 if (hLib)
167 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
169 PF_NPGetCaps getCaps = MPR_GETPROC(NPGetCaps);
171 TRACE("loaded lib %p\n", hLib);
172 if (getCaps)
174 PWNetProvider provider =
175 &providerTable->table[providerTable->numProviders];
177 provider->hLib = hLib;
178 provider->name = name;
179 TRACE("name is %s\n", debugstr_w(name));
180 provider->getCaps = getCaps;
181 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
182 provider->dwNetType = getCaps(WNNC_NET_TYPE);
183 TRACE("net type is 0x%08x\n", provider->dwNetType);
184 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
185 if (provider->dwEnumScopes)
187 TRACE("supports enumeration\n");
188 provider->openEnum = MPR_GETPROC(NPOpenEnum);
189 TRACE("NPOpenEnum %p\n", provider->openEnum);
190 provider->enumResource = MPR_GETPROC(NPEnumResource);
191 TRACE("NPEnumResource %p\n", provider->enumResource);
192 provider->closeEnum = MPR_GETPROC(NPCloseEnum);
193 TRACE("NPCloseEnum %p\n", provider->closeEnum);
194 provider->getResourceInformation = MPR_GETPROC(NPGetResourceInformation);
195 TRACE("NPGetResourceInformation %p\n", provider->getResourceInformation);
196 if (!provider->openEnum ||
197 !provider->enumResource ||
198 !provider->closeEnum)
200 provider->openEnum = NULL;
201 provider->enumResource = NULL;
202 provider->closeEnum = NULL;
203 provider->dwEnumScopes = 0;
204 WARN("Couldn't load enumeration functions\n");
207 provider->addConnection = MPR_GETPROC(NPAddConnection);
208 provider->addConnection3 = MPR_GETPROC(NPAddConnection3);
209 TRACE("NPAddConnection %p\n", provider->addConnection);
210 TRACE("NPAddConnection3 %p\n", provider->addConnection3);
211 providerTable->numProviders++;
213 else
215 WARN("Provider %s didn't export NPGetCaps\n",
216 debugstr_w(provider));
217 HeapFree(GetProcessHeap(), 0, name);
218 FreeLibrary(hLib);
221 #undef MPR_GETPROC
223 else
225 WARN("Couldn't load library %s for provider %s\n",
226 debugstr_w(providerPath), debugstr_w(provider));
227 HeapFree(GetProcessHeap(), 0, name);
230 else
232 WARN("Couldn't get provider name for provider %s\n",
233 debugstr_w(provider));
236 else
237 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
238 RegCloseKey(hKey);
240 else
241 WARN("Couldn't open service key for provider %s\n",
242 debugstr_w(provider));
245 void wnetInit(HINSTANCE hInstDll)
247 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
248 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
249 'C','o','n','t','r','o','l','\\',
250 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
251 'O','r','d','e','r',0 };
252 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
253 'O','r','d','e','r',0 };
254 HKEY hKey;
256 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
257 == ERROR_SUCCESS)
259 DWORD size = 0;
261 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
262 if (size)
264 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
266 if (providers)
268 DWORD type;
270 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
271 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
273 PWSTR ptr;
274 DWORD numToAllocate;
276 TRACE("provider order is %s\n", debugstr_w(providers));
277 /* first count commas as a heuristic for how many to
278 * allocate space for */
279 for (ptr = providers, numToAllocate = 1; ptr; )
281 ptr = strchrW(ptr, ',');
282 if (ptr) {
283 numToAllocate++;
284 ptr++;
287 providerTable =
288 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
289 sizeof(WNetProviderTable)
290 + (numToAllocate - 1) * sizeof(WNetProvider));
291 if (providerTable)
293 PWSTR ptrPrev;
294 int entireNetworkLen;
295 LPCWSTR stringresource;
297 entireNetworkLen = LoadStringW(hInstDll,
298 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
299 providerTable->entireNetwork = HeapAlloc(
300 GetProcessHeap(), 0, (entireNetworkLen + 1) *
301 sizeof(WCHAR));
302 if (providerTable->entireNetwork)
304 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
305 providerTable->entireNetwork[entireNetworkLen] = 0;
307 providerTable->numAllocated = numToAllocate;
308 for (ptr = providers; ptr; )
310 ptrPrev = ptr;
311 ptr = strchrW(ptr, ',');
312 if (ptr)
313 *ptr++ = '\0';
314 _tryLoadProvider(ptrPrev);
318 HeapFree(GetProcessHeap(), 0, providers);
321 RegCloseKey(hKey);
325 void wnetFree(void)
327 if (providerTable)
329 DWORD i;
331 for (i = 0; i < providerTable->numProviders; i++)
333 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
334 FreeModule(providerTable->table[i].hLib);
336 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
337 HeapFree(GetProcessHeap(), 0, providerTable);
338 providerTable = NULL;
342 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
344 DWORD ret = BAD_PROVIDER_INDEX;
346 if (providerTable && providerTable->numProviders)
348 DWORD i;
350 for (i = 0; i < providerTable->numProviders &&
351 ret == BAD_PROVIDER_INDEX; i++)
352 if (!strcmpW(lpProvider, providerTable->table[i].name))
353 ret = i;
355 return ret;
359 * Browsing Functions
362 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
364 LPNETRESOURCEW ret;
366 if (lpNet)
368 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
369 if (ret)
371 size_t len;
373 *ret = *lpNet;
374 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
375 if (lpNet->lpRemoteName)
377 len = strlenW(lpNet->lpRemoteName) + 1;
378 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
379 if (ret->lpRemoteName)
380 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
384 else
385 ret = NULL;
386 return ret;
389 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
391 if (lpNet)
393 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
394 HeapFree(GetProcessHeap(), 0, lpNet);
398 static PWNetEnumerator _createNullEnumerator(void)
400 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
401 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
403 if (ret)
404 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
405 return ret;
408 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
409 DWORD dwUsage, LPNETRESOURCEW lpNet)
411 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
412 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
414 if (ret)
416 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
417 ret->dwScope = dwScope;
418 ret->dwType = dwType;
419 ret->dwUsage = dwUsage;
420 ret->lpNet = _copyNetResourceForEnumW(lpNet);
422 return ret;
425 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
426 DWORD dwUsage, DWORD index, HANDLE handle)
428 PWNetEnumerator ret;
430 if (!providerTable || index >= providerTable->numProviders)
431 ret = NULL;
432 else
434 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
435 if (ret)
437 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
438 ret->providerIndex = index;
439 ret->dwScope = dwScope;
440 ret->dwType = dwType;
441 ret->dwUsage = dwUsage;
442 ret->handle = handle;
445 return ret;
448 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
449 DWORD dwUsage)
451 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
452 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
454 if (ret)
456 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
457 ret->dwScope = dwScope;
458 ret->dwType = dwType;
459 ret->dwUsage = dwUsage;
461 return ret;
464 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
465 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
466 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
467 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
468 * if not all members of the array could be thunked, and something else on
469 * failure.
471 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
472 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
474 DWORD i, numToThunk, totalBytes, ret;
475 LPSTR strNext;
477 if (!lpNetArrayIn)
478 return WN_BAD_POINTER;
479 if (!lpcCount)
480 return WN_BAD_POINTER;
481 if (*lpcCount == -1)
482 return WN_BAD_VALUE;
483 if (!lpBuffer)
484 return WN_BAD_POINTER;
485 if (!lpBufferSize)
486 return WN_BAD_POINTER;
488 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
490 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
492 totalBytes += sizeof(NETRESOURCEA);
493 if (lpNet->lpLocalName)
494 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
495 -1, NULL, 0, NULL, NULL);
496 if (lpNet->lpRemoteName)
497 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
498 -1, NULL, 0, NULL, NULL);
499 if (lpNet->lpComment)
500 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
501 -1, NULL, 0, NULL, NULL);
502 if (lpNet->lpProvider)
503 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
504 -1, NULL, 0, NULL, NULL);
505 if (totalBytes < *lpBufferSize)
506 numToThunk = i + 1;
508 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
509 for (i = 0; i < numToThunk; i++)
511 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
512 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
514 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
515 /* lie about string lengths, we already verified how many
516 * we have space for above
518 if (lpNetIn->lpLocalName)
520 lpNetOut->lpLocalName = strNext;
521 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
522 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
524 if (lpNetIn->lpRemoteName)
526 lpNetOut->lpRemoteName = strNext;
527 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
528 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
530 if (lpNetIn->lpComment)
532 lpNetOut->lpComment = strNext;
533 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
534 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
536 if (lpNetIn->lpProvider)
538 lpNetOut->lpProvider = strNext;
539 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
540 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
543 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
544 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
545 *lpcCount, ret);
546 return ret;
549 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
550 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
551 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
552 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
553 * if not all members of the array could be thunked, and something else on
554 * failure.
556 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
557 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
559 DWORD i, numToThunk, totalBytes, ret;
560 LPWSTR strNext;
562 if (!lpNetArrayIn)
563 return WN_BAD_POINTER;
564 if (!lpcCount)
565 return WN_BAD_POINTER;
566 if (*lpcCount == -1)
567 return WN_BAD_VALUE;
568 if (!lpBuffer)
569 return WN_BAD_POINTER;
570 if (!lpBufferSize)
571 return WN_BAD_POINTER;
573 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
575 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
577 totalBytes += sizeof(NETRESOURCEW);
578 if (lpNet->lpLocalName)
579 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
580 -1, NULL, 0) * sizeof(WCHAR);
581 if (lpNet->lpRemoteName)
582 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
583 -1, NULL, 0) * sizeof(WCHAR);
584 if (lpNet->lpComment)
585 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
586 -1, NULL, 0) * sizeof(WCHAR);
587 if (lpNet->lpProvider)
588 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
589 -1, NULL, 0) * sizeof(WCHAR);
590 if (totalBytes < *lpBufferSize)
591 numToThunk = i + 1;
593 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
594 for (i = 0; i < numToThunk; i++)
596 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
597 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
599 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
600 /* lie about string lengths, we already verified how many
601 * we have space for above
603 if (lpNetIn->lpLocalName)
605 lpNetOut->lpLocalName = strNext;
606 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
607 -1, lpNetOut->lpLocalName, *lpBufferSize);
609 if (lpNetIn->lpRemoteName)
611 lpNetOut->lpRemoteName = strNext;
612 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
613 -1, lpNetOut->lpRemoteName, *lpBufferSize);
615 if (lpNetIn->lpComment)
617 lpNetOut->lpComment = strNext;
618 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
619 -1, lpNetOut->lpComment, *lpBufferSize);
621 if (lpNetIn->lpProvider)
623 lpNetOut->lpProvider = strNext;
624 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
625 -1, lpNetOut->lpProvider, *lpBufferSize);
628 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
629 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
630 *lpcCount, ret);
631 return ret;
634 /*********************************************************************
635 * WNetOpenEnumA [MPR.@]
637 * See comments for WNetOpenEnumW.
639 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
640 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
642 DWORD ret;
644 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
645 dwScope, dwType, dwUsage, lpNet, lphEnum );
647 if (!lphEnum)
648 ret = WN_BAD_POINTER;
649 else if (!providerTable || providerTable->numProviders == 0)
651 *lphEnum = NULL;
652 ret = WN_NO_NETWORK;
654 else
656 if (lpNet)
658 LPNETRESOURCEW lpNetWide = NULL;
659 BYTE buf[1024];
660 DWORD size = sizeof(buf), count = 1;
661 BOOL allocated = FALSE;
663 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
664 if (ret == WN_MORE_DATA)
666 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
667 size);
668 if (lpNetWide)
670 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
671 &size);
672 allocated = TRUE;
674 else
675 ret = WN_OUT_OF_MEMORY;
677 else if (ret == WN_SUCCESS)
678 lpNetWide = (LPNETRESOURCEW)buf;
679 if (ret == WN_SUCCESS)
680 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
681 lphEnum);
682 if (allocated)
683 HeapFree(GetProcessHeap(), 0, lpNetWide);
685 else
686 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
688 if (ret)
689 SetLastError(ret);
690 TRACE("Returning %d\n", ret);
691 return ret;
694 /*********************************************************************
695 * WNetOpenEnumW [MPR.@]
697 * Network enumeration has way too many parameters, so I'm not positive I got
698 * them right. What I've got so far:
700 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
701 * all the network providers should be enumerated.
703 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
704 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
705 * lpProvider is set, all the network providers should be enumerated.
706 * (This means the enumeration is a list of network providers, not that the
707 * enumeration is passed on to the providers.)
709 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
710 * resource matches the "Entire Network" resource (no remote name, no
711 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
712 * enumeration is done on every network provider.
714 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
715 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
716 * only to the given network provider.
718 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
719 * no lpProvider is set, enumeration will be tried on every network provider,
720 * in the order in which they're loaded.
722 * - The LPNETRESOURCE should be disregarded for scopes besides
723 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
724 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
726 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
727 * resource in the enumerated list, as well as any machines in your
728 * workgroup. The machines in your workgroup come from doing a
729 * RESOURCE_CONTEXT enumeration of every Network Provider.
731 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
732 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
734 DWORD ret;
736 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
737 dwScope, dwType, dwUsage, lpNet, lphEnum );
739 if (!lphEnum)
740 ret = WN_BAD_POINTER;
741 else if (!providerTable || providerTable->numProviders == 0)
743 *lphEnum = NULL;
744 ret = WN_NO_NETWORK;
746 else
748 switch (dwScope)
750 case RESOURCE_GLOBALNET:
751 if (lpNet)
753 if (lpNet->lpProvider)
755 DWORD index = _findProviderIndexW(lpNet->lpProvider);
757 if (index != BAD_PROVIDER_INDEX)
759 if (providerTable->table[index].openEnum &&
760 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
762 HANDLE handle;
763 PWSTR RemoteName = lpNet->lpRemoteName;
765 if ((lpNet->dwUsage & RESOURCEUSAGE_CONTAINER) &&
766 RemoteName && !strcmpW(RemoteName, lpNet->lpProvider))
767 lpNet->lpRemoteName = NULL;
769 ret = providerTable->table[index].openEnum(
770 dwScope, dwType, dwUsage, lpNet, &handle);
771 if (ret == WN_SUCCESS)
773 *lphEnum = _createProviderEnumerator(
774 dwScope, dwType, dwUsage, index, handle);
775 ret = *lphEnum ? WN_SUCCESS :
776 WN_OUT_OF_MEMORY;
779 lpNet->lpRemoteName = RemoteName;
781 else
782 ret = WN_NOT_SUPPORTED;
784 else
785 ret = WN_BAD_PROVIDER;
787 else if (lpNet->lpRemoteName)
789 *lphEnum = _createGlobalEnumeratorW(dwScope,
790 dwType, dwUsage, lpNet);
791 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
793 else
795 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
796 providerTable->entireNetwork))
798 /* comment matches the "Entire Network", enumerate
799 * global scope of every provider
801 *lphEnum = _createGlobalEnumeratorW(dwScope,
802 dwType, dwUsage, lpNet);
804 else
806 /* this is the same as not having passed lpNet */
807 *lphEnum = _createGlobalEnumeratorW(dwScope,
808 dwType, dwUsage, NULL);
810 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
813 else
815 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
816 dwUsage, lpNet);
817 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
819 break;
820 case RESOURCE_CONTEXT:
821 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
822 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
823 break;
824 case RESOURCE_REMEMBERED:
825 case RESOURCE_CONNECTED:
826 *lphEnum = _createNullEnumerator();
827 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
828 break;
829 default:
830 WARN("unknown scope 0x%08x\n", dwScope);
831 ret = WN_BAD_VALUE;
834 if (ret)
835 SetLastError(ret);
836 TRACE("Returning %d\n", ret);
837 return ret;
840 /*********************************************************************
841 * WNetEnumResourceA [MPR.@]
843 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
844 LPVOID lpBuffer, LPDWORD lpBufferSize )
846 DWORD ret;
848 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
850 if (!hEnum)
851 ret = WN_BAD_POINTER;
852 else if (!lpcCount)
853 ret = WN_BAD_POINTER;
854 else if (!lpBuffer)
855 ret = WN_BAD_POINTER;
856 else if (!lpBufferSize)
857 ret = WN_BAD_POINTER;
858 else if (*lpBufferSize < sizeof(NETRESOURCEA))
860 *lpBufferSize = sizeof(NETRESOURCEA);
861 ret = WN_MORE_DATA;
863 else
865 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
866 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
868 if (localBuffer)
870 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
871 &localSize);
872 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
874 /* FIXME: this isn't necessarily going to work in the case of
875 * WN_MORE_DATA, because our enumerator may have moved on to
876 * the next provider. MSDN states that a large (16KB) buffer
877 * size is the appropriate usage of this function, so
878 * hopefully it won't be an issue.
880 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
881 lpBuffer, lpBufferSize);
882 *lpcCount = localCount;
884 HeapFree(GetProcessHeap(), 0, localBuffer);
886 else
887 ret = WN_OUT_OF_MEMORY;
889 if (ret)
890 SetLastError(ret);
891 TRACE("Returning %d\n", ret);
892 return ret;
895 static DWORD _countProviderBytesW(PWNetProvider provider)
897 DWORD ret;
899 if (provider)
901 ret = sizeof(NETRESOURCEW);
902 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
904 else
905 ret = 0;
906 return ret;
909 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
910 LPVOID lpBuffer, const DWORD *lpBufferSize)
912 DWORD ret;
914 if (!enumerator)
915 return WN_BAD_POINTER;
916 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
917 return WN_BAD_VALUE;
918 if (!lpcCount)
919 return WN_BAD_POINTER;
920 if (!lpBuffer)
921 return WN_BAD_POINTER;
922 if (!lpBufferSize)
923 return WN_BAD_POINTER;
924 if (*lpBufferSize < sizeof(NETRESOURCEA))
925 return WN_MORE_DATA;
927 if (!providerTable || enumerator->providerIndex >=
928 providerTable->numProviders)
929 ret = WN_NO_MORE_ENTRIES;
930 else
932 DWORD bytes = 0, count = 0, countLimit, i;
933 LPNETRESOURCEW resource;
934 LPWSTR strNext;
936 countLimit = *lpcCount == -1 ?
937 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
938 while (count < countLimit && bytes < *lpBufferSize)
940 DWORD bytesNext = _countProviderBytesW(
941 &providerTable->table[count + enumerator->providerIndex]);
943 if (bytes + bytesNext < *lpBufferSize)
945 bytes += bytesNext;
946 count++;
949 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
950 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
952 resource->dwScope = RESOURCE_GLOBALNET;
953 resource->dwType = RESOURCETYPE_ANY;
954 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
955 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
956 RESOURCEUSAGE_RESERVED;
957 resource->lpLocalName = NULL;
958 resource->lpRemoteName = strNext;
959 strcpyW(resource->lpRemoteName,
960 providerTable->table[i + enumerator->providerIndex].name);
961 strNext += strlenW(resource->lpRemoteName) + 1;
962 resource->lpComment = NULL;
963 resource->lpProvider = strNext;
964 strcpyW(resource->lpProvider,
965 providerTable->table[i + enumerator->providerIndex].name);
966 strNext += strlenW(resource->lpProvider) + 1;
968 enumerator->providerIndex += count;
969 *lpcCount = count;
970 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
972 TRACE("Returning %d\n", ret);
973 return ret;
976 /* Advances the enumerator (assumed to be a global enumerator) to the next
977 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
978 * not open a handle with the next provider.
979 * If the existing handle is NULL, may leave the enumerator unchanged, since
980 * the current provider may support the desired scope.
981 * If the existing handle is not NULL, closes it before moving on.
982 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
983 * provider, and another error on failure.
985 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
987 if (!enumerator)
988 return WN_BAD_POINTER;
989 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
990 return WN_BAD_VALUE;
991 if (!providerTable || enumerator->providerIndex >=
992 providerTable->numProviders)
993 return WN_NO_MORE_ENTRIES;
995 if (enumerator->providerDone)
997 DWORD dwEnum = 0;
998 enumerator->providerDone = FALSE;
999 if (enumerator->handle)
1001 providerTable->table[enumerator->providerIndex].closeEnum(
1002 enumerator->handle);
1003 enumerator->handle = NULL;
1004 enumerator->providerIndex++;
1006 if (enumerator->dwScope == RESOURCE_CONNECTED)
1007 dwEnum = WNNC_ENUM_LOCAL;
1008 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
1009 dwEnum = WNNC_ENUM_GLOBAL;
1010 else if (enumerator->dwScope == RESOURCE_CONTEXT)
1011 dwEnum = WNNC_ENUM_CONTEXT;
1012 for (; enumerator->providerIndex < providerTable->numProviders &&
1013 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
1014 & dwEnum); enumerator->providerIndex++)
1017 return enumerator->providerIndex < providerTable->numProviders ?
1018 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1021 /* "Passes through" call to the next provider that supports the enumeration
1022 * type.
1023 * FIXME: if one call to a provider's enumerator succeeds while there's still
1024 * space in lpBuffer, I don't call to the next provider. The caller may not
1025 * expect that it should call EnumResourceW again with a return value of
1026 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1027 * may have to be moved around a bit, ick.
1029 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1030 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1032 DWORD ret;
1034 if (!enumerator)
1035 return WN_BAD_POINTER;
1036 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1037 return WN_BAD_VALUE;
1038 if (!lpcCount)
1039 return WN_BAD_POINTER;
1040 if (!lpBuffer)
1041 return WN_BAD_POINTER;
1042 if (!lpBufferSize)
1043 return WN_BAD_POINTER;
1044 if (*lpBufferSize < sizeof(NETRESOURCEW))
1045 return WN_MORE_DATA;
1047 ret = _globalEnumeratorAdvance(enumerator);
1048 if (ret == WN_SUCCESS)
1050 ret = providerTable->table[enumerator->providerIndex].
1051 openEnum(enumerator->dwScope, enumerator->dwType,
1052 enumerator->dwUsage, enumerator->lpNet,
1053 &enumerator->handle);
1054 if (ret == WN_SUCCESS)
1056 ret = providerTable->table[enumerator->providerIndex].
1057 enumResource(enumerator->handle, lpcCount, lpBuffer,
1058 lpBufferSize);
1059 if (ret != WN_MORE_DATA)
1060 enumerator->providerDone = TRUE;
1063 TRACE("Returning %d\n", ret);
1064 return ret;
1067 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1068 LPVOID lpBuffer, LPDWORD lpBufferSize)
1070 DWORD ret;
1072 if (!enumerator)
1073 return WN_BAD_POINTER;
1074 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1075 return WN_BAD_VALUE;
1076 if (!lpcCount)
1077 return WN_BAD_POINTER;
1078 if (!lpBuffer)
1079 return WN_BAD_POINTER;
1080 if (!lpBufferSize)
1081 return WN_BAD_POINTER;
1082 if (*lpBufferSize < sizeof(NETRESOURCEW))
1083 return WN_MORE_DATA;
1084 if (!providerTable)
1085 return WN_NO_NETWORK;
1087 switch (enumerator->dwScope)
1089 case RESOURCE_GLOBALNET:
1090 if (enumerator->lpNet)
1091 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1092 lpBuffer, lpBufferSize);
1093 else
1094 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1095 lpBufferSize);
1096 break;
1097 case RESOURCE_CONTEXT:
1098 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1099 lpBufferSize);
1100 break;
1101 default:
1102 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1103 ret = WN_NO_MORE_ENTRIES;
1105 TRACE("Returning %d\n", ret);
1106 return ret;
1109 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1110 LPVOID lpBuffer, LPDWORD lpBufferSize)
1112 if (!enumerator)
1113 return WN_BAD_POINTER;
1114 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1115 return WN_BAD_VALUE;
1116 if (!enumerator->handle)
1117 return WN_BAD_VALUE;
1118 if (!lpcCount)
1119 return WN_BAD_POINTER;
1120 if (!lpBuffer)
1121 return WN_BAD_POINTER;
1122 if (!lpBufferSize)
1123 return WN_BAD_POINTER;
1124 if (!providerTable)
1125 return WN_NO_NETWORK;
1126 if (enumerator->providerIndex >= providerTable->numProviders)
1127 return WN_NO_MORE_ENTRIES;
1128 if (!providerTable->table[enumerator->providerIndex].enumResource)
1129 return WN_BAD_VALUE;
1130 return providerTable->table[enumerator->providerIndex].enumResource(
1131 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1134 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1135 LPVOID lpBuffer, LPDWORD lpBufferSize)
1137 DWORD ret;
1138 size_t cchEntireNetworkLen, bytesNeeded;
1140 if (!enumerator)
1141 return WN_BAD_POINTER;
1142 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1143 return WN_BAD_VALUE;
1144 if (!lpcCount)
1145 return WN_BAD_POINTER;
1146 if (!lpBuffer)
1147 return WN_BAD_POINTER;
1148 if (!lpBufferSize)
1149 return WN_BAD_POINTER;
1150 if (!providerTable)
1151 return WN_NO_NETWORK;
1153 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1154 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1155 if (*lpBufferSize < bytesNeeded)
1157 *lpBufferSize = bytesNeeded;
1158 ret = WN_MORE_DATA;
1160 else
1162 LPNETRESOURCEW lpNet = lpBuffer;
1164 lpNet->dwScope = RESOURCE_GLOBALNET;
1165 lpNet->dwType = enumerator->dwType;
1166 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1167 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1168 lpNet->lpLocalName = NULL;
1169 lpNet->lpRemoteName = NULL;
1170 lpNet->lpProvider = NULL;
1171 /* odd, but correct: put comment at end of buffer, so it won't get
1172 * overwritten by subsequent calls to a provider's enumResource
1174 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1175 (cchEntireNetworkLen * sizeof(WCHAR)));
1176 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1177 ret = WN_SUCCESS;
1179 if (ret == WN_SUCCESS)
1181 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1183 /* "Entire Network" entry enumerated--morph this into a global
1184 * enumerator. enumerator->lpNet continues to be NULL, since it has
1185 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1187 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1188 ret = _enumerateGlobalW(enumerator, lpcCount,
1189 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1190 if (ret == WN_SUCCESS)
1192 /* reflect the fact that we already enumerated "Entire Network" */
1193 (*lpcCount)++;
1194 *lpBufferSize = bufferSize + bytesNeeded;
1196 else
1198 /* the provider enumeration failed, but we already succeeded in
1199 * enumerating "Entire Network"--leave type as global to allow a
1200 * retry, but indicate success with a count of one.
1202 ret = WN_SUCCESS;
1203 *lpcCount = 1;
1204 *lpBufferSize = bytesNeeded;
1207 TRACE("Returning %d\n", ret);
1208 return ret;
1211 /*********************************************************************
1212 * WNetEnumResourceW [MPR.@]
1214 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1215 LPVOID lpBuffer, LPDWORD lpBufferSize )
1217 DWORD ret;
1219 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1221 if (!hEnum)
1222 ret = WN_BAD_POINTER;
1223 else if (!lpcCount)
1224 ret = WN_BAD_POINTER;
1225 else if (!lpBuffer)
1226 ret = WN_BAD_POINTER;
1227 else if (!lpBufferSize)
1228 ret = WN_BAD_POINTER;
1229 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1231 *lpBufferSize = sizeof(NETRESOURCEW);
1232 ret = WN_MORE_DATA;
1234 else
1236 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1238 switch (enumerator->enumType)
1240 case WNET_ENUMERATOR_TYPE_NULL:
1241 ret = WN_NO_MORE_ENTRIES;
1242 break;
1243 case WNET_ENUMERATOR_TYPE_GLOBAL:
1244 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1245 lpBufferSize);
1246 break;
1247 case WNET_ENUMERATOR_TYPE_PROVIDER:
1248 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1249 lpBufferSize);
1250 break;
1251 case WNET_ENUMERATOR_TYPE_CONTEXT:
1252 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1253 lpBufferSize);
1254 break;
1255 default:
1256 WARN("bogus enumerator type!\n");
1257 ret = WN_NO_NETWORK;
1260 if (ret)
1261 SetLastError(ret);
1262 TRACE("Returning %d\n", ret);
1263 return ret;
1266 /*********************************************************************
1267 * WNetCloseEnum [MPR.@]
1269 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1271 DWORD ret;
1273 TRACE( "(%p)\n", hEnum );
1275 if (hEnum)
1277 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1279 switch (enumerator->enumType)
1281 case WNET_ENUMERATOR_TYPE_NULL:
1282 ret = WN_SUCCESS;
1283 break;
1284 case WNET_ENUMERATOR_TYPE_GLOBAL:
1285 if (enumerator->lpNet)
1286 _freeEnumNetResource(enumerator->lpNet);
1287 if (enumerator->handle)
1288 providerTable->table[enumerator->providerIndex].
1289 closeEnum(enumerator->handle);
1290 ret = WN_SUCCESS;
1291 break;
1292 case WNET_ENUMERATOR_TYPE_PROVIDER:
1293 if (enumerator->handle)
1294 providerTable->table[enumerator->providerIndex].
1295 closeEnum(enumerator->handle);
1296 ret = WN_SUCCESS;
1297 break;
1298 default:
1299 WARN("bogus enumerator type!\n");
1300 ret = WN_BAD_HANDLE;
1302 HeapFree(GetProcessHeap(), 0, hEnum);
1304 else
1305 ret = WN_BAD_HANDLE;
1306 if (ret)
1307 SetLastError(ret);
1308 TRACE("Returning %d\n", ret);
1309 return ret;
1312 /*********************************************************************
1313 * WNetGetResourceInformationA [MPR.@]
1315 * See WNetGetResourceInformationW
1317 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1318 LPVOID lpBuffer, LPDWORD cbBuffer,
1319 LPSTR *lplpSystem )
1321 DWORD ret;
1323 TRACE( "(%p, %p, %p, %p)\n",
1324 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1326 if (!providerTable || providerTable->numProviders == 0)
1327 ret = WN_NO_NETWORK;
1328 else if (lpNetResource)
1330 LPNETRESOURCEW lpNetResourceW = NULL;
1331 DWORD size = 1024, count = 1;
1332 DWORD len;
1334 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1335 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1336 if (ret == WN_MORE_DATA)
1338 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1339 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1340 if (lpNetResourceW)
1341 ret = _thunkNetResourceArrayAToW(lpNetResource,
1342 &count, lpNetResourceW, &size);
1343 else
1344 ret = WN_OUT_OF_MEMORY;
1346 if (ret == WN_SUCCESS)
1348 LPWSTR lpSystemW = NULL;
1349 LPVOID lpBufferW;
1350 size = 1024;
1351 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1352 if (lpBufferW)
1354 ret = WNetGetResourceInformationW(lpNetResourceW,
1355 lpBufferW, &size, &lpSystemW);
1356 if (ret == WN_MORE_DATA)
1358 HeapFree(GetProcessHeap(), 0, lpBufferW);
1359 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1360 if (lpBufferW)
1361 ret = WNetGetResourceInformationW(lpNetResourceW,
1362 lpBufferW, &size, &lpSystemW);
1363 else
1364 ret = WN_OUT_OF_MEMORY;
1366 if (ret == WN_SUCCESS)
1368 ret = _thunkNetResourceArrayWToA(lpBufferW,
1369 &count, lpBuffer, cbBuffer);
1370 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1371 lpNetResourceW = lpBufferW;
1372 size = sizeof(NETRESOURCEA);
1373 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1374 -1, NULL, 0, NULL, NULL);
1375 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1376 -1, NULL, 0, NULL, NULL);
1378 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1379 -1, NULL, 0, NULL, NULL);
1380 if ((len) && ( size + len < *cbBuffer))
1382 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1383 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1384 *lplpSystem, len, NULL, NULL);
1385 ret = WN_SUCCESS;
1387 else
1388 ret = WN_MORE_DATA;
1390 else
1391 ret = WN_OUT_OF_MEMORY;
1392 HeapFree(GetProcessHeap(), 0, lpBufferW);
1394 else
1395 ret = WN_OUT_OF_MEMORY;
1396 HeapFree(GetProcessHeap(), 0, lpSystemW);
1398 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1400 else
1401 ret = WN_NO_NETWORK;
1403 if (ret)
1404 SetLastError(ret);
1405 TRACE("Returning %d\n", ret);
1406 return ret;
1409 /*********************************************************************
1410 * WNetGetResourceInformationW [MPR.@]
1412 * WNetGetResourceInformationW function identifies the network provider
1413 * that owns the resource and gets information about the type of the resource.
1415 * PARAMS:
1416 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1417 * defines a network resource.
1418 * lpBuffer [ O] the pointer to buffer, containing result. It
1419 * contains NETRESOURCEW structure and strings to
1420 * which the members of the NETRESOURCEW structure
1421 * point.
1422 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1423 * in bytes.
1424 * lplpSystem [ O] the pointer to string in the output buffer,
1425 * containing the part of the resource name without
1426 * names of the server and share.
1428 * RETURNS:
1429 * NO_ERROR if the function succeeds. System error code if the function fails.
1432 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1433 LPVOID lpBuffer, LPDWORD cbBuffer,
1434 LPWSTR *lplpSystem )
1436 DWORD ret = WN_NO_NETWORK;
1437 DWORD index;
1439 TRACE( "(%p, %p, %p, %p)\n",
1440 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1442 if (!(lpBuffer))
1443 ret = WN_OUT_OF_MEMORY;
1444 else if (providerTable != NULL)
1446 /* FIXME: For function value of a variable is indifferent, it does
1447 * search of all providers in a network.
1449 for (index = 0; index < providerTable->numProviders; index++)
1451 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1452 WNNC_DLG_GETRESOURCEINFORMATION)
1454 if (providerTable->table[index].getResourceInformation)
1455 ret = providerTable->table[index].getResourceInformation(
1456 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1457 else
1458 ret = WN_NO_NETWORK;
1459 if (ret == WN_SUCCESS)
1460 break;
1464 if (ret)
1465 SetLastError(ret);
1466 return ret;
1469 /*********************************************************************
1470 * WNetGetResourceParentA [MPR.@]
1472 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1473 LPVOID lpBuffer, LPDWORD lpBufferSize )
1475 FIXME( "(%p, %p, %p): stub\n",
1476 lpNetResource, lpBuffer, lpBufferSize );
1478 SetLastError(WN_NO_NETWORK);
1479 return WN_NO_NETWORK;
1482 /*********************************************************************
1483 * WNetGetResourceParentW [MPR.@]
1485 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1486 LPVOID lpBuffer, LPDWORD lpBufferSize )
1488 FIXME( "(%p, %p, %p): stub\n",
1489 lpNetResource, lpBuffer, lpBufferSize );
1491 SetLastError(WN_NO_NETWORK);
1492 return WN_NO_NETWORK;
1498 * Connection Functions
1501 /*********************************************************************
1502 * WNetAddConnectionA [MPR.@]
1504 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1505 LPCSTR lpLocalName )
1507 NETRESOURCEA resourcesA;
1509 memset(&resourcesA, 0, sizeof(resourcesA));
1510 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1511 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1512 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1515 /*********************************************************************
1516 * WNetAddConnectionW [MPR.@]
1518 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1519 LPCWSTR lpLocalName )
1521 NETRESOURCEW resourcesW;
1523 memset(&resourcesW, 0, sizeof(resourcesW));
1524 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1525 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1526 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1529 /*********************************************************************
1530 * WNetAddConnection2A [MPR.@]
1532 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1533 LPCSTR lpPassword, LPCSTR lpUserID,
1534 DWORD dwFlags )
1536 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1537 NULL, 0, NULL);
1540 /*********************************************************************
1541 * WNetAddConnection2W [MPR.@]
1543 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1544 LPCWSTR lpPassword, LPCWSTR lpUserID,
1545 DWORD dwFlags )
1547 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1548 NULL, 0, NULL);
1551 /*********************************************************************
1552 * WNetAddConnection3A [MPR.@]
1554 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1555 LPCSTR lpPassword, LPCSTR lpUserID,
1556 DWORD dwFlags )
1558 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1559 dwFlags, NULL, 0, NULL);
1562 /*********************************************************************
1563 * WNetAddConnection3W [MPR.@]
1565 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1566 LPCWSTR lpPassword, LPCWSTR lpUserID,
1567 DWORD dwFlags )
1569 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1570 dwFlags, NULL, 0, NULL);
1573 struct use_connection_context
1575 HWND hwndOwner;
1576 NETRESOURCEW *resource;
1577 NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */
1578 WCHAR *password;
1579 WCHAR *userid;
1580 DWORD flags;
1581 void *accessname;
1582 DWORD *buffer_size;
1583 DWORD *result;
1584 DWORD (*pre_set_accessname)(struct use_connection_context*);
1585 void (*set_accessname)(struct use_connection_context*);
1588 static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt)
1590 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1592 DWORD len;
1594 if (ctxt->resource->lpLocalName)
1595 len = strlenW(ctxt->resource->lpLocalName);
1596 else
1597 len = strlenW(ctxt->resource->lpRemoteName);
1599 if (++len > *ctxt->buffer_size)
1601 *ctxt->buffer_size = len;
1602 return ERROR_MORE_DATA;
1605 else
1606 ctxt->accessname = NULL;
1608 return ERROR_SUCCESS;
1611 static void use_connection_set_accessnameW(struct use_connection_context *ctxt)
1613 WCHAR *accessname = ctxt->accessname;
1614 if (ctxt->resource->lpLocalName)
1615 strcpyW(accessname, ctxt->resource->lpLocalName);
1616 else
1617 strcpyW(accessname, ctxt->resource->lpRemoteName);
1620 static DWORD wnet_use_connection( struct use_connection_context *ctxt )
1622 WNetProvider *provider;
1623 DWORD index, ret, caps;
1625 if (!providerTable || providerTable->numProviders == 0)
1626 return WN_NO_NETWORK;
1628 if (!ctxt->resource)
1629 return ERROR_INVALID_PARAMETER;
1631 if (!ctxt->resource->lpProvider)
1633 FIXME("Networking provider selection is not implemented.\n");
1634 return WN_NO_NETWORK;
1637 if (!ctxt->resource->lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
1639 FIXME("Locale device selection is not implemented.\n");
1640 return WN_NO_NETWORK;
1643 if (ctxt->flags & CONNECT_INTERACTIVE)
1644 return ERROR_BAD_NET_NAME;
1646 index = _findProviderIndexW(ctxt->resource->lpProvider);
1647 if (index == BAD_PROVIDER_INDEX)
1648 return ERROR_BAD_PROVIDER;
1650 provider = &providerTable->table[index];
1651 caps = provider->getCaps(WNNC_CONNECTION);
1652 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1653 return ERROR_BAD_PROVIDER;
1655 if ((ret = ctxt->pre_set_accessname(ctxt)))
1656 return ret;
1658 ret = WN_ACCESS_DENIED;
1659 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1660 ret = provider->addConnection3(ctxt->hwndOwner, ctxt->resource, ctxt->password, ctxt->userid, ctxt->flags);
1661 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1662 ret = provider->addConnection(ctxt->resource, ctxt->password, ctxt->userid);
1664 if (ret == WN_SUCCESS && ctxt->accessname)
1665 ctxt->set_accessname(ctxt);
1667 return ret;
1670 /*****************************************************************
1671 * WNetUseConnectionW [MPR.@]
1673 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
1674 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
1676 struct use_connection_context ctxt;
1678 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1679 hwndOwner, resource, password, debugstr_w(userid), flags,
1680 accessname, buffer_size, result );
1682 ctxt.hwndOwner = hwndOwner;
1683 ctxt.resource = resource;
1684 ctxt.resourceA = NULL;
1685 ctxt.password = (WCHAR*)password;
1686 ctxt.userid = (WCHAR*)userid;
1687 ctxt.flags = flags;
1688 ctxt.accessname = accessname;
1689 ctxt.buffer_size = buffer_size;
1690 ctxt.result = result;
1691 ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
1692 ctxt.set_accessname = use_connection_set_accessnameW;
1694 return wnet_use_connection(&ctxt);
1697 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt)
1699 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1701 DWORD len;
1703 if (ctxt->resourceA->lpLocalName)
1704 len = strlen(ctxt->resourceA->lpLocalName);
1705 else
1706 len = strlen(ctxt->resourceA->lpRemoteName);
1708 if (++len > *ctxt->buffer_size)
1710 *ctxt->buffer_size = len;
1711 return ERROR_MORE_DATA;
1714 else
1715 ctxt->accessname = NULL;
1717 return ERROR_SUCCESS;
1720 static void use_connection_set_accessnameA(struct use_connection_context *ctxt)
1722 char *accessname = ctxt->accessname;
1723 if (ctxt->resourceA->lpLocalName)
1724 strcpy(accessname, ctxt->resourceA->lpLocalName);
1725 else
1726 strcpy(accessname, ctxt->resourceA->lpRemoteName);
1729 static LPWSTR strdupAtoW( LPCSTR str )
1731 LPWSTR ret;
1732 INT len;
1734 if (!str) return NULL;
1735 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
1736 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1737 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
1738 return ret;
1741 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
1743 resourceW->dwScope = resourceA->dwScope;
1744 resourceW->dwType = resourceA->dwType;
1745 resourceW->dwDisplayType = resourceA->dwDisplayType;
1746 resourceW->dwUsage = resourceA->dwUsage;
1747 resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
1748 resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
1749 resourceW->lpComment = strdupAtoW(resourceA->lpComment);
1750 resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
1753 static void free_netresourceW( NETRESOURCEW *resource )
1755 HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
1756 HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
1757 HeapFree(GetProcessHeap(), 0, resource->lpComment);
1758 HeapFree(GetProcessHeap(), 0, resource->lpProvider);
1761 /*****************************************************************
1762 * WNetUseConnectionA [MPR.@]
1764 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
1765 LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
1766 DWORD *buffer_size, DWORD *result )
1768 struct use_connection_context ctxt;
1769 NETRESOURCEW resourceW;
1770 DWORD ret;
1772 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
1773 accessname, buffer_size, result );
1775 netresource_a_to_w(resource, &resourceW);
1777 ctxt.hwndOwner = hwndOwner;
1778 ctxt.resource = &resourceW;
1779 ctxt.resourceA = resource;
1780 ctxt.password = strdupAtoW(password);
1781 ctxt.userid = strdupAtoW(userid);
1782 ctxt.flags = flags;
1783 ctxt.accessname = accessname;
1784 ctxt.buffer_size = buffer_size;
1785 ctxt.result = result;
1786 ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
1787 ctxt.set_accessname = use_connection_set_accessnameA;
1789 ret = wnet_use_connection(&ctxt);
1791 free_netresourceW(&resourceW);
1792 HeapFree(GetProcessHeap(), 0, ctxt.password);
1793 HeapFree(GetProcessHeap(), 0, ctxt.userid);
1795 return ret;
1798 /*********************************************************************
1799 * WNetCancelConnectionA [MPR.@]
1801 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1803 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1805 return WN_SUCCESS;
1808 /*********************************************************************
1809 * WNetCancelConnectionW [MPR.@]
1811 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1813 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1815 return WN_SUCCESS;
1818 /*********************************************************************
1819 * WNetCancelConnection2A [MPR.@]
1821 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1823 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1825 return WN_SUCCESS;
1828 /*********************************************************************
1829 * WNetCancelConnection2W [MPR.@]
1831 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1833 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1835 return WN_SUCCESS;
1838 /*****************************************************************
1839 * WNetRestoreConnectionA [MPR.@]
1841 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
1843 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1845 SetLastError(WN_NO_NETWORK);
1846 return WN_NO_NETWORK;
1849 /*****************************************************************
1850 * WNetRestoreConnectionW [MPR.@]
1852 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
1854 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1856 SetLastError(WN_NO_NETWORK);
1857 return WN_NO_NETWORK;
1860 /**************************************************************************
1861 * WNetGetConnectionA [MPR.@]
1863 * RETURNS
1864 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1865 * - WN_NOT_CONNECTED drive is a local drive
1866 * - WN_MORE_DATA buffer isn't big enough
1867 * - WN_SUCCESS success (net path in buffer)
1869 * FIXME: need to test return values under different errors
1871 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1872 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1874 DWORD ret;
1876 if (!lpLocalName)
1877 ret = WN_BAD_POINTER;
1878 else if (!lpBufferSize)
1879 ret = WN_BAD_POINTER;
1880 else if (!lpRemoteName && *lpBufferSize)
1881 ret = WN_BAD_POINTER;
1882 else
1884 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1886 if (len)
1888 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1890 if (wideLocalName)
1892 WCHAR wideRemoteStatic[MAX_PATH];
1893 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1895 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1897 /* try once without memory allocation */
1898 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1899 &wideRemoteSize);
1900 if (ret == WN_SUCCESS)
1902 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1903 -1, NULL, 0, NULL, NULL);
1905 if (len <= *lpBufferSize)
1907 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1908 lpRemoteName, *lpBufferSize, NULL, NULL);
1909 ret = WN_SUCCESS;
1911 else
1913 *lpBufferSize = len;
1914 ret = WN_MORE_DATA;
1917 else if (ret == WN_MORE_DATA)
1919 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1920 wideRemoteSize * sizeof(WCHAR));
1922 if (wideRemote)
1924 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1925 &wideRemoteSize);
1926 if (ret == WN_SUCCESS)
1928 if (len <= *lpBufferSize)
1930 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1931 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1932 ret = WN_SUCCESS;
1934 else
1936 *lpBufferSize = len;
1937 ret = WN_MORE_DATA;
1940 HeapFree(GetProcessHeap(), 0, wideRemote);
1942 else
1943 ret = WN_OUT_OF_MEMORY;
1945 HeapFree(GetProcessHeap(), 0, wideLocalName);
1947 else
1948 ret = WN_OUT_OF_MEMORY;
1950 else
1951 ret = WN_BAD_LOCALNAME;
1953 if (ret)
1954 SetLastError(ret);
1955 TRACE("Returning %d\n", ret);
1956 return ret;
1959 /* find the network connection for a given drive; helper for WNetGetConnection */
1960 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
1962 char buffer[1024];
1963 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
1964 HANDLE mgr;
1965 DWORD ret = WN_NOT_CONNECTED;
1966 DWORD bytes_returned;
1968 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
1969 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1970 0, 0 )) == INVALID_HANDLE_VALUE)
1972 ERR( "failed to open mount manager err %u\n", GetLastError() );
1973 return ret;
1975 memset( data, 0, sizeof(*data) );
1976 data->letter = letter;
1977 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
1978 data, sizeof(buffer), &bytes_returned, NULL ))
1980 char *p, *mount_point = buffer + data->mount_point_offset;
1981 DWORD len;
1983 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
1985 mount_point += 2;
1986 mount_point[0] = '\\';
1987 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
1989 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
1990 if (len > *size)
1992 *size = len;
1993 ret = WN_MORE_DATA;
1995 else
1997 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
1998 ret = WN_SUCCESS;
2002 CloseHandle( mgr );
2003 return ret;
2006 /**************************************************************************
2007 * WNetGetConnectionW [MPR.@]
2009 * FIXME: need to test return values under different errors
2011 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
2012 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
2014 DWORD ret;
2016 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
2017 lpBufferSize);
2019 if (!lpLocalName)
2020 ret = WN_BAD_POINTER;
2021 else if (!lpBufferSize)
2022 ret = WN_BAD_POINTER;
2023 else if (!lpRemoteName && *lpBufferSize)
2024 ret = WN_BAD_POINTER;
2025 else if (!lpLocalName[0])
2026 ret = WN_BAD_LOCALNAME;
2027 else
2029 if (lpLocalName[1] == ':')
2031 switch(GetDriveTypeW(lpLocalName))
2033 case DRIVE_REMOTE:
2034 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
2035 break;
2036 case DRIVE_REMOVABLE:
2037 case DRIVE_FIXED:
2038 case DRIVE_CDROM:
2039 TRACE("file is local\n");
2040 ret = WN_NOT_CONNECTED;
2041 break;
2042 default:
2043 ret = WN_BAD_LOCALNAME;
2046 else
2047 ret = WN_BAD_LOCALNAME;
2049 if (ret)
2050 SetLastError(ret);
2051 TRACE("Returning %d\n", ret);
2052 return ret;
2055 /**************************************************************************
2056 * WNetSetConnectionA [MPR.@]
2058 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
2059 LPVOID pvValue )
2061 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
2063 SetLastError(WN_NO_NETWORK);
2064 return WN_NO_NETWORK;
2067 /**************************************************************************
2068 * WNetSetConnectionW [MPR.@]
2070 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2071 LPVOID pvValue )
2073 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2075 SetLastError(WN_NO_NETWORK);
2076 return WN_NO_NETWORK;
2079 /*****************************************************************
2080 * WNetGetUniversalNameA [MPR.@]
2082 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2083 LPVOID lpBuffer, LPDWORD lpBufferSize )
2085 DWORD err, size;
2087 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2088 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2090 switch (dwInfoLevel)
2092 case UNIVERSAL_NAME_INFO_LEVEL:
2094 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2096 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2098 err = ERROR_NOT_CONNECTED;
2099 break;
2102 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2103 if (*lpBufferSize < size)
2105 err = WN_MORE_DATA;
2106 break;
2108 info->lpUniversalName = (char *)info + sizeof(*info);
2109 lstrcpyA(info->lpUniversalName, lpLocalPath);
2110 err = WN_NO_ERROR;
2111 break;
2113 case REMOTE_NAME_INFO_LEVEL:
2114 err = WN_NO_NETWORK;
2115 break;
2117 default:
2118 err = WN_BAD_VALUE;
2119 break;
2122 SetLastError(err);
2123 return err;
2126 /*****************************************************************
2127 * WNetGetUniversalNameW [MPR.@]
2129 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2130 LPVOID lpBuffer, LPDWORD lpBufferSize )
2132 DWORD err, size;
2134 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2135 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2137 switch (dwInfoLevel)
2139 case UNIVERSAL_NAME_INFO_LEVEL:
2141 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2143 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2145 err = ERROR_NOT_CONNECTED;
2146 break;
2149 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2150 if (*lpBufferSize < size)
2152 err = WN_MORE_DATA;
2153 break;
2155 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2156 lstrcpyW(info->lpUniversalName, lpLocalPath);
2157 err = WN_NO_ERROR;
2158 break;
2160 case REMOTE_NAME_INFO_LEVEL:
2161 err = WN_NO_NETWORK;
2162 break;
2164 default:
2165 err = WN_BAD_VALUE;
2166 break;
2169 if (err != WN_NO_ERROR) SetLastError(err);
2170 return err;
2176 * Other Functions
2179 /**************************************************************************
2180 * WNetGetUserA [MPR.@]
2182 * FIXME: we should not return ourselves, but the owner of the drive lpName
2184 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2186 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2187 return GetLastError();
2190 /*****************************************************************
2191 * WNetGetUserW [MPR.@]
2193 * FIXME: we should not return ourselves, but the owner of the drive lpName
2195 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2197 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2198 return GetLastError();
2201 /*********************************************************************
2202 * WNetConnectionDialog [MPR.@]
2204 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2206 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2208 SetLastError(WN_NO_NETWORK);
2209 return WN_NO_NETWORK;
2212 /*********************************************************************
2213 * WNetConnectionDialog1A [MPR.@]
2215 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2217 FIXME( "(%p): stub\n", lpConnDlgStruct );
2219 SetLastError(WN_NO_NETWORK);
2220 return WN_NO_NETWORK;
2223 /*********************************************************************
2224 * WNetConnectionDialog1W [MPR.@]
2226 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2228 FIXME( "(%p): stub\n", lpConnDlgStruct );
2230 SetLastError(WN_NO_NETWORK);
2231 return WN_NO_NETWORK;
2234 /*********************************************************************
2235 * WNetDisconnectDialog [MPR.@]
2237 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2239 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2241 SetLastError(WN_NO_NETWORK);
2242 return WN_NO_NETWORK;
2245 /*********************************************************************
2246 * WNetDisconnectDialog1A [MPR.@]
2248 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2250 FIXME( "(%p): stub\n", lpConnDlgStruct );
2252 SetLastError(WN_NO_NETWORK);
2253 return WN_NO_NETWORK;
2256 /*********************************************************************
2257 * WNetDisconnectDialog1W [MPR.@]
2259 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2261 FIXME( "(%p): stub\n", lpConnDlgStruct );
2263 SetLastError(WN_NO_NETWORK);
2264 return WN_NO_NETWORK;
2267 /*********************************************************************
2268 * WNetGetLastErrorA [MPR.@]
2270 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2271 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2272 LPSTR lpNameBuf, DWORD nNameBufSize )
2274 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2275 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2277 SetLastError(WN_NO_NETWORK);
2278 return WN_NO_NETWORK;
2281 /*********************************************************************
2282 * WNetGetLastErrorW [MPR.@]
2284 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2285 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2286 LPWSTR lpNameBuf, DWORD nNameBufSize )
2288 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2289 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2291 SetLastError(WN_NO_NETWORK);
2292 return WN_NO_NETWORK;
2295 /*********************************************************************
2296 * WNetGetNetworkInformationA [MPR.@]
2298 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2299 LPNETINFOSTRUCT lpNetInfoStruct )
2301 DWORD ret;
2303 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2305 if (!lpProvider)
2306 ret = WN_BAD_POINTER;
2307 else
2309 int len;
2311 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2312 if (len)
2314 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2316 if (wideProvider)
2318 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2319 len);
2320 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2321 HeapFree(GetProcessHeap(), 0, wideProvider);
2323 else
2324 ret = WN_OUT_OF_MEMORY;
2326 else
2327 ret = GetLastError();
2329 if (ret)
2330 SetLastError(ret);
2331 TRACE("Returning %d\n", ret);
2332 return ret;
2335 /*********************************************************************
2336 * WNetGetNetworkInformationW [MPR.@]
2338 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2339 LPNETINFOSTRUCT lpNetInfoStruct )
2341 DWORD ret;
2343 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2345 if (!lpProvider)
2346 ret = WN_BAD_POINTER;
2347 else if (!lpNetInfoStruct)
2348 ret = WN_BAD_POINTER;
2349 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2350 ret = WN_BAD_VALUE;
2351 else
2353 if (providerTable && providerTable->numProviders)
2355 DWORD providerIndex = _findProviderIndexW(lpProvider);
2357 if (providerIndex != BAD_PROVIDER_INDEX)
2359 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2360 lpNetInfoStruct->dwProviderVersion =
2361 providerTable->table[providerIndex].dwSpecVersion;
2362 lpNetInfoStruct->dwStatus = NO_ERROR;
2363 lpNetInfoStruct->dwCharacteristics = 0;
2364 lpNetInfoStruct->dwHandle = 0;
2365 lpNetInfoStruct->wNetType =
2366 HIWORD(providerTable->table[providerIndex].dwNetType);
2367 lpNetInfoStruct->dwPrinters = -1;
2368 lpNetInfoStruct->dwDrives = -1;
2369 ret = WN_SUCCESS;
2371 else
2372 ret = WN_BAD_PROVIDER;
2374 else
2375 ret = WN_NO_NETWORK;
2377 if (ret)
2378 SetLastError(ret);
2379 TRACE("Returning %d\n", ret);
2380 return ret;
2383 /*****************************************************************
2384 * WNetGetProviderNameA [MPR.@]
2386 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2387 LPSTR lpProvider, LPDWORD lpBufferSize )
2389 DWORD ret;
2391 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2392 lpBufferSize);
2394 if (!lpProvider)
2395 ret = WN_BAD_POINTER;
2396 else if (!lpBufferSize)
2397 ret = WN_BAD_POINTER;
2398 else
2400 if (providerTable)
2402 DWORD i;
2404 ret = WN_NO_NETWORK;
2405 for (i = 0; i < providerTable->numProviders &&
2406 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2407 i++)
2409 if (i < providerTable->numProviders)
2411 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2412 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2414 if (*lpBufferSize < sizeNeeded)
2416 *lpBufferSize = sizeNeeded;
2417 ret = WN_MORE_DATA;
2419 else
2421 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2422 -1, lpProvider, *lpBufferSize, NULL, NULL);
2423 ret = WN_SUCCESS;
2424 /* FIXME: is *lpBufferSize set to the number of characters
2425 * copied? */
2429 else
2430 ret = WN_NO_NETWORK;
2432 if (ret)
2433 SetLastError(ret);
2434 TRACE("Returning %d\n", ret);
2435 return ret;
2438 /*****************************************************************
2439 * WNetGetProviderNameW [MPR.@]
2441 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2442 LPWSTR lpProvider, LPDWORD lpBufferSize )
2444 DWORD ret;
2446 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2447 lpBufferSize);
2449 if (!lpProvider)
2450 ret = WN_BAD_POINTER;
2451 else if (!lpBufferSize)
2452 ret = WN_BAD_POINTER;
2453 else
2455 if (providerTable)
2457 DWORD i;
2459 ret = WN_NO_NETWORK;
2460 for (i = 0; i < providerTable->numProviders &&
2461 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2462 i++)
2464 if (i < providerTable->numProviders)
2466 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2468 if (*lpBufferSize < sizeNeeded)
2470 *lpBufferSize = sizeNeeded;
2471 ret = WN_MORE_DATA;
2473 else
2475 strcpyW(lpProvider, providerTable->table[i].name);
2476 ret = WN_SUCCESS;
2477 /* FIXME: is *lpBufferSize set to the number of characters
2478 * copied? */
2482 else
2483 ret = WN_NO_NETWORK;
2485 if (ret)
2486 SetLastError(ret);
2487 TRACE("Returning %d\n", ret);
2488 return ret;