Removed struct32.[ch].
[wine/multimedia.git] / dlls / mpr / wnet.c
blob25630309056ff26c2a8569d9e5834785207f4eb6
1 /*
2 * MPR WNet functions
4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winnls.h"
26 #include "winnetwk.h"
27 #include "npapi.h"
28 #include "winreg.h"
29 #include "winuser.h"
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
32 #include "mprres.h"
33 #include "wnetpriv.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(mpr);
37 /* Data structures representing network service providers. Assumes only one
38 * thread creates them, and that they are constant for the life of the process
39 * (and therefore doesn't synchronize access).
40 * FIXME: only basic provider data and enumeration-related data are implemented
41 * so far, need to implement the rest too.
43 typedef struct _WNetProvider
45 HMODULE hLib;
46 PWSTR name;
47 PF_NPGetCaps getCaps;
48 DWORD dwSpecVersion;
49 DWORD dwNetType;
50 DWORD dwEnumScopes;
51 PF_NPOpenEnum openEnum;
52 PF_NPEnumResource enumResource;
53 PF_NPCloseEnum closeEnum;
54 } WNetProvider, *PWNetProvider;
56 typedef struct _WNetProviderTable
58 LPWSTR entireNetwork;
59 DWORD numAllocated;
60 DWORD numProviders;
61 WNetProvider table[1];
62 } WNetProviderTable, *PWNetProviderTable;
64 #define WNET_ENUMERATOR_TYPE_NULL 0
65 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
66 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
67 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
69 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
70 * the enumeration; it represents one of the following types:
71 * - a 'null' enumeration, one that contains no members
72 * - a global enumeration, one that's executed across all providers
73 * - a provider-specific enumeration, one that's only executed by a single
74 * provider
75 * - a context enumeration. I know this contradicts what I just said about
76 * there being no correspondence between the scope and the type, but it's
77 * necessary for the special case that a "Entire Network" entry needs to
78 * be enumerated in an enumeration of the context scope. Thus an enumeration
79 * of the context scope results in a context type enumerator, which morphs
80 * into a global enumeration (so the enumeration continues across all
81 * providers).
83 typedef struct _WNetEnumerator
85 DWORD enumType;
86 DWORD providerIndex;
87 HANDLE handle;
88 BOOL providerDone;
89 DWORD dwScope;
90 DWORD dwType;
91 DWORD dwUsage;
92 LPNETRESOURCEW lpNet;
93 } WNetEnumerator, *PWNetEnumerator;
95 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
97 /* Returns an index (into the global WNetProviderTable) of the provider with
98 * the given name, or BAD_PROVIDER_INDEX if not found.
100 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
102 PWNetProviderTable providerTable;
105 * Global provider table functions
108 static void _tryLoadProvider(PCWSTR provider)
110 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
111 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
112 'S','e','r','v','i','c','e','s','\\',0 };
113 static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
114 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
115 WCHAR serviceName[MAX_PATH];
116 HKEY hKey;
118 TRACE("%s\n", debugstr_w(provider));
119 snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt,
120 servicePrefix, provider);
121 serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0';
122 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
123 ERROR_SUCCESS)
125 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
126 'P','a','t','h',0 };
127 WCHAR providerPath[MAX_PATH];
128 DWORD type, size = sizeof(providerPath);
130 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
131 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && type == REG_SZ)
133 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
134 PWSTR name = NULL;
136 size = 0;
137 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
138 if (size)
140 name = (PWSTR)HeapAlloc(GetProcessHeap(), 0, size);
141 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
142 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
144 HeapFree(GetProcessHeap(), 0, name);
145 name = NULL;
148 if (name)
150 HMODULE hLib = LoadLibraryW(providerPath);
152 if (hLib)
154 PF_NPGetCaps getCaps = (PF_NPGetCaps)GetProcAddress(hLib,
155 "NPGetCaps");
157 TRACE("loaded lib %p\n", hLib);
158 if (getCaps)
160 PWNetProvider provider =
161 &providerTable->table[providerTable->numProviders];
163 provider->hLib = hLib;
164 provider->name = name;
165 TRACE("name is %s\n", debugstr_w(name));
166 provider->getCaps = getCaps;
167 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
168 provider->dwNetType = getCaps(WNNC_NET_TYPE);
169 TRACE("net type is 0x%08lx\n", provider->dwNetType);
170 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
171 if (provider->dwEnumScopes)
173 TRACE("supports enumeration\n");
174 provider->openEnum = (PF_NPOpenEnum)
175 GetProcAddress(hLib, "NPOpenEnum");
176 TRACE("openEnum is %p\n", provider->openEnum);
177 provider->enumResource = (PF_NPEnumResource)
178 GetProcAddress(hLib, "NPEnumResource");
179 TRACE("enumResource is %p\n",
180 provider->enumResource);
181 provider->closeEnum = (PF_NPCloseEnum)
182 GetProcAddress(hLib, "NPCloseEnum");
183 TRACE("closeEnum is %p\n", provider->closeEnum);
184 if (!provider->openEnum || !provider->enumResource
185 || !provider->closeEnum)
187 provider->openEnum = NULL;
188 provider->enumResource = NULL;
189 provider->closeEnum = NULL;
190 provider->dwEnumScopes = 0;
191 WARN("Couldn't load enumeration functions\n");
194 providerTable->numProviders++;
196 else
198 WARN("Provider %s didn't export NPGetCaps\n",
199 debugstr_w(provider));
200 if (name)
201 HeapFree(GetProcessHeap(), 0, name);
202 FreeLibrary(hLib);
205 else
207 WARN("Couldn't load library %s for provider %s\n",
208 debugstr_w(providerPath), debugstr_w(provider));
209 HeapFree(GetProcessHeap(), 0, name);
212 else
214 WARN("Couldn't get provider name for provider %s\n",
215 debugstr_w(provider));
218 else
219 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
220 RegCloseKey(hKey);
222 else
223 WARN("Couldn't open service key for provider %s\n",
224 debugstr_w(provider));
227 void wnetInit(HINSTANCE hInstDll)
229 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
230 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
231 'C','o','n','t','r','o','l','\\',
232 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
233 'O','r','d','e','r',0 };
234 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
235 'O','r','d','e','r',0 };
236 HKEY hKey;
238 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
239 == ERROR_SUCCESS)
241 DWORD size = 0;
243 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
244 if (size)
246 PWSTR providers = (PWSTR)HeapAlloc(GetProcessHeap(), 0, size);
248 if (providers)
250 DWORD type;
252 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
253 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
255 PWSTR ptr;
256 DWORD numToAllocate;
258 TRACE("provider order is %s\n", debugstr_w(providers));
259 /* first count commas as a heuristic for how many to
260 * allocate space for */
261 for (ptr = providers, numToAllocate = 1; ptr; )
263 ptr = strchrW(ptr, ',');
264 if (ptr)
265 numToAllocate++;
267 providerTable = (PWNetProviderTable)
268 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
269 sizeof(WNetProviderTable)
270 + (numToAllocate - 1) * sizeof(WNetProvider));
271 if (providerTable)
273 PWSTR ptrPrev;
274 int entireNetworkLen;
276 entireNetworkLen = LoadStringW(hInstDll,
277 IDS_ENTIRENETWORK, NULL, 0);
278 providerTable->entireNetwork = (LPWSTR)HeapAlloc(
279 GetProcessHeap(), 0, (entireNetworkLen + 1) *
280 sizeof(WCHAR));
281 if (providerTable->entireNetwork)
282 LoadStringW(hInstDll, IDS_ENTIRENETWORK,
283 providerTable->entireNetwork,
284 entireNetworkLen + 1);
285 providerTable->numAllocated = numToAllocate;
286 for (ptr = providers; ptr; )
288 ptrPrev = ptr;
289 ptr = strchrW(ptr, ',');
290 if (ptr)
291 *ptr = '\0';
292 _tryLoadProvider(ptrPrev);
296 HeapFree(GetProcessHeap(), 0, providers);
299 RegCloseKey(hKey);
303 void wnetFree(void)
305 if (providerTable)
307 DWORD i;
309 for (i = 0; i < providerTable->numProviders; i++)
311 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
312 FreeModule(providerTable->table[i].hLib);
314 if (providerTable->entireNetwork)
315 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
316 HeapFree(GetProcessHeap(), 0, providerTable);
317 providerTable = NULL;
321 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
323 DWORD ret = BAD_PROVIDER_INDEX;
325 if (providerTable && providerTable->numProviders)
327 DWORD i;
329 for (i = 0; i < providerTable->numProviders &&
330 ret == BAD_PROVIDER_INDEX; i++)
331 if (!strcmpW(lpProvider, providerTable->table[i].name))
332 ret = i;
334 return ret;
338 * Browsing Functions
341 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
343 LPNETRESOURCEW ret;
345 if (lpNet)
347 ret = (LPNETRESOURCEW)HeapAlloc(GetProcessHeap(), 0,
348 sizeof(NETRESOURCEW));
349 if (ret)
351 size_t len;
353 memcpy(ret, lpNet, sizeof(ret));
354 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
355 if (lpNet->lpRemoteName)
357 len = strlenW(lpNet->lpRemoteName) + 1;
358 ret->lpRemoteName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
359 len * sizeof(WCHAR));
360 if (ret->lpRemoteName)
361 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
365 else
366 ret = NULL;
367 return ret;
370 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
372 if (lpNet)
374 if (lpNet->lpRemoteName)
375 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
376 HeapFree(GetProcessHeap(), 0, lpNet);
380 static PWNetEnumerator _createNullEnumerator(void)
382 PWNetEnumerator ret = (PWNetEnumerator)HeapAlloc(GetProcessHeap(),
383 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
385 if (ret)
386 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
387 return ret;
390 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
391 DWORD dwUsage, LPNETRESOURCEW lpNet)
393 PWNetEnumerator ret = (PWNetEnumerator)HeapAlloc(GetProcessHeap(),
394 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
396 if (ret)
398 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
399 ret->dwScope = dwScope;
400 ret->dwType = dwType;
401 ret->dwUsage = dwUsage;
402 ret->lpNet = _copyNetResourceForEnumW(lpNet);
404 return ret;
407 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
408 DWORD dwUsage, DWORD index, HANDLE handle)
410 PWNetEnumerator ret;
412 if (!providerTable || index >= providerTable->numProviders)
413 ret = NULL;
414 else
416 ret = (PWNetEnumerator)HeapAlloc(GetProcessHeap(),
417 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
418 if (ret)
420 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
421 ret->providerIndex = index;
422 ret->dwScope = dwScope;
423 ret->dwType = dwType;
424 ret->dwUsage = dwUsage;
425 ret->handle = handle;
428 return ret;
431 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
432 DWORD dwUsage)
434 PWNetEnumerator ret = (PWNetEnumerator)HeapAlloc(GetProcessHeap(),
435 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
437 if (ret)
439 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
440 ret->dwScope = dwScope;
441 ret->dwType = dwType;
442 ret->dwUsage = dwUsage;
444 return ret;
447 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
448 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
449 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
450 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
451 * if not all members of the array could be thunked, and something else on
452 * failure.
454 static DWORD _thunkNetResourceArrayWToA(const LPNETRESOURCEW lpNetArrayIn,
455 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
457 DWORD i, numToThunk, totalBytes, ret;
458 LPSTR strNext;
460 if (!lpNetArrayIn)
461 return WN_BAD_POINTER;
462 if (!lpcCount)
463 return WN_BAD_POINTER;
464 if (*lpcCount == -1)
465 return WN_BAD_VALUE;
466 if (!lpBuffer)
467 return WN_BAD_POINTER;
468 if (!lpBufferSize)
469 return WN_BAD_POINTER;
471 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
473 LPNETRESOURCEW lpNet = lpNetArrayIn + i;
475 totalBytes += sizeof(NETRESOURCEA);
476 if (lpNet->lpLocalName)
477 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
478 -1, NULL, 0, NULL, NULL);
479 if (lpNet->lpRemoteName)
480 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
481 -1, NULL, 0, NULL, NULL);
482 if (lpNet->lpComment)
483 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
484 -1, NULL, 0, NULL, NULL);
485 if (lpNet->lpProvider)
486 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
487 -1, NULL, 0, NULL, NULL);
488 if (totalBytes < *lpBufferSize)
489 numToThunk = i + 1;
491 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
492 for (i = 0; i < numToThunk; i++)
494 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
495 LPNETRESOURCEW lpNetIn = lpNetArrayIn + i;
497 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
498 /* lie about string lengths, we already verified how many
499 * we have space for above
501 if (lpNetIn->lpLocalName)
503 lpNetOut->lpLocalName = strNext;
504 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
505 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
507 if (lpNetIn->lpRemoteName)
509 lpNetOut->lpRemoteName = strNext;
510 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
511 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
513 if (lpNetIn->lpComment)
515 lpNetOut->lpComment = strNext;
516 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
517 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
519 if (lpNetIn->lpProvider)
521 lpNetOut->lpProvider = strNext;
522 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
523 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
526 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
527 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk,
528 *lpcCount, ret);
529 return ret;
532 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
533 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
534 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
535 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
536 * if not all members of the array could be thunked, and something else on
537 * failure.
539 static DWORD _thunkNetResourceArrayAToW(const LPNETRESOURCEA lpNetArrayIn,
540 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
542 DWORD i, numToThunk, totalBytes, ret;
543 LPWSTR strNext;
545 if (!lpNetArrayIn)
546 return WN_BAD_POINTER;
547 if (!lpcCount)
548 return WN_BAD_POINTER;
549 if (*lpcCount == -1)
550 return WN_BAD_VALUE;
551 if (!lpBuffer)
552 return WN_BAD_POINTER;
553 if (!lpBufferSize)
554 return WN_BAD_POINTER;
556 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
558 LPNETRESOURCEA lpNet = lpNetArrayIn + i;
560 totalBytes += sizeof(NETRESOURCEW);
561 if (lpNet->lpLocalName)
562 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
563 -1, NULL, 0) * sizeof(WCHAR);
564 if (lpNet->lpRemoteName)
565 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
566 -1, NULL, 0) * sizeof(WCHAR);
567 if (lpNet->lpComment)
568 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
569 -1, NULL, 0) * sizeof(WCHAR);
570 if (lpNet->lpProvider)
571 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
572 -1, NULL, 0) * sizeof(WCHAR);
573 if (totalBytes < *lpBufferSize)
574 numToThunk = i + 1;
576 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
577 for (i = 0; i < numToThunk; i++)
579 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
580 LPNETRESOURCEA lpNetIn = lpNetArrayIn + i;
582 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
583 /* lie about string lengths, we already verified how many
584 * we have space for above
586 if (lpNetIn->lpLocalName)
588 lpNetOut->lpLocalName = strNext;
589 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
590 -1, lpNetOut->lpLocalName, *lpBufferSize);
592 if (lpNetIn->lpRemoteName)
594 lpNetOut->lpRemoteName = strNext;
595 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
596 -1, lpNetOut->lpRemoteName, *lpBufferSize);
598 if (lpNetIn->lpComment)
600 lpNetOut->lpComment = strNext;
601 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
602 -1, lpNetOut->lpComment, *lpBufferSize);
604 if (lpNetIn->lpProvider)
606 lpNetOut->lpProvider = strNext;
607 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
608 -1, lpNetOut->lpProvider, *lpBufferSize);
611 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
612 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk,
613 *lpcCount, ret);
614 return ret;
617 /*********************************************************************
618 * WNetOpenEnumA [MPR.@]
620 * See comments for WNetOpenEnumW.
622 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
623 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
625 DWORD ret;
627 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
628 dwScope, dwType, dwUsage, lpNet, lphEnum );
630 if (!lphEnum)
631 ret = WN_BAD_POINTER;
632 else if (!providerTable || providerTable->numProviders == 0)
633 ret = WN_NO_NETWORK;
634 else
636 if (lpNet)
638 LPNETRESOURCEW lpNetWide = NULL;
639 BYTE buf[1024];
640 DWORD size = sizeof(buf), count = 1;
641 BOOL allocated = FALSE;
643 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
644 if (ret == WN_MORE_DATA)
646 lpNetWide = (LPNETRESOURCEW)HeapAlloc(GetProcessHeap(), 0,
647 size);
648 if (lpNetWide)
650 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
651 &size);
652 allocated = TRUE;
654 else
655 ret = WN_OUT_OF_MEMORY;
657 else if (ret == WN_SUCCESS)
658 lpNetWide = (LPNETRESOURCEW)buf;
659 if (ret == WN_SUCCESS)
660 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
661 lphEnum);
662 if (allocated && lpNetWide)
663 HeapFree(GetProcessHeap(), 0, lpNetWide);
665 else
666 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
668 if (ret)
669 SetLastError(ret);
670 TRACE("Returning %ld\n", ret);
671 return ret;
674 /*********************************************************************
675 * WNetOpenEnumW [MPR.@]
677 * Network enumeration has way too many parameters, so I'm not positive I got
678 * them right. What I've got so far:
680 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
681 * all the network providers should be enumerated.
683 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
684 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
685 * lpProvider is set, all the network providers should be enumerated.
686 * (This means the enumeration is a list of network providers, not that the
687 * enumeration is passed on to the providers.)
689 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
690 * resource matches the "Entire Network" resource (no remote name, no
691 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
692 * enumeration is done on every network provider.
694 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
695 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
696 * only to the given network provider.
698 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
699 * no lpProvider is set, enumeration will be tried on every network provider,
700 * in the order in which they're loaded.
702 * - The LPNETRESOURCE should be disregarded for scopes besides
703 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
704 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
706 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
707 * resource in the enumerated list, as well as any machines in your
708 * workgroup. The machines in your workgroup come from doing a
709 * RESOURCE_CONTEXT enumeration of every Network Provider.
711 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
712 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
714 DWORD ret;
716 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
717 dwScope, dwType, dwUsage, lpNet, lphEnum );
719 if (!lphEnum)
720 ret = WN_BAD_POINTER;
721 else if (!providerTable || providerTable->numProviders == 0)
722 ret = WN_NO_NETWORK;
723 else
725 switch (dwScope)
727 case RESOURCE_GLOBALNET:
728 if (lpNet)
730 if (lpNet->lpProvider)
732 DWORD index = _findProviderIndexW(lpNet->lpProvider);
734 if (index != BAD_PROVIDER_INDEX)
736 if (providerTable->table[index].openEnum &&
737 providerTable->table[index].dwEnumScopes & dwScope)
739 HANDLE handle;
741 ret = providerTable->table[index].openEnum(
742 dwScope, dwType, dwUsage, lpNet, &handle);
743 if (ret == WN_SUCCESS)
745 *lphEnum =
746 (HANDLE)_createProviderEnumerator(
747 dwScope, dwType, dwUsage, index, handle);
748 ret = *lphEnum ? WN_SUCCESS :
749 WN_OUT_OF_MEMORY;
752 else
753 ret = WN_NOT_SUPPORTED;
755 else
756 ret = WN_BAD_PROVIDER;
758 else if (lpNet->lpRemoteName)
760 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
761 dwType, dwUsage, lpNet);
762 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
764 else
766 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
767 providerTable->entireNetwork))
769 /* comment matches the "Entire Network", enumerate
770 * global scope of every provider
772 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
773 dwType, dwUsage, lpNet);
775 else
777 /* this is the same as not having passed lpNet */
778 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope,
779 dwType, dwUsage, NULL);
781 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
784 else
786 *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, dwType,
787 dwUsage, lpNet);
788 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
790 break;
791 case RESOURCE_CONTEXT:
792 *lphEnum = (HANDLE)_createContextEnumerator(dwScope, dwType,
793 dwUsage);
794 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
795 break;
796 case RESOURCE_REMEMBERED:
797 case RESOURCE_CONNECTED:
798 *lphEnum = (HANDLE)_createNullEnumerator();
799 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
800 break;
801 default:
802 WARN("unknown scope 0x%08lx\n", dwScope);
803 ret = WN_BAD_VALUE;
806 if (ret)
807 SetLastError(ret);
808 TRACE("Returning %ld\n", ret);
809 return ret;
812 /*********************************************************************
813 * WNetEnumResourceA [MPR.@]
815 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
816 LPVOID lpBuffer, LPDWORD lpBufferSize )
818 DWORD ret;
820 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
822 if (!hEnum)
823 ret = WN_BAD_POINTER;
824 else if (!lpcCount)
825 ret = WN_BAD_POINTER;
826 if (!lpBuffer)
827 ret = WN_BAD_POINTER;
828 else if (!lpBufferSize)
829 ret = WN_BAD_POINTER;
830 else if (*lpBufferSize < sizeof(NETRESOURCEA))
832 *lpBufferSize = sizeof(NETRESOURCEA);
833 ret = WN_MORE_DATA;
835 else
837 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
838 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
840 if (localBuffer)
842 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
843 &localSize);
844 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
846 /* FIXME: this isn't necessarily going to work in the case of
847 * WN_MORE_DATA, because our enumerator may have moved on to
848 * the next provider. MSDN states that a large (16KB) buffer
849 * size is the appropriate usage of this function, so
850 * hopefully it won't be an issue.
852 ret = _thunkNetResourceArrayWToA((LPNETRESOURCEW)localBuffer,
853 &localCount, lpBuffer, lpBufferSize);
854 *lpcCount = localCount;
856 HeapFree(GetProcessHeap(), 0, localBuffer);
858 else
859 ret = WN_OUT_OF_MEMORY;
861 if (ret)
862 SetLastError(ret);
863 TRACE("Returning %ld\n", ret);
864 return ret;
867 static DWORD _countProviderBytesW(PWNetProvider provider)
869 DWORD ret;
871 if (provider)
873 ret = sizeof(NETRESOURCEW);
874 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
876 else
877 ret = 0;
878 return ret;
881 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
882 LPVOID lpBuffer, LPDWORD lpBufferSize)
884 DWORD ret;
886 if (!enumerator)
887 return WN_BAD_POINTER;
888 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
889 return WN_BAD_VALUE;
890 if (!lpcCount)
891 return WN_BAD_POINTER;
892 if (!lpBuffer)
893 return WN_BAD_POINTER;
894 if (!lpBufferSize)
895 return WN_BAD_POINTER;
896 if (*lpBufferSize < sizeof(NETRESOURCEA))
897 return WN_MORE_DATA;
899 if (!providerTable || enumerator->providerIndex >=
900 providerTable->numProviders)
901 ret = WN_NO_MORE_ENTRIES;
902 else
904 DWORD bytes = 0, count = 0, countLimit, i;
905 LPNETRESOURCEW resource;
906 LPWSTR strNext;
908 countLimit = *lpcCount == -1 ?
909 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
910 while (count < countLimit && bytes < *lpBufferSize)
912 DWORD bytesNext = _countProviderBytesW(
913 &providerTable->table[count + enumerator->providerIndex]);
915 if (bytes + bytesNext < *lpBufferSize)
917 bytes += bytesNext;
918 count++;
921 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
922 for (i = 0, resource = (LPNETRESOURCEW)lpBuffer; i < count;
923 i++, resource++)
925 resource->dwScope = RESOURCE_GLOBALNET;
926 resource->dwType = RESOURCETYPE_ANY;
927 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
928 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
929 RESOURCEUSAGE_RESERVED;
930 resource->lpLocalName = NULL;
931 resource->lpRemoteName = strNext;
932 strcpyW(resource->lpRemoteName,
933 providerTable->table[i + enumerator->providerIndex].name);
934 strNext += strlenW(resource->lpRemoteName) + 1;
935 resource->lpComment = NULL;
936 resource->lpProvider = strNext;
937 strcpyW(resource->lpProvider,
938 providerTable->table[i + enumerator->providerIndex].name);
939 strNext += strlenW(resource->lpProvider) + 1;
941 enumerator->providerIndex += count;
942 *lpcCount = count;
943 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
945 TRACE("Returning %ld\n", ret);
946 return ret;
949 /* Advances the enumerator (assumed to be a global enumerator) to the next
950 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
951 * not open a handle with the next provider.
952 * If the existing handle is NULL, may leave the enumerator unchanged, since
953 * the current provider may support the desired scope.
954 * If the existing handle is not NULL, closes it before moving on.
955 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
956 * provider, and another error on failure.
958 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
960 if (!enumerator)
961 return WN_BAD_POINTER;
962 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
963 return WN_BAD_VALUE;
964 if (!providerTable || enumerator->providerIndex >=
965 providerTable->numProviders)
966 return WN_NO_MORE_ENTRIES;
968 if (enumerator->providerDone)
970 enumerator->providerDone = FALSE;
971 if (enumerator->handle)
973 providerTable->table[enumerator->providerIndex].closeEnum(
974 enumerator->handle);
975 enumerator->handle = NULL;
976 enumerator->providerIndex++;
978 for (; enumerator->providerIndex < providerTable->numProviders &&
979 !(enumerator->dwScope & providerTable->table
980 [enumerator->providerIndex].dwEnumScopes);
981 enumerator->providerIndex++)
984 return enumerator->providerIndex < providerTable->numProviders ?
985 WN_SUCCESS : WN_NO_MORE_ENTRIES;
988 /* "Passes through" call to the next provider that supports the enumeration
989 * type.
990 * FIXME: if one call to a provider's enumerator succeeds while there's still
991 * space in lpBuffer, I don't call to the next provider. The caller may not
992 * expect that it should call EnumResourceW again with a return value of
993 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
994 * may have to be moved around a bit, ick.
996 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
997 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
999 DWORD ret;
1001 if (!enumerator)
1002 return WN_BAD_POINTER;
1003 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1004 return WN_BAD_VALUE;
1005 if (!lpcCount)
1006 return WN_BAD_POINTER;
1007 if (!lpBuffer)
1008 return WN_BAD_POINTER;
1009 if (!lpBufferSize)
1010 return WN_BAD_POINTER;
1011 if (*lpBufferSize < sizeof(NETRESOURCEW))
1012 return WN_MORE_DATA;
1014 ret = _globalEnumeratorAdvance(enumerator);
1015 if (ret == WN_SUCCESS)
1017 ret = providerTable->table[enumerator->providerIndex].
1018 openEnum(enumerator->dwScope, enumerator->dwType,
1019 enumerator->dwUsage, enumerator->lpNet,
1020 &enumerator->handle);
1021 if (ret == WN_SUCCESS)
1023 ret = providerTable->table[enumerator->providerIndex].
1024 enumResource(enumerator->handle, lpcCount, lpBuffer,
1025 lpBufferSize);
1026 if (ret != WN_MORE_DATA)
1027 enumerator->providerDone = TRUE;
1030 TRACE("Returning %ld\n", ret);
1031 return ret;
1034 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1035 LPVOID lpBuffer, LPDWORD lpBufferSize)
1037 DWORD ret;
1039 if (!enumerator)
1040 return WN_BAD_POINTER;
1041 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1042 return WN_BAD_VALUE;
1043 if (!lpcCount)
1044 return WN_BAD_POINTER;
1045 if (!lpBuffer)
1046 return WN_BAD_POINTER;
1047 if (!lpBufferSize)
1048 return WN_BAD_POINTER;
1049 if (*lpBufferSize < sizeof(NETRESOURCEW))
1050 return WN_MORE_DATA;
1051 if (!providerTable)
1052 return WN_NO_NETWORK;
1054 switch (enumerator->dwScope)
1056 case RESOURCE_GLOBALNET:
1057 if (enumerator->lpNet)
1058 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1059 lpBuffer, lpBufferSize);
1060 else
1061 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1062 lpBufferSize);
1063 break;
1064 case RESOURCE_CONTEXT:
1065 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1066 lpBufferSize);
1067 break;
1068 default:
1069 WARN("unexpected scope 0x%08lx\n", enumerator->dwScope);
1070 ret = WN_NO_MORE_ENTRIES;
1072 TRACE("Returning %ld\n", ret);
1073 return ret;
1076 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1077 LPVOID lpBuffer, LPDWORD lpBufferSize)
1079 if (!enumerator)
1080 return WN_BAD_POINTER;
1081 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1082 return WN_BAD_VALUE;
1083 if (!enumerator->handle)
1084 return WN_BAD_VALUE;
1085 if (!lpcCount)
1086 return WN_BAD_POINTER;
1087 if (!lpBuffer)
1088 return WN_BAD_POINTER;
1089 if (!lpBufferSize)
1090 return WN_BAD_POINTER;
1091 if (!providerTable)
1092 return WN_NO_NETWORK;
1093 if (enumerator->providerIndex >= providerTable->numProviders)
1094 return WN_NO_MORE_ENTRIES;
1095 if (!providerTable->table[enumerator->providerIndex].enumResource)
1096 return WN_BAD_VALUE;
1097 return providerTable->table[enumerator->providerIndex].enumResource(
1098 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1101 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1102 LPVOID lpBuffer, LPDWORD lpBufferSize)
1104 DWORD ret;
1105 size_t cchEntireNetworkLen, bytesNeeded;
1107 if (!enumerator)
1108 return WN_BAD_POINTER;
1109 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1110 return WN_BAD_VALUE;
1111 if (!lpcCount)
1112 return WN_BAD_POINTER;
1113 if (!lpBuffer)
1114 return WN_BAD_POINTER;
1115 if (!lpBufferSize)
1116 return WN_BAD_POINTER;
1117 if (!providerTable)
1118 return WN_NO_NETWORK;
1120 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1121 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1122 if (*lpBufferSize < bytesNeeded)
1124 *lpBufferSize = bytesNeeded;
1125 ret = WN_MORE_DATA;
1127 else
1129 LPNETRESOURCEW lpNet = (LPNETRESOURCEW)lpBuffer;
1131 lpNet->dwScope = RESOURCE_GLOBALNET;
1132 lpNet->dwType = enumerator->dwType;
1133 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1134 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1135 lpNet->lpLocalName = NULL;
1136 lpNet->lpRemoteName = NULL;
1137 lpNet->lpProvider = NULL;
1138 /* odd, but correct: put comment at end of buffer, so it won't get
1139 * overwritten by subsequent calls to a provider's enumResource
1141 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1142 (cchEntireNetworkLen * sizeof(WCHAR)));
1143 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1144 ret = WN_SUCCESS;
1146 if (ret == WN_SUCCESS)
1148 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1150 /* "Entire Network" entry enumerated--morph this into a global
1151 * enumerator. enumerator->lpNet continues to be NULL, since it has
1152 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1154 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1155 ret = _enumerateGlobalW(enumerator, lpcCount,
1156 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1157 if (ret == WN_SUCCESS)
1159 /* reflect the fact that we already enumerated "Entire Network" */
1160 lpcCount++;
1161 *lpBufferSize = bufferSize + bytesNeeded;
1163 else
1165 /* the provider enumeration failed, but we already succeeded in
1166 * enumerating "Entire Network"--leave type as global to allow a
1167 * retry, but indicate success with a count of one.
1169 ret = WN_SUCCESS;
1170 *lpcCount = 1;
1171 *lpBufferSize = bytesNeeded;
1174 TRACE("Returning %ld\n", ret);
1175 return ret;
1178 /*********************************************************************
1179 * WNetEnumResourceW [MPR.@]
1181 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1182 LPVOID lpBuffer, LPDWORD lpBufferSize )
1184 DWORD ret;
1186 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1188 if (!hEnum)
1189 ret = WN_BAD_POINTER;
1190 else if (!lpcCount)
1191 ret = WN_BAD_POINTER;
1192 else if (!lpBuffer)
1193 ret = WN_BAD_POINTER;
1194 else if (!lpBufferSize)
1195 ret = WN_BAD_POINTER;
1196 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1198 *lpBufferSize = sizeof(NETRESOURCEW);
1199 ret = WN_MORE_DATA;
1201 else
1203 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1205 switch (enumerator->enumType)
1207 case WNET_ENUMERATOR_TYPE_NULL:
1208 ret = WN_NO_MORE_ENTRIES;
1209 break;
1210 case WNET_ENUMERATOR_TYPE_GLOBAL:
1211 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1212 lpBufferSize);
1213 break;
1214 case WNET_ENUMERATOR_TYPE_PROVIDER:
1215 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1216 lpBufferSize);
1217 break;
1218 case WNET_ENUMERATOR_TYPE_CONTEXT:
1219 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1220 lpBufferSize);
1221 break;
1222 default:
1223 WARN("bogus enumerator type!\n");
1224 ret = WN_NO_NETWORK;
1227 if (ret)
1228 SetLastError(ret);
1229 TRACE("Returning %ld\n", ret);
1230 return ret;
1233 /*********************************************************************
1234 * WNetCloseEnum [MPR.@]
1236 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1238 DWORD ret;
1240 TRACE( "(%p)\n", hEnum );
1242 if (hEnum)
1244 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1246 switch (enumerator->enumType)
1248 case WNET_ENUMERATOR_TYPE_NULL:
1249 ret = WN_SUCCESS;
1250 break;
1251 case WNET_ENUMERATOR_TYPE_GLOBAL:
1252 if (enumerator->lpNet)
1253 _freeEnumNetResource(enumerator->lpNet);
1254 if (enumerator->handle)
1255 providerTable->table[enumerator->providerIndex].
1256 closeEnum(enumerator->handle);
1257 ret = WN_SUCCESS;
1258 break;
1259 case WNET_ENUMERATOR_TYPE_PROVIDER:
1260 if (enumerator->handle)
1261 providerTable->table[enumerator->providerIndex].
1262 closeEnum(enumerator->handle);
1263 ret = WN_SUCCESS;
1264 break;
1265 default:
1266 WARN("bogus enumerator type!\n");
1267 ret = WN_BAD_HANDLE;
1269 HeapFree(GetProcessHeap(), 0, hEnum);
1271 else
1272 ret = WN_BAD_HANDLE;
1273 if (ret)
1274 SetLastError(ret);
1275 TRACE("Returning %ld\n", ret);
1276 return ret;
1279 /*********************************************************************
1280 * WNetGetResourceInformationA [MPR.@]
1282 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1283 LPVOID lpBuffer, LPDWORD cbBuffer,
1284 LPSTR *lplpSystem )
1286 FIXME( "(%p, %p, %p, %p): stub\n",
1287 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1289 SetLastError(WN_NO_NETWORK);
1290 return WN_NO_NETWORK;
1293 /*********************************************************************
1294 * WNetGetResourceInformationW [MPR.@]
1296 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1297 LPVOID lpBuffer, LPDWORD cbBuffer,
1298 LPWSTR *lplpSystem )
1300 FIXME( "(%p, %p, %p, %p): stub\n",
1301 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1303 SetLastError(WN_NO_NETWORK);
1304 return WN_NO_NETWORK;
1307 /*********************************************************************
1308 * WNetGetResourceParentA [MPR.@]
1310 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1311 LPVOID lpBuffer, LPDWORD lpBufferSize )
1313 FIXME( "(%p, %p, %p): stub\n",
1314 lpNetResource, lpBuffer, lpBufferSize );
1316 SetLastError(WN_NO_NETWORK);
1317 return WN_NO_NETWORK;
1320 /*********************************************************************
1321 * WNetGetResourceParentW [MPR.@]
1323 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1324 LPVOID lpBuffer, LPDWORD lpBufferSize )
1326 FIXME( "(%p, %p, %p): stub\n",
1327 lpNetResource, lpBuffer, lpBufferSize );
1329 SetLastError(WN_NO_NETWORK);
1330 return WN_NO_NETWORK;
1336 * Connection Functions
1339 /*********************************************************************
1340 * WNetAddConnectionA [MPR.@]
1342 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1343 LPCSTR lpLocalName )
1345 FIXME( "(%s, %p, %s): stub\n",
1346 debugstr_a(lpRemoteName), lpPassword, debugstr_a(lpLocalName) );
1348 SetLastError(WN_NO_NETWORK);
1349 return WN_NO_NETWORK;
1352 /*********************************************************************
1353 * WNetAddConnectionW [MPR.@]
1355 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1356 LPCWSTR lpLocalName )
1358 FIXME( "(%s, %p, %s): stub\n",
1359 debugstr_w(lpRemoteName), lpPassword, debugstr_w(lpLocalName) );
1361 SetLastError(WN_NO_NETWORK);
1362 return WN_NO_NETWORK;
1365 /*********************************************************************
1366 * WNetAddConnection2A [MPR.@]
1368 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1369 LPCSTR lpPassword, LPCSTR lpUserID,
1370 DWORD dwFlags )
1372 FIXME( "(%p, %p, %s, 0x%08lX): stub\n",
1373 lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1375 SetLastError(WN_NO_NETWORK);
1376 return WN_NO_NETWORK;
1379 /*********************************************************************
1380 * WNetAddConnection2W [MPR.@]
1382 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1383 LPCWSTR lpPassword, LPCWSTR lpUserID,
1384 DWORD dwFlags )
1386 FIXME( "(%p, %p, %s, 0x%08lX): stub\n",
1387 lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1389 SetLastError(WN_NO_NETWORK);
1390 return WN_NO_NETWORK;
1393 /*********************************************************************
1394 * WNetAddConnection3A [MPR.@]
1396 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1397 LPCSTR lpPassword, LPCSTR lpUserID,
1398 DWORD dwFlags )
1400 FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n",
1401 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1403 SetLastError(WN_NO_NETWORK);
1404 return WN_NO_NETWORK;
1407 /*********************************************************************
1408 * WNetAddConnection3W [MPR.@]
1410 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1411 LPCWSTR lpPassword, LPCWSTR lpUserID,
1412 DWORD dwFlags )
1414 FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n",
1415 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1417 SetLastError(WN_NO_NETWORK);
1418 return WN_NO_NETWORK;
1421 /*****************************************************************
1422 * WNetUseConnectionA [MPR.@]
1424 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1425 LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
1426 LPSTR lpAccessName, LPDWORD lpBufferSize,
1427 LPDWORD lpResult )
1429 FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n",
1430 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags,
1431 debugstr_a(lpAccessName), lpBufferSize, lpResult );
1433 SetLastError(WN_NO_NETWORK);
1434 return WN_NO_NETWORK;
1437 /*****************************************************************
1438 * WNetUseConnectionW [MPR.@]
1440 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1441 LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags,
1442 LPWSTR lpAccessName, LPDWORD lpBufferSize,
1443 LPDWORD lpResult )
1445 FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n",
1446 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags,
1447 debugstr_w(lpAccessName), lpBufferSize, lpResult );
1449 SetLastError(WN_NO_NETWORK);
1450 return WN_NO_NETWORK;
1453 /*********************************************************************
1454 * WNetCancelConnectionA [MPR.@]
1456 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1458 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1460 return WN_SUCCESS;
1463 /*********************************************************************
1464 * WNetCancelConnectionW [MPR.@]
1466 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1468 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1470 return WN_SUCCESS;
1473 /*********************************************************************
1474 * WNetCancelConnection2A [MPR.@]
1476 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1478 FIXME( "(%s, %08lX, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1480 return WN_SUCCESS;
1483 /*********************************************************************
1484 * WNetCancelConnection2W [MPR.@]
1486 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1488 FIXME( "(%s, %08lX, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1490 return WN_SUCCESS;
1493 /*****************************************************************
1494 * WNetRestoreConnectionA [MPR.@]
1496 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPSTR lpszDevice )
1498 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1500 SetLastError(WN_NO_NETWORK);
1501 return WN_NO_NETWORK;
1504 /*****************************************************************
1505 * WNetRestoreConnectionW [MPR.@]
1507 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPWSTR lpszDevice )
1509 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1511 SetLastError(WN_NO_NETWORK);
1512 return WN_NO_NETWORK;
1515 /**************************************************************************
1516 * WNetGetConnectionA [MPR.@]
1518 * RETURNS
1519 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1520 * - WN_NOT_CONNECTED drive is a local drive
1521 * - WN_MORE_DATA buffer isn't big enough
1522 * - WN_SUCCESS success (net path in buffer)
1524 * FIXME: need to test return values under different errors
1526 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1527 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1529 DWORD ret;
1531 if (!lpLocalName)
1532 ret = WN_BAD_POINTER;
1533 else if (!lpRemoteName)
1534 ret = WN_BAD_POINTER;
1535 else if (!lpBufferSize)
1536 ret = WN_BAD_POINTER;
1537 else
1539 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1541 if (len)
1543 PWSTR wideLocalName = (PWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1545 if (wideLocalName)
1547 WCHAR wideRemoteStatic[MAX_PATH];
1548 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1550 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1552 /* try once without memory allocation */
1553 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1554 &wideRemoteSize);
1555 if (ret == WN_SUCCESS)
1557 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1558 -1, NULL, 0, NULL, NULL);
1560 if (len <= *lpBufferSize)
1562 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1563 lpRemoteName, *lpBufferSize, NULL, NULL);
1564 ret = WN_SUCCESS;
1566 else
1568 *lpBufferSize = len;
1569 ret = WN_MORE_DATA;
1572 else if (ret == WN_MORE_DATA)
1574 PWSTR wideRemote = (PWSTR)HeapAlloc(GetProcessHeap(), 0,
1575 wideRemoteSize * sizeof(WCHAR));
1577 if (wideRemote)
1579 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1580 &wideRemoteSize);
1581 if (ret == WN_SUCCESS)
1583 if (len <= *lpBufferSize)
1585 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1586 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1587 ret = WN_SUCCESS;
1589 else
1591 *lpBufferSize = len;
1592 ret = WN_MORE_DATA;
1595 HeapFree(GetProcessHeap(), 0, wideRemote);
1597 else
1598 ret = WN_OUT_OF_MEMORY;
1600 HeapFree(GetProcessHeap(), 0, wideLocalName);
1602 else
1603 ret = WN_OUT_OF_MEMORY;
1605 else
1606 ret = WN_BAD_LOCALNAME;
1608 if (ret)
1609 SetLastError(ret);
1610 TRACE("Returning %ld\n", ret);
1611 return ret;
1614 /**************************************************************************
1615 * WNetGetConnectionW [MPR.@]
1617 * FIXME: need to test return values under different errors
1619 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
1620 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
1622 DWORD ret;
1624 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
1625 lpBufferSize);
1627 if (!lpLocalName)
1628 ret = WN_BAD_POINTER;
1629 else if (!lpRemoteName)
1630 ret = WN_BAD_POINTER;
1631 else if (!lpBufferSize)
1632 ret = WN_BAD_POINTER;
1633 else if (!lpLocalName[0])
1634 ret = WN_BAD_LOCALNAME;
1635 else
1637 if (lpLocalName[1] == ':')
1639 switch(GetDriveTypeW(lpLocalName))
1641 case DRIVE_REMOTE:
1643 WCHAR remote[MAX_PATH];
1644 if (!QueryDosDeviceW( lpLocalName, remote, MAX_PATH )) remote[0] = 0;
1645 if (strlenW(remote) + 1 > *lpBufferSize)
1647 *lpBufferSize = strlenW(remote) + 1;
1648 ret = WN_MORE_DATA;
1650 else
1652 strcpyW( lpRemoteName, remote );
1653 *lpBufferSize = strlenW(lpRemoteName) + 1;
1654 ret = WN_SUCCESS;
1656 break;
1658 case DRIVE_REMOVABLE:
1659 case DRIVE_FIXED:
1660 case DRIVE_CDROM:
1661 TRACE("file is local\n");
1662 ret = WN_NOT_CONNECTED;
1663 break;
1664 default:
1665 ret = WN_BAD_LOCALNAME;
1668 else
1669 ret = WN_BAD_LOCALNAME;
1671 if (ret)
1672 SetLastError(ret);
1673 TRACE("Returning %ld\n", ret);
1674 return ret;
1677 /**************************************************************************
1678 * WNetSetConnectionA [MPR.@]
1680 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
1681 LPVOID pvValue )
1683 FIXME( "(%s, %08lX, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
1685 SetLastError(WN_NO_NETWORK);
1686 return WN_NO_NETWORK;
1689 /**************************************************************************
1690 * WNetSetConnectionW [MPR.@]
1692 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
1693 LPVOID pvValue )
1695 FIXME( "(%s, %08lX, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
1697 SetLastError(WN_NO_NETWORK);
1698 return WN_NO_NETWORK;
1701 /*****************************************************************
1702 * WNetGetUniversalNameA [MPR.@]
1704 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
1705 LPVOID lpBuffer, LPDWORD lpBufferSize )
1707 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
1708 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1710 SetLastError(WN_NO_NETWORK);
1711 return WN_NO_NETWORK;
1714 /*****************************************************************
1715 * WNetGetUniversalNameW [MPR.@]
1717 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
1718 LPVOID lpBuffer, LPDWORD lpBufferSize )
1720 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
1721 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1723 SetLastError(WN_NO_NETWORK);
1724 return WN_NO_NETWORK;
1730 * Other Functions
1733 /**************************************************************************
1734 * WNetGetUserA [MPR.@]
1736 * FIXME: we should not return ourselves, but the owner of the drive lpName
1738 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
1740 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
1741 return GetLastError();
1744 /*****************************************************************
1745 * WNetGetUserW [MPR.@]
1747 * FIXME: we should not return ourselves, but the owner of the drive lpName
1749 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
1751 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
1752 return GetLastError();
1755 /*********************************************************************
1756 * WNetConnectionDialog [MPR.@]
1758 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
1760 FIXME( "(%p, %08lX): stub\n", hwnd, dwType );
1762 SetLastError(WN_NO_NETWORK);
1763 return WN_NO_NETWORK;
1766 /*********************************************************************
1767 * WNetConnectionDialog1A [MPR.@]
1769 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
1771 FIXME( "(%p): stub\n", lpConnDlgStruct );
1773 SetLastError(WN_NO_NETWORK);
1774 return WN_NO_NETWORK;
1777 /*********************************************************************
1778 * WNetConnectionDialog1W [MPR.@]
1780 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
1782 FIXME( "(%p): stub\n", lpConnDlgStruct );
1784 SetLastError(WN_NO_NETWORK);
1785 return WN_NO_NETWORK;
1788 /*********************************************************************
1789 * WNetDisconnectDialog [MPR.@]
1791 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
1793 FIXME( "(%p, %08lX): stub\n", hwnd, dwType );
1795 SetLastError(WN_NO_NETWORK);
1796 return WN_NO_NETWORK;
1799 /*********************************************************************
1800 * WNetDisconnectDialog1A [MPR.@]
1802 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
1804 FIXME( "(%p): stub\n", lpConnDlgStruct );
1806 SetLastError(WN_NO_NETWORK);
1807 return WN_NO_NETWORK;
1810 /*********************************************************************
1811 * WNetDisconnectDialog1W [MPR.@]
1813 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
1815 FIXME( "(%p): stub\n", lpConnDlgStruct );
1817 SetLastError(WN_NO_NETWORK);
1818 return WN_NO_NETWORK;
1821 /*********************************************************************
1822 * WNetGetLastErrorA [MPR.@]
1824 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
1825 LPSTR lpErrorBuf, DWORD nErrorBufSize,
1826 LPSTR lpNameBuf, DWORD nNameBufSize )
1828 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
1829 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
1831 SetLastError(WN_NO_NETWORK);
1832 return WN_NO_NETWORK;
1835 /*********************************************************************
1836 * WNetGetLastErrorW [MPR.@]
1838 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
1839 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
1840 LPWSTR lpNameBuf, DWORD nNameBufSize )
1842 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
1843 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
1845 SetLastError(WN_NO_NETWORK);
1846 return WN_NO_NETWORK;
1849 /*********************************************************************
1850 * WNetGetNetworkInformationA [MPR.@]
1852 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
1853 LPNETINFOSTRUCT lpNetInfoStruct )
1855 DWORD ret;
1857 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
1859 if (!lpProvider)
1860 ret = WN_BAD_POINTER;
1861 else
1863 int len;
1865 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
1866 if (len)
1868 LPWSTR wideProvider = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
1869 len * sizeof(WCHAR));
1871 if (wideProvider)
1873 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
1874 len);
1875 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
1876 HeapFree(GetProcessHeap(), 0, wideProvider);
1878 else
1879 ret = WN_OUT_OF_MEMORY;
1881 else
1882 ret = GetLastError();
1884 if (ret)
1885 SetLastError(ret);
1886 TRACE("Returning %ld\n", ret);
1887 return ret;
1890 /*********************************************************************
1891 * WNetGetNetworkInformationW [MPR.@]
1893 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
1894 LPNETINFOSTRUCT lpNetInfoStruct )
1896 DWORD ret;
1898 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
1900 if (!lpProvider)
1901 ret = WN_BAD_POINTER;
1902 else if (!lpNetInfoStruct)
1903 ret = WN_BAD_POINTER;
1904 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
1905 ret = WN_BAD_VALUE;
1906 else
1908 if (providerTable && providerTable->numProviders)
1910 DWORD providerIndex = _findProviderIndexW(lpProvider);
1912 if (providerIndex != BAD_PROVIDER_INDEX)
1914 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
1915 lpNetInfoStruct->dwProviderVersion =
1916 providerTable->table[providerIndex].dwSpecVersion;
1917 lpNetInfoStruct->dwStatus = NO_ERROR;
1918 lpNetInfoStruct->dwCharacteristics = 0;
1919 lpNetInfoStruct->dwHandle = (ULONG_PTR)NULL;
1920 lpNetInfoStruct->wNetType =
1921 HIWORD(providerTable->table[providerIndex].dwNetType);
1922 lpNetInfoStruct->dwPrinters = -1;
1923 lpNetInfoStruct->dwDrives = -1;
1924 ret = WN_SUCCESS;
1926 else
1927 ret = WN_BAD_PROVIDER;
1929 else
1930 ret = WN_NO_NETWORK;
1932 if (ret)
1933 SetLastError(ret);
1934 TRACE("Returning %ld\n", ret);
1935 return ret;
1938 /*****************************************************************
1939 * WNetGetProviderNameA [MPR.@]
1941 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
1942 LPSTR lpProvider, LPDWORD lpBufferSize )
1944 DWORD ret;
1946 TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
1947 lpBufferSize);
1949 if (!lpProvider)
1950 ret = WN_BAD_POINTER;
1951 else if (!lpBufferSize)
1952 ret = WN_BAD_POINTER;
1953 else
1955 if (providerTable)
1957 DWORD i;
1959 ret = WN_NO_NETWORK;
1960 for (i = 0; i < providerTable->numProviders &&
1961 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
1962 i++)
1964 if (i < providerTable->numProviders)
1966 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
1967 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
1969 if (*lpBufferSize < sizeNeeded)
1971 *lpBufferSize = sizeNeeded;
1972 ret = WN_MORE_DATA;
1974 else
1976 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
1977 -1, lpProvider, *lpBufferSize, NULL, NULL);
1978 ret = WN_SUCCESS;
1979 /* FIXME: is *lpBufferSize set to the number of characters
1980 * copied? */
1984 else
1985 ret = WN_NO_NETWORK;
1987 if (ret)
1988 SetLastError(ret);
1989 TRACE("Returning %ld\n", ret);
1990 return ret;
1993 /*****************************************************************
1994 * WNetGetProviderNameW [MPR.@]
1996 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
1997 LPWSTR lpProvider, LPDWORD lpBufferSize )
1999 DWORD ret;
2001 TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2002 lpBufferSize);
2004 if (!lpProvider)
2005 ret = WN_BAD_POINTER;
2006 else if (!lpBufferSize)
2007 ret = WN_BAD_POINTER;
2008 else
2010 if (providerTable)
2012 DWORD i;
2014 ret = WN_NO_NETWORK;
2015 for (i = 0; i < providerTable->numProviders &&
2016 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2017 i++)
2019 if (i < providerTable->numProviders)
2021 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2023 if (*lpBufferSize < sizeNeeded)
2025 *lpBufferSize = sizeNeeded;
2026 ret = WN_MORE_DATA;
2028 else
2030 strcpyW(lpProvider, providerTable->table[i].name);
2031 ret = WN_SUCCESS;
2032 /* FIXME: is *lpBufferSize set to the number of characters
2033 * copied? */
2037 else
2038 ret = WN_NO_NETWORK;
2040 if (ret)
2041 SetLastError(ret);
2042 TRACE("Returning %ld\n", ret);
2043 return ret;