Sync with trunk head (part 1 of 2)
[reactos.git] / dll / win32 / mpr / wnet.c
1 /*
2 * MPR WNet functions
3 *
4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
7 *
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.
12 *
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.
17 *
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
21 */
22
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 #include "wine/debug.h"
33 #include "wine/unicode.h"
34 #include "mprres.h"
35 #include "wnetpriv.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(mpr);
38
39 /* Data structures representing network service providers. Assumes only one
40 * thread creates them, and that they are constant for the life of the process
41 * (and therefore doesn't synchronize access).
42 * FIXME: only basic provider data and enumeration-related data are implemented
43 * so far, need to implement the rest too.
44 */
45 typedef struct _WNetProvider
46 {
47 HMODULE hLib;
48 PWSTR name;
49 PF_NPGetCaps getCaps;
50 DWORD dwSpecVersion;
51 DWORD dwNetType;
52 DWORD dwEnumScopes;
53 PF_NPOpenEnum openEnum;
54 PF_NPEnumResource enumResource;
55 PF_NPCloseEnum closeEnum;
56 PF_NPGetResourceInformation getResourceInformation;
57 } WNetProvider, *PWNetProvider;
58
59 typedef struct _WNetProviderTable
60 {
61 LPWSTR entireNetwork;
62 DWORD numAllocated;
63 DWORD numProviders;
64 WNetProvider table[1];
65 } WNetProviderTable, *PWNetProviderTable;
66
67 #define WNET_ENUMERATOR_TYPE_NULL 0
68 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
69 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
70 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
71
72 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
73 * the enumeration; it represents one of the following types:
74 * - a 'null' enumeration, one that contains no members
75 * - a global enumeration, one that's executed across all providers
76 * - a provider-specific enumeration, one that's only executed by a single
77 * provider
78 * - a context enumeration. I know this contradicts what I just said about
79 * there being no correspondence between the scope and the type, but it's
80 * necessary for the special case that a "Entire Network" entry needs to
81 * be enumerated in an enumeration of the context scope. Thus an enumeration
82 * of the context scope results in a context type enumerator, which morphs
83 * into a global enumeration (so the enumeration continues across all
84 * providers).
85 */
86 typedef struct _WNetEnumerator
87 {
88 DWORD enumType;
89 DWORD providerIndex;
90 HANDLE handle;
91 BOOL providerDone;
92 DWORD dwScope;
93 DWORD dwType;
94 DWORD dwUsage;
95 LPNETRESOURCEW lpNet;
96 } WNetEnumerator, *PWNetEnumerator;
97
98 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
99
100 /* Returns an index (into the global WNetProviderTable) of the provider with
101 * the given name, or BAD_PROVIDER_INDEX if not found.
102 */
103 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
104
105 static PWNetProviderTable providerTable;
106
107 /*
108 * Global provider table functions
109 */
110
111 static void _tryLoadProvider(PCWSTR provider)
112 {
113 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
114 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
115 'S','e','r','v','i','c','e','s','\\',0 };
116 static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
117 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
118 WCHAR serviceName[MAX_PATH];
119 HKEY hKey;
120
121 TRACE("%s\n", debugstr_w(provider));
122 snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt,
123 servicePrefix, provider);
124 serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0';
125 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
126 ERROR_SUCCESS)
127 {
128 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
129 'P','a','t','h',0 };
130 WCHAR providerPath[MAX_PATH];
131 DWORD type, size = sizeof(providerPath);
132
133 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
134 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && type == REG_SZ)
135 {
136 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
137 PWSTR name = NULL;
138
139 size = 0;
140 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
141 if (size)
142 {
143 name = HeapAlloc(GetProcessHeap(), 0, size);
144 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
145 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
146 {
147 HeapFree(GetProcessHeap(), 0, name);
148 name = NULL;
149 }
150 }
151 if (name)
152 {
153 HMODULE hLib = LoadLibraryW(providerPath);
154
155 if (hLib)
156 {
157 PF_NPGetCaps getCaps = (PF_NPGetCaps)GetProcAddress(hLib,
158 "NPGetCaps");
159
160 TRACE("loaded lib %p\n", hLib);
161 if (getCaps)
162 {
163 PWNetProvider provider =
164 &providerTable->table[providerTable->numProviders];
165
166 provider->hLib = hLib;
167 provider->name = name;
168 TRACE("name is %s\n", debugstr_w(name));
169 provider->getCaps = getCaps;
170 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
171 provider->dwNetType = getCaps(WNNC_NET_TYPE);
172 TRACE("net type is 0x%08x\n", provider->dwNetType);
173 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
174 if (provider->dwEnumScopes)
175 {
176 TRACE("supports enumeration\n");
177 provider->openEnum = (PF_NPOpenEnum)
178 GetProcAddress(hLib, "NPOpenEnum");
179 TRACE("openEnum is %p\n", provider->openEnum);
180 provider->enumResource = (PF_NPEnumResource)
181 GetProcAddress(hLib, "NPEnumResource");
182 TRACE("enumResource is %p\n",
183 provider->enumResource);
184 provider->closeEnum = (PF_NPCloseEnum)
185 GetProcAddress(hLib, "NPCloseEnum");
186 TRACE("closeEnum is %p\n", provider->closeEnum);
187 provider->getResourceInformation = (PF_NPGetResourceInformation)
188 GetProcAddress(hLib, "NPGetResourceInformation");
189 TRACE("getResourceInformation is %p\n",
190 provider->getResourceInformation);
191 if (!provider->openEnum || !provider->enumResource
192 || !provider->closeEnum)
193 {
194 provider->openEnum = NULL;
195 provider->enumResource = NULL;
196 provider->closeEnum = NULL;
197 provider->dwEnumScopes = 0;
198 WARN("Couldn't load enumeration functions\n");
199 }
200 }
201 providerTable->numProviders++;
202 }
203 else
204 {
205 WARN("Provider %s didn't export NPGetCaps\n",
206 debugstr_w(provider));
207 HeapFree(GetProcessHeap(), 0, name);
208 FreeLibrary(hLib);
209 }
210 }
211 else
212 {
213 WARN("Couldn't load library %s for provider %s\n",
214 debugstr_w(providerPath), debugstr_w(provider));
215 HeapFree(GetProcessHeap(), 0, name);
216 }
217 }
218 else
219 {
220 WARN("Couldn't get provider name for provider %s\n",
221 debugstr_w(provider));
222 }
223 }
224 else
225 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
226 RegCloseKey(hKey);
227 }
228 else
229 WARN("Couldn't open service key for provider %s\n",
230 debugstr_w(provider));
231 }
232
233 void wnetInit(HINSTANCE hInstDll)
234 {
235 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
236 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
237 'C','o','n','t','r','o','l','\\',
238 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
239 'O','r','d','e','r',0 };
240 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
241 'O','r','d','e','r',0 };
242 HKEY hKey;
243
244 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
245 == ERROR_SUCCESS)
246 {
247 DWORD size = 0;
248
249 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
250 if (size)
251 {
252 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
253
254 if (providers)
255 {
256 DWORD type;
257
258 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
259 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
260 {
261 PWSTR ptr;
262 DWORD numToAllocate;
263
264 TRACE("provider order is %s\n", debugstr_w(providers));
265 /* first count commas as a heuristic for how many to
266 * allocate space for */
267 for (ptr = providers, numToAllocate = 1; ptr; )
268 {
269 ptr = strchrW(ptr, ',');
270 if (ptr) {
271 numToAllocate++;
272 ptr++;
273 }
274 }
275 providerTable =
276 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
277 sizeof(WNetProviderTable)
278 + (numToAllocate - 1) * sizeof(WNetProvider));
279 if (providerTable)
280 {
281 PWSTR ptrPrev;
282 int entireNetworkLen;
283 LPCWSTR stringresource;
284
285 entireNetworkLen = LoadStringW(hInstDll,
286 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
287 providerTable->entireNetwork = HeapAlloc(
288 GetProcessHeap(), 0, (entireNetworkLen + 1) *
289 sizeof(WCHAR));
290 if (providerTable->entireNetwork)
291 {
292 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
293 providerTable->entireNetwork[entireNetworkLen] = 0;
294 }
295 providerTable->numAllocated = numToAllocate;
296 for (ptr = providers; ptr; )
297 {
298 ptrPrev = ptr;
299 ptr = strchrW(ptr, ',');
300 if (ptr)
301 *ptr++ = '\0';
302 _tryLoadProvider(ptrPrev);
303 }
304 }
305 }
306 HeapFree(GetProcessHeap(), 0, providers);
307 }
308 }
309 RegCloseKey(hKey);
310 }
311 }
312
313 void wnetFree(void)
314 {
315 if (providerTable)
316 {
317 DWORD i;
318
319 for (i = 0; i < providerTable->numProviders; i++)
320 {
321 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
322 FreeModule(providerTable->table[i].hLib);
323 }
324 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
325 HeapFree(GetProcessHeap(), 0, providerTable);
326 providerTable = NULL;
327 }
328 }
329
330 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
331 {
332 DWORD ret = BAD_PROVIDER_INDEX;
333
334 if (providerTable && providerTable->numProviders)
335 {
336 DWORD i;
337
338 for (i = 0; i < providerTable->numProviders &&
339 ret == BAD_PROVIDER_INDEX; i++)
340 if (!strcmpW(lpProvider, providerTable->table[i].name))
341 ret = i;
342 }
343 return ret;
344 }
345
346 /*
347 * Browsing Functions
348 */
349
350 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
351 {
352 LPNETRESOURCEW ret;
353
354 if (lpNet)
355 {
356 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
357 if (ret)
358 {
359 size_t len;
360
361 *ret = *lpNet;
362 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
363 if (lpNet->lpRemoteName)
364 {
365 len = strlenW(lpNet->lpRemoteName) + 1;
366 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
367 if (ret->lpRemoteName)
368 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
369 }
370 }
371 }
372 else
373 ret = NULL;
374 return ret;
375 }
376
377 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
378 {
379 if (lpNet)
380 {
381 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
382 HeapFree(GetProcessHeap(), 0, lpNet);
383 }
384 }
385
386 static PWNetEnumerator _createNullEnumerator(void)
387 {
388 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
389 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
390
391 if (ret)
392 ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
393 return ret;
394 }
395
396 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
397 DWORD dwUsage, LPNETRESOURCEW lpNet)
398 {
399 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
400 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
401
402 if (ret)
403 {
404 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
405 ret->dwScope = dwScope;
406 ret->dwType = dwType;
407 ret->dwUsage = dwUsage;
408 ret->lpNet = _copyNetResourceForEnumW(lpNet);
409 }
410 return ret;
411 }
412
413 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
414 DWORD dwUsage, DWORD index, HANDLE handle)
415 {
416 PWNetEnumerator ret;
417
418 if (!providerTable || index >= providerTable->numProviders)
419 ret = NULL;
420 else
421 {
422 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
423 if (ret)
424 {
425 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER;
426 ret->providerIndex = index;
427 ret->dwScope = dwScope;
428 ret->dwType = dwType;
429 ret->dwUsage = dwUsage;
430 ret->handle = handle;
431 }
432 }
433 return ret;
434 }
435
436 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
437 DWORD dwUsage)
438 {
439 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
440 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
441
442 if (ret)
443 {
444 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
445 ret->dwScope = dwScope;
446 ret->dwType = dwType;
447 ret->dwUsage = dwUsage;
448 }
449 return ret;
450 }
451
452 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
453 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
454 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
455 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
456 * if not all members of the array could be thunked, and something else on
457 * failure.
458 */
459 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
460 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
461 {
462 DWORD i, numToThunk, totalBytes, ret;
463 LPSTR strNext;
464
465 if (!lpNetArrayIn)
466 return WN_BAD_POINTER;
467 if (!lpcCount)
468 return WN_BAD_POINTER;
469 if (*lpcCount == -1)
470 return WN_BAD_VALUE;
471 if (!lpBuffer)
472 return WN_BAD_POINTER;
473 if (!lpBufferSize)
474 return WN_BAD_POINTER;
475
476 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
477 {
478 const NETRESOURCEW *lpNet = lpNetArrayIn + i;
479
480 totalBytes += sizeof(NETRESOURCEA);
481 if (lpNet->lpLocalName)
482 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
483 -1, NULL, 0, NULL, NULL);
484 if (lpNet->lpRemoteName)
485 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
486 -1, NULL, 0, NULL, NULL);
487 if (lpNet->lpComment)
488 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
489 -1, NULL, 0, NULL, NULL);
490 if (lpNet->lpProvider)
491 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
492 -1, NULL, 0, NULL, NULL);
493 if (totalBytes < *lpBufferSize)
494 numToThunk = i + 1;
495 }
496 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
497 for (i = 0; i < numToThunk; i++)
498 {
499 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
500 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
501
502 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
503 /* lie about string lengths, we already verified how many
504 * we have space for above
505 */
506 if (lpNetIn->lpLocalName)
507 {
508 lpNetOut->lpLocalName = strNext;
509 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
510 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
511 }
512 if (lpNetIn->lpRemoteName)
513 {
514 lpNetOut->lpRemoteName = strNext;
515 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
516 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
517 }
518 if (lpNetIn->lpComment)
519 {
520 lpNetOut->lpComment = strNext;
521 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
522 lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
523 }
524 if (lpNetIn->lpProvider)
525 {
526 lpNetOut->lpProvider = strNext;
527 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
528 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
529 }
530 }
531 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
532 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
533 *lpcCount, ret);
534 return ret;
535 }
536
537 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
538 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
539 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
540 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
541 * if not all members of the array could be thunked, and something else on
542 * failure.
543 */
544 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
545 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
546 {
547 DWORD i, numToThunk, totalBytes, ret;
548 LPWSTR strNext;
549
550 if (!lpNetArrayIn)
551 return WN_BAD_POINTER;
552 if (!lpcCount)
553 return WN_BAD_POINTER;
554 if (*lpcCount == -1)
555 return WN_BAD_VALUE;
556 if (!lpBuffer)
557 return WN_BAD_POINTER;
558 if (!lpBufferSize)
559 return WN_BAD_POINTER;
560
561 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
562 {
563 const NETRESOURCEA *lpNet = lpNetArrayIn + i;
564
565 totalBytes += sizeof(NETRESOURCEW);
566 if (lpNet->lpLocalName)
567 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
568 -1, NULL, 0) * sizeof(WCHAR);
569 if (lpNet->lpRemoteName)
570 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
571 -1, NULL, 0) * sizeof(WCHAR);
572 if (lpNet->lpComment)
573 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
574 -1, NULL, 0) * sizeof(WCHAR);
575 if (lpNet->lpProvider)
576 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
577 -1, NULL, 0) * sizeof(WCHAR);
578 if (totalBytes < *lpBufferSize)
579 numToThunk = i + 1;
580 }
581 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
582 for (i = 0; i < numToThunk; i++)
583 {
584 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
585 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
586
587 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
588 /* lie about string lengths, we already verified how many
589 * we have space for above
590 */
591 if (lpNetIn->lpLocalName)
592 {
593 lpNetOut->lpLocalName = strNext;
594 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
595 -1, lpNetOut->lpLocalName, *lpBufferSize);
596 }
597 if (lpNetIn->lpRemoteName)
598 {
599 lpNetOut->lpRemoteName = strNext;
600 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
601 -1, lpNetOut->lpRemoteName, *lpBufferSize);
602 }
603 if (lpNetIn->lpComment)
604 {
605 lpNetOut->lpComment = strNext;
606 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
607 -1, lpNetOut->lpComment, *lpBufferSize);
608 }
609 if (lpNetIn->lpProvider)
610 {
611 lpNetOut->lpProvider = strNext;
612 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
613 -1, lpNetOut->lpProvider, *lpBufferSize);
614 }
615 }
616 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
617 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
618 *lpcCount, ret);
619 return ret;
620 }
621
622 /*********************************************************************
623 * WNetOpenEnumA [MPR.@]
624 *
625 * See comments for WNetOpenEnumW.
626 */
627 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
628 LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
629 {
630 DWORD ret;
631
632 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
633 dwScope, dwType, dwUsage, lpNet, lphEnum );
634
635 if (!lphEnum)
636 ret = WN_BAD_POINTER;
637 else if (!providerTable || providerTable->numProviders == 0)
638 {
639 lphEnum = NULL;
640 ret = WN_NO_NETWORK;
641 }
642 else
643 {
644 if (lpNet)
645 {
646 LPNETRESOURCEW lpNetWide = NULL;
647 BYTE buf[1024];
648 DWORD size = sizeof(buf), count = 1;
649 BOOL allocated = FALSE;
650
651 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
652 if (ret == WN_MORE_DATA)
653 {
654 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
655 size);
656 if (lpNetWide)
657 {
658 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
659 &size);
660 allocated = TRUE;
661 }
662 else
663 ret = WN_OUT_OF_MEMORY;
664 }
665 else if (ret == WN_SUCCESS)
666 lpNetWide = (LPNETRESOURCEW)buf;
667 if (ret == WN_SUCCESS)
668 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
669 lphEnum);
670 if (allocated)
671 HeapFree(GetProcessHeap(), 0, lpNetWide);
672 }
673 else
674 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
675 }
676 if (ret)
677 SetLastError(ret);
678 TRACE("Returning %d\n", ret);
679 return ret;
680 }
681
682 /*********************************************************************
683 * WNetOpenEnumW [MPR.@]
684 *
685 * Network enumeration has way too many parameters, so I'm not positive I got
686 * them right. What I've got so far:
687 *
688 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
689 * all the network providers should be enumerated.
690 *
691 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
692 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
693 * lpProvider is set, all the network providers should be enumerated.
694 * (This means the enumeration is a list of network providers, not that the
695 * enumeration is passed on to the providers.)
696 *
697 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
698 * resource matches the "Entire Network" resource (no remote name, no
699 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
700 * enumeration is done on every network provider.
701 *
702 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
703 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
704 * only to the given network provider.
705 *
706 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
707 * no lpProvider is set, enumeration will be tried on every network provider,
708 * in the order in which they're loaded.
709 *
710 * - The LPNETRESOURCE should be disregarded for scopes besides
711 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
712 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
713 *
714 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
715 * resource in the enumerated list, as well as any machines in your
716 * workgroup. The machines in your workgroup come from doing a
717 * RESOURCE_CONTEXT enumeration of every Network Provider.
718 */
719 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
720 LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
721 {
722 DWORD ret;
723
724 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
725 dwScope, dwType, dwUsage, lpNet, lphEnum );
726
727 if (!lphEnum)
728 ret = WN_BAD_POINTER;
729 else if (!providerTable || providerTable->numProviders == 0)
730 {
731 lphEnum = NULL;
732 ret = WN_NO_NETWORK;
733 }
734 else
735 {
736 switch (dwScope)
737 {
738 case RESOURCE_GLOBALNET:
739 if (lpNet)
740 {
741 if (lpNet->lpProvider)
742 {
743 DWORD index = _findProviderIndexW(lpNet->lpProvider);
744
745 if (index != BAD_PROVIDER_INDEX)
746 {
747 if (providerTable->table[index].openEnum &&
748 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
749 {
750 HANDLE handle;
751
752 ret = providerTable->table[index].openEnum(
753 dwScope, dwType, dwUsage, lpNet, &handle);
754 if (ret == WN_SUCCESS)
755 {
756 *lphEnum = _createProviderEnumerator(
757 dwScope, dwType, dwUsage, index, handle);
758 ret = *lphEnum ? WN_SUCCESS :
759 WN_OUT_OF_MEMORY;
760 }
761 }
762 else
763 ret = WN_NOT_SUPPORTED;
764 }
765 else
766 ret = WN_BAD_PROVIDER;
767 }
768 else if (lpNet->lpRemoteName)
769 {
770 *lphEnum = _createGlobalEnumeratorW(dwScope,
771 dwType, dwUsage, lpNet);
772 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
773 }
774 else
775 {
776 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
777 providerTable->entireNetwork))
778 {
779 /* comment matches the "Entire Network", enumerate
780 * global scope of every provider
781 */
782 *lphEnum = _createGlobalEnumeratorW(dwScope,
783 dwType, dwUsage, lpNet);
784 }
785 else
786 {
787 /* this is the same as not having passed lpNet */
788 *lphEnum = _createGlobalEnumeratorW(dwScope,
789 dwType, dwUsage, NULL);
790 }
791 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
792 }
793 }
794 else
795 {
796 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
797 dwUsage, lpNet);
798 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
799 }
800 break;
801 case RESOURCE_CONTEXT:
802 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
803 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
804 break;
805 case RESOURCE_REMEMBERED:
806 case RESOURCE_CONNECTED:
807 *lphEnum = _createNullEnumerator();
808 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
809 break;
810 default:
811 WARN("unknown scope 0x%08x\n", dwScope);
812 ret = WN_BAD_VALUE;
813 }
814 }
815 if (ret)
816 SetLastError(ret);
817 TRACE("Returning %d\n", ret);
818 return ret;
819 }
820
821 /*********************************************************************
822 * WNetEnumResourceA [MPR.@]
823 */
824 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
825 LPVOID lpBuffer, LPDWORD lpBufferSize )
826 {
827 DWORD ret;
828
829 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
830
831 if (!hEnum)
832 ret = WN_BAD_POINTER;
833 else if (!lpcCount)
834 ret = WN_BAD_POINTER;
835 else if (!lpBuffer)
836 ret = WN_BAD_POINTER;
837 else if (!lpBufferSize)
838 ret = WN_BAD_POINTER;
839 else if (*lpBufferSize < sizeof(NETRESOURCEA))
840 {
841 *lpBufferSize = sizeof(NETRESOURCEA);
842 ret = WN_MORE_DATA;
843 }
844 else
845 {
846 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
847 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
848
849 if (localBuffer)
850 {
851 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
852 &localSize);
853 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
854 {
855 /* FIXME: this isn't necessarily going to work in the case of
856 * WN_MORE_DATA, because our enumerator may have moved on to
857 * the next provider. MSDN states that a large (16KB) buffer
858 * size is the appropriate usage of this function, so
859 * hopefully it won't be an issue.
860 */
861 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
862 lpBuffer, lpBufferSize);
863 *lpcCount = localCount;
864 }
865 HeapFree(GetProcessHeap(), 0, localBuffer);
866 }
867 else
868 ret = WN_OUT_OF_MEMORY;
869 }
870 if (ret)
871 SetLastError(ret);
872 TRACE("Returning %d\n", ret);
873 return ret;
874 }
875
876 static DWORD _countProviderBytesW(PWNetProvider provider)
877 {
878 DWORD ret;
879
880 if (provider)
881 {
882 ret = sizeof(NETRESOURCEW);
883 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
884 }
885 else
886 ret = 0;
887 return ret;
888 }
889
890 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
891 LPVOID lpBuffer, const DWORD *lpBufferSize)
892 {
893 DWORD ret;
894
895 if (!enumerator)
896 return WN_BAD_POINTER;
897 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
898 return WN_BAD_VALUE;
899 if (!lpcCount)
900 return WN_BAD_POINTER;
901 if (!lpBuffer)
902 return WN_BAD_POINTER;
903 if (!lpBufferSize)
904 return WN_BAD_POINTER;
905 if (*lpBufferSize < sizeof(NETRESOURCEA))
906 return WN_MORE_DATA;
907
908 if (!providerTable || enumerator->providerIndex >=
909 providerTable->numProviders)
910 ret = WN_NO_MORE_ENTRIES;
911 else
912 {
913 DWORD bytes = 0, count = 0, countLimit, i;
914 LPNETRESOURCEW resource;
915 LPWSTR strNext;
916
917 countLimit = *lpcCount == -1 ?
918 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
919 while (count < countLimit && bytes < *lpBufferSize)
920 {
921 DWORD bytesNext = _countProviderBytesW(
922 &providerTable->table[count + enumerator->providerIndex]);
923
924 if (bytes + bytesNext < *lpBufferSize)
925 {
926 bytes += bytesNext;
927 count++;
928 }
929 }
930 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
931 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
932 {
933 resource->dwScope = RESOURCE_GLOBALNET;
934 resource->dwType = RESOURCETYPE_ANY;
935 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
936 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
937 RESOURCEUSAGE_RESERVED;
938 resource->lpLocalName = NULL;
939 resource->lpRemoteName = strNext;
940 strcpyW(resource->lpRemoteName,
941 providerTable->table[i + enumerator->providerIndex].name);
942 strNext += strlenW(resource->lpRemoteName) + 1;
943 resource->lpComment = NULL;
944 resource->lpProvider = strNext;
945 strcpyW(resource->lpProvider,
946 providerTable->table[i + enumerator->providerIndex].name);
947 strNext += strlenW(resource->lpProvider) + 1;
948 }
949 enumerator->providerIndex += count;
950 *lpcCount = count;
951 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
952 }
953 TRACE("Returning %d\n", ret);
954 return ret;
955 }
956
957 /* Advances the enumerator (assumed to be a global enumerator) to the next
958 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
959 * not open a handle with the next provider.
960 * If the existing handle is NULL, may leave the enumerator unchanged, since
961 * the current provider may support the desired scope.
962 * If the existing handle is not NULL, closes it before moving on.
963 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
964 * provider, and another error on failure.
965 */
966 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
967 {
968 if (!enumerator)
969 return WN_BAD_POINTER;
970 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
971 return WN_BAD_VALUE;
972 if (!providerTable || enumerator->providerIndex >=
973 providerTable->numProviders)
974 return WN_NO_MORE_ENTRIES;
975
976 if (enumerator->providerDone)
977 {
978 DWORD dwEnum = 0;
979 enumerator->providerDone = FALSE;
980 if (enumerator->handle)
981 {
982 providerTable->table[enumerator->providerIndex].closeEnum(
983 enumerator->handle);
984 enumerator->handle = NULL;
985 enumerator->providerIndex++;
986 }
987 if (enumerator->dwScope == RESOURCE_CONNECTED)
988 dwEnum = WNNC_ENUM_LOCAL;
989 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
990 dwEnum = WNNC_ENUM_GLOBAL;
991 else if (enumerator->dwScope == RESOURCE_CONTEXT)
992 dwEnum = WNNC_ENUM_CONTEXT;
993 for (; enumerator->providerIndex < providerTable->numProviders &&
994 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
995 & dwEnum); enumerator->providerIndex++)
996 ;
997 }
998 return enumerator->providerIndex < providerTable->numProviders ?
999 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1000 }
1001
1002 /* "Passes through" call to the next provider that supports the enumeration
1003 * type.
1004 * FIXME: if one call to a provider's enumerator succeeds while there's still
1005 * space in lpBuffer, I don't call to the next provider. The caller may not
1006 * expect that it should call EnumResourceW again with a return value of
1007 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1008 * may have to be moved around a bit, ick.
1009 */
1010 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1011 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1012 {
1013 DWORD ret;
1014
1015 if (!enumerator)
1016 return WN_BAD_POINTER;
1017 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1018 return WN_BAD_VALUE;
1019 if (!lpcCount)
1020 return WN_BAD_POINTER;
1021 if (!lpBuffer)
1022 return WN_BAD_POINTER;
1023 if (!lpBufferSize)
1024 return WN_BAD_POINTER;
1025 if (*lpBufferSize < sizeof(NETRESOURCEW))
1026 return WN_MORE_DATA;
1027
1028 ret = _globalEnumeratorAdvance(enumerator);
1029 if (ret == WN_SUCCESS)
1030 {
1031 ret = providerTable->table[enumerator->providerIndex].
1032 openEnum(enumerator->dwScope, enumerator->dwType,
1033 enumerator->dwUsage, enumerator->lpNet,
1034 &enumerator->handle);
1035 if (ret == WN_SUCCESS)
1036 {
1037 ret = providerTable->table[enumerator->providerIndex].
1038 enumResource(enumerator->handle, lpcCount, lpBuffer,
1039 lpBufferSize);
1040 if (ret != WN_MORE_DATA)
1041 enumerator->providerDone = TRUE;
1042 }
1043 }
1044 TRACE("Returning %d\n", ret);
1045 return ret;
1046 }
1047
1048 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1049 LPVOID lpBuffer, LPDWORD lpBufferSize)
1050 {
1051 DWORD ret;
1052
1053 if (!enumerator)
1054 return WN_BAD_POINTER;
1055 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1056 return WN_BAD_VALUE;
1057 if (!lpcCount)
1058 return WN_BAD_POINTER;
1059 if (!lpBuffer)
1060 return WN_BAD_POINTER;
1061 if (!lpBufferSize)
1062 return WN_BAD_POINTER;
1063 if (*lpBufferSize < sizeof(NETRESOURCEW))
1064 return WN_MORE_DATA;
1065 if (!providerTable)
1066 return WN_NO_NETWORK;
1067
1068 switch (enumerator->dwScope)
1069 {
1070 case RESOURCE_GLOBALNET:
1071 if (enumerator->lpNet)
1072 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1073 lpBuffer, lpBufferSize);
1074 else
1075 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1076 lpBufferSize);
1077 break;
1078 case RESOURCE_CONTEXT:
1079 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1080 lpBufferSize);
1081 break;
1082 default:
1083 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1084 ret = WN_NO_MORE_ENTRIES;
1085 }
1086 TRACE("Returning %d\n", ret);
1087 return ret;
1088 }
1089
1090 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1091 LPVOID lpBuffer, LPDWORD lpBufferSize)
1092 {
1093 if (!enumerator)
1094 return WN_BAD_POINTER;
1095 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1096 return WN_BAD_VALUE;
1097 if (!enumerator->handle)
1098 return WN_BAD_VALUE;
1099 if (!lpcCount)
1100 return WN_BAD_POINTER;
1101 if (!lpBuffer)
1102 return WN_BAD_POINTER;
1103 if (!lpBufferSize)
1104 return WN_BAD_POINTER;
1105 if (!providerTable)
1106 return WN_NO_NETWORK;
1107 if (enumerator->providerIndex >= providerTable->numProviders)
1108 return WN_NO_MORE_ENTRIES;
1109 if (!providerTable->table[enumerator->providerIndex].enumResource)
1110 return WN_BAD_VALUE;
1111 return providerTable->table[enumerator->providerIndex].enumResource(
1112 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1113 }
1114
1115 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1116 LPVOID lpBuffer, LPDWORD lpBufferSize)
1117 {
1118 DWORD ret;
1119 size_t cchEntireNetworkLen, bytesNeeded;
1120
1121 if (!enumerator)
1122 return WN_BAD_POINTER;
1123 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1124 return WN_BAD_VALUE;
1125 if (!lpcCount)
1126 return WN_BAD_POINTER;
1127 if (!lpBuffer)
1128 return WN_BAD_POINTER;
1129 if (!lpBufferSize)
1130 return WN_BAD_POINTER;
1131 if (!providerTable)
1132 return WN_NO_NETWORK;
1133
1134 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1135 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1136 if (*lpBufferSize < bytesNeeded)
1137 {
1138 *lpBufferSize = bytesNeeded;
1139 ret = WN_MORE_DATA;
1140 }
1141 else
1142 {
1143 LPNETRESOURCEW lpNet = lpBuffer;
1144
1145 lpNet->dwScope = RESOURCE_GLOBALNET;
1146 lpNet->dwType = enumerator->dwType;
1147 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1148 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1149 lpNet->lpLocalName = NULL;
1150 lpNet->lpRemoteName = NULL;
1151 lpNet->lpProvider = NULL;
1152 /* odd, but correct: put comment at end of buffer, so it won't get
1153 * overwritten by subsequent calls to a provider's enumResource
1154 */
1155 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1156 (cchEntireNetworkLen * sizeof(WCHAR)));
1157 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1158 ret = WN_SUCCESS;
1159 }
1160 if (ret == WN_SUCCESS)
1161 {
1162 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1163
1164 /* "Entire Network" entry enumerated--morph this into a global
1165 * enumerator. enumerator->lpNet continues to be NULL, since it has
1166 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1167 */
1168 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1169 ret = _enumerateGlobalW(enumerator, lpcCount,
1170 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1171 if (ret == WN_SUCCESS)
1172 {
1173 /* reflect the fact that we already enumerated "Entire Network" */
1174 lpcCount++;
1175 *lpBufferSize = bufferSize + bytesNeeded;
1176 }
1177 else
1178 {
1179 /* the provider enumeration failed, but we already succeeded in
1180 * enumerating "Entire Network"--leave type as global to allow a
1181 * retry, but indicate success with a count of one.
1182 */
1183 ret = WN_SUCCESS;
1184 *lpcCount = 1;
1185 *lpBufferSize = bytesNeeded;
1186 }
1187 }
1188 TRACE("Returning %d\n", ret);
1189 return ret;
1190 }
1191
1192 /*********************************************************************
1193 * WNetEnumResourceW [MPR.@]
1194 */
1195 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1196 LPVOID lpBuffer, LPDWORD lpBufferSize )
1197 {
1198 DWORD ret;
1199
1200 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1201
1202 if (!hEnum)
1203 ret = WN_BAD_POINTER;
1204 else if (!lpcCount)
1205 ret = WN_BAD_POINTER;
1206 else if (!lpBuffer)
1207 ret = WN_BAD_POINTER;
1208 else if (!lpBufferSize)
1209 ret = WN_BAD_POINTER;
1210 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1211 {
1212 *lpBufferSize = sizeof(NETRESOURCEW);
1213 ret = WN_MORE_DATA;
1214 }
1215 else
1216 {
1217 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1218
1219 switch (enumerator->enumType)
1220 {
1221 case WNET_ENUMERATOR_TYPE_NULL:
1222 ret = WN_NO_MORE_ENTRIES;
1223 break;
1224 case WNET_ENUMERATOR_TYPE_GLOBAL:
1225 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1226 lpBufferSize);
1227 break;
1228 case WNET_ENUMERATOR_TYPE_PROVIDER:
1229 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1230 lpBufferSize);
1231 break;
1232 case WNET_ENUMERATOR_TYPE_CONTEXT:
1233 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1234 lpBufferSize);
1235 break;
1236 default:
1237 WARN("bogus enumerator type!\n");
1238 ret = WN_NO_NETWORK;
1239 }
1240 }
1241 if (ret)
1242 SetLastError(ret);
1243 TRACE("Returning %d\n", ret);
1244 return ret;
1245 }
1246
1247 /*********************************************************************
1248 * WNetCloseEnum [MPR.@]
1249 */
1250 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1251 {
1252 DWORD ret;
1253
1254 TRACE( "(%p)\n", hEnum );
1255
1256 if (hEnum)
1257 {
1258 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1259
1260 switch (enumerator->enumType)
1261 {
1262 case WNET_ENUMERATOR_TYPE_NULL:
1263 ret = WN_SUCCESS;
1264 break;
1265 case WNET_ENUMERATOR_TYPE_GLOBAL:
1266 if (enumerator->lpNet)
1267 _freeEnumNetResource(enumerator->lpNet);
1268 if (enumerator->handle)
1269 providerTable->table[enumerator->providerIndex].
1270 closeEnum(enumerator->handle);
1271 ret = WN_SUCCESS;
1272 break;
1273 case WNET_ENUMERATOR_TYPE_PROVIDER:
1274 if (enumerator->handle)
1275 providerTable->table[enumerator->providerIndex].
1276 closeEnum(enumerator->handle);
1277 ret = WN_SUCCESS;
1278 break;
1279 default:
1280 WARN("bogus enumerator type!\n");
1281 ret = WN_BAD_HANDLE;
1282 }
1283 HeapFree(GetProcessHeap(), 0, hEnum);
1284 }
1285 else
1286 ret = WN_BAD_HANDLE;
1287 if (ret)
1288 SetLastError(ret);
1289 TRACE("Returning %d\n", ret);
1290 return ret;
1291 }
1292
1293 /*********************************************************************
1294 * WNetGetResourceInformationA [MPR.@]
1295 *
1296 * See WNetGetResourceInformationW
1297 */
1298 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1299 LPVOID lpBuffer, LPDWORD cbBuffer,
1300 LPSTR *lplpSystem )
1301 {
1302 DWORD ret;
1303
1304 TRACE( "(%p, %p, %p, %p)\n",
1305 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1306
1307 if (!providerTable || providerTable->numProviders == 0)
1308 ret = WN_NO_NETWORK;
1309 else if (lpNetResource)
1310 {
1311 LPNETRESOURCEW lpNetResourceW = NULL;
1312 DWORD size = 1024, count = 1;
1313 DWORD len;
1314
1315 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1316 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1317 if (ret == WN_MORE_DATA)
1318 {
1319 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1320 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1321 if (lpNetResourceW)
1322 ret = _thunkNetResourceArrayAToW(lpNetResource,
1323 &count, lpNetResourceW, &size);
1324 else
1325 ret = WN_OUT_OF_MEMORY;
1326 }
1327 if (ret == WN_SUCCESS)
1328 {
1329 LPWSTR lpSystemW = NULL;
1330 LPVOID lpBufferW;
1331 size = 1024;
1332 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1333 if (lpBufferW)
1334 {
1335 ret = WNetGetResourceInformationW(lpNetResourceW,
1336 lpBufferW, &size, &lpSystemW);
1337 if (ret == WN_MORE_DATA)
1338 {
1339 HeapFree(GetProcessHeap(), 0, lpBufferW);
1340 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1341 if (lpBufferW)
1342 ret = WNetGetResourceInformationW(lpNetResourceW,
1343 lpBufferW, &size, &lpSystemW);
1344 else
1345 ret = WN_OUT_OF_MEMORY;
1346 }
1347 if (ret == WN_SUCCESS)
1348 {
1349 ret = _thunkNetResourceArrayWToA(lpBufferW,
1350 &count, lpBuffer, cbBuffer);
1351 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1352 lpNetResourceW = lpBufferW;
1353 size = sizeof(NETRESOURCEA);
1354 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1355 -1, NULL, 0, NULL, NULL);
1356 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1357 -1, NULL, 0, NULL, NULL);
1358
1359 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1360 -1, NULL, 0, NULL, NULL);
1361 if ((len) && ( size + len < *cbBuffer))
1362 {
1363 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1364 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1365 *lplpSystem, len, NULL, NULL);
1366 ret = WN_SUCCESS;
1367 }
1368 else
1369 ret = WN_MORE_DATA;
1370 }
1371 else
1372 ret = WN_OUT_OF_MEMORY;
1373 HeapFree(GetProcessHeap(), 0, lpBufferW);
1374 }
1375 else
1376 ret = WN_OUT_OF_MEMORY;
1377 HeapFree(GetProcessHeap(), 0, lpSystemW);
1378 }
1379 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1380 }
1381 else
1382 ret = WN_NO_NETWORK;
1383
1384 if (ret)
1385 SetLastError(ret);
1386 TRACE("Returning %d\n", ret);
1387 return ret;
1388 }
1389
1390 /*********************************************************************
1391 * WNetGetResourceInformationW [MPR.@]
1392 *
1393 * WNetGetResourceInformationW function identifies the network provider
1394 * that owns the resource and gets information about the type of the resource.
1395 *
1396 * PARAMS:
1397 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1398 * defines a network resource.
1399 * lpBuffer [ O] the pointer to buffer, containing result. It
1400 * contains NETRESOURCEW structure and strings to
1401 * which the members of the NETRESOURCEW structure
1402 * point.
1403 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1404 * in bytes.
1405 * lplpSystem [ O] the pointer to string in the output buffer,
1406 * containing the part of the resource name without
1407 * names of the server and share.
1408 *
1409 * RETURNS:
1410 * NO_ERROR if the function succeeds. System error code if the function fails.
1411 */
1412
1413 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1414 LPVOID lpBuffer, LPDWORD cbBuffer,
1415 LPWSTR *lplpSystem )
1416 {
1417 DWORD ret = WN_NO_NETWORK;
1418 DWORD index;
1419
1420 TRACE( "(%p, %p, %p, %p)\n",
1421 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1422
1423 if (!(lpBuffer))
1424 ret = WN_OUT_OF_MEMORY;
1425 else if (providerTable != NULL)
1426 {
1427 /* FIXME: For function value of a variable is indifferent, it does
1428 * search of all providers in a network.
1429 */
1430 for (index = 0; index < providerTable->numProviders; index++)
1431 {
1432 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1433 WNNC_DLG_GETRESOURCEINFORMATION)
1434 {
1435 if (providerTable->table[index].getResourceInformation)
1436 ret = providerTable->table[index].getResourceInformation(
1437 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1438 else
1439 ret = WN_NO_NETWORK;
1440 if (ret == WN_SUCCESS)
1441 break;
1442 }
1443 }
1444 }
1445 if (ret)
1446 SetLastError(ret);
1447 return ret;
1448 }
1449
1450 /*********************************************************************
1451 * WNetGetResourceParentA [MPR.@]
1452 */
1453 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1454 LPVOID lpBuffer, LPDWORD lpBufferSize )
1455 {
1456 FIXME( "(%p, %p, %p): stub\n",
1457 lpNetResource, lpBuffer, lpBufferSize );
1458
1459 SetLastError(WN_NO_NETWORK);
1460 return WN_NO_NETWORK;
1461 }
1462
1463 /*********************************************************************
1464 * WNetGetResourceParentW [MPR.@]
1465 */
1466 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1467 LPVOID lpBuffer, LPDWORD lpBufferSize )
1468 {
1469 FIXME( "(%p, %p, %p): stub\n",
1470 lpNetResource, lpBuffer, lpBufferSize );
1471
1472 SetLastError(WN_NO_NETWORK);
1473 return WN_NO_NETWORK;
1474 }
1475
1476
1477
1478 /*
1479 * Connection Functions
1480 */
1481
1482 /*********************************************************************
1483 * WNetAddConnectionA [MPR.@]
1484 */
1485 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1486 LPCSTR lpLocalName )
1487 {
1488 FIXME( "(%s, %p, %s): stub\n",
1489 debugstr_a(lpRemoteName), lpPassword, debugstr_a(lpLocalName) );
1490
1491 SetLastError(WN_NO_NETWORK);
1492 return WN_NO_NETWORK;
1493 }
1494
1495 /*********************************************************************
1496 * WNetAddConnectionW [MPR.@]
1497 */
1498 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1499 LPCWSTR lpLocalName )
1500 {
1501 FIXME( "(%s, %p, %s): stub\n",
1502 debugstr_w(lpRemoteName), lpPassword, debugstr_w(lpLocalName) );
1503
1504 SetLastError(WN_NO_NETWORK);
1505 return WN_NO_NETWORK;
1506 }
1507
1508 /*********************************************************************
1509 * WNetAddConnection2A [MPR.@]
1510 */
1511 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1512 LPCSTR lpPassword, LPCSTR lpUserID,
1513 DWORD dwFlags )
1514 {
1515 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1516 lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1517
1518 SetLastError(WN_NO_NETWORK);
1519 return WN_NO_NETWORK;
1520 }
1521
1522 /*********************************************************************
1523 * WNetAddConnection2W [MPR.@]
1524 */
1525 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1526 LPCWSTR lpPassword, LPCWSTR lpUserID,
1527 DWORD dwFlags )
1528 {
1529 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1530 lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1531
1532 SetLastError(WN_NO_NETWORK);
1533 return WN_NO_NETWORK;
1534 }
1535
1536 /*********************************************************************
1537 * WNetAddConnection3A [MPR.@]
1538 */
1539 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1540 LPCSTR lpPassword, LPCSTR lpUserID,
1541 DWORD dwFlags )
1542 {
1543 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1544 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
1545
1546 SetLastError(WN_NO_NETWORK);
1547 return WN_NO_NETWORK;
1548 }
1549
1550 /*********************************************************************
1551 * WNetAddConnection3W [MPR.@]
1552 */
1553 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1554 LPCWSTR lpPassword, LPCWSTR lpUserID,
1555 DWORD dwFlags )
1556 {
1557 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1558 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
1559
1560 SetLastError(WN_NO_NETWORK);
1561 return WN_NO_NETWORK;
1562 }
1563
1564 /*****************************************************************
1565 * WNetUseConnectionA [MPR.@]
1566 */
1567 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1568 LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
1569 LPSTR lpAccessName, LPDWORD lpBufferSize,
1570 LPDWORD lpResult )
1571 {
1572 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1573 hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags,
1574 debugstr_a(lpAccessName), lpBufferSize, lpResult );
1575
1576 SetLastError(WN_NO_NETWORK);
1577 return WN_NO_NETWORK;
1578 }
1579
1580 /*****************************************************************
1581 * WNetUseConnectionW [MPR.@]
1582 */
1583 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1584 LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags,
1585 LPWSTR lpAccessName, LPDWORD lpBufferSize,
1586 LPDWORD lpResult )
1587 {
1588 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1589 hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags,
1590 debugstr_w(lpAccessName), lpBufferSize, lpResult );
1591
1592 SetLastError(WN_NO_NETWORK);
1593 return WN_NO_NETWORK;
1594 }
1595
1596 /*********************************************************************
1597 * WNetCancelConnectionA [MPR.@]
1598 */
1599 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1600 {
1601 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1602
1603 return WN_SUCCESS;
1604 }
1605
1606 /*********************************************************************
1607 * WNetCancelConnectionW [MPR.@]
1608 */
1609 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1610 {
1611 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1612
1613 return WN_SUCCESS;
1614 }
1615
1616 /*********************************************************************
1617 * WNetCancelConnection2A [MPR.@]
1618 */
1619 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1620 {
1621 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1622
1623 return WN_SUCCESS;
1624 }
1625
1626 /*********************************************************************
1627 * WNetCancelConnection2W [MPR.@]
1628 */
1629 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1630 {
1631 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1632
1633 return WN_SUCCESS;
1634 }
1635
1636 /*****************************************************************
1637 * WNetRestoreConnectionA [MPR.@]
1638 */
1639 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
1640 {
1641 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1642
1643 SetLastError(WN_NO_NETWORK);
1644 return WN_NO_NETWORK;
1645 }
1646
1647 /*****************************************************************
1648 * WNetRestoreConnectionW [MPR.@]
1649 */
1650 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
1651 {
1652 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1653
1654 SetLastError(WN_NO_NETWORK);
1655 return WN_NO_NETWORK;
1656 }
1657
1658 /**************************************************************************
1659 * WNetGetConnectionA [MPR.@]
1660 *
1661 * RETURNS
1662 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1663 * - WN_NOT_CONNECTED drive is a local drive
1664 * - WN_MORE_DATA buffer isn't big enough
1665 * - WN_SUCCESS success (net path in buffer)
1666 *
1667 * FIXME: need to test return values under different errors
1668 */
1669 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1670 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1671 {
1672 DWORD ret;
1673
1674 if (!lpLocalName)
1675 ret = WN_BAD_POINTER;
1676 else if (!lpBufferSize)
1677 ret = WN_BAD_POINTER;
1678 else if (!lpRemoteName && *lpBufferSize)
1679 ret = WN_BAD_POINTER;
1680 else
1681 {
1682 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1683
1684 if (len)
1685 {
1686 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1687
1688 if (wideLocalName)
1689 {
1690 WCHAR wideRemoteStatic[MAX_PATH];
1691 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1692
1693 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1694
1695 /* try once without memory allocation */
1696 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1697 &wideRemoteSize);
1698 if (ret == WN_SUCCESS)
1699 {
1700 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1701 -1, NULL, 0, NULL, NULL);
1702
1703 if (len <= *lpBufferSize)
1704 {
1705 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1706 lpRemoteName, *lpBufferSize, NULL, NULL);
1707 ret = WN_SUCCESS;
1708 }
1709 else
1710 {
1711 *lpBufferSize = len;
1712 ret = WN_MORE_DATA;
1713 }
1714 }
1715 else if (ret == WN_MORE_DATA)
1716 {
1717 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1718 wideRemoteSize * sizeof(WCHAR));
1719
1720 if (wideRemote)
1721 {
1722 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1723 &wideRemoteSize);
1724 if (ret == WN_SUCCESS)
1725 {
1726 if (len <= *lpBufferSize)
1727 {
1728 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1729 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1730 ret = WN_SUCCESS;
1731 }
1732 else
1733 {
1734 *lpBufferSize = len;
1735 ret = WN_MORE_DATA;
1736 }
1737 }
1738 HeapFree(GetProcessHeap(), 0, wideRemote);
1739 }
1740 else
1741 ret = WN_OUT_OF_MEMORY;
1742 }
1743 HeapFree(GetProcessHeap(), 0, wideLocalName);
1744 }
1745 else
1746 ret = WN_OUT_OF_MEMORY;
1747 }
1748 else
1749 ret = WN_BAD_LOCALNAME;
1750 }
1751 if (ret)
1752 SetLastError(ret);
1753 TRACE("Returning %d\n", ret);
1754 return ret;
1755 }
1756
1757 /**************************************************************************
1758 * WNetGetConnectionW [MPR.@]
1759 *
1760 * FIXME: need to test return values under different errors
1761 */
1762 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
1763 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
1764 {
1765 DWORD ret;
1766
1767 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
1768 lpBufferSize);
1769
1770 if (!lpLocalName)
1771 ret = WN_BAD_POINTER;
1772 else if (!lpBufferSize)
1773 ret = WN_BAD_POINTER;
1774 else if (!lpRemoteName && *lpBufferSize)
1775 ret = WN_BAD_POINTER;
1776 else if (!lpLocalName[0])
1777 ret = WN_BAD_LOCALNAME;
1778 else
1779 {
1780 if (lpLocalName[1] == ':')
1781 {
1782 switch(GetDriveTypeW(lpLocalName))
1783 {
1784 case DRIVE_REMOTE:
1785 {
1786 static const WCHAR unc[] = { 'u','n','c','\\' };
1787 WCHAR rremote[MAX_PATH], *remote = rremote;
1788 if (!QueryDosDeviceW( lpLocalName, remote, MAX_PATH )) remote[0] = 0;
1789 else if (!strncmpW(remote, unc, 4))
1790 {
1791 remote += 2;
1792 remote[0] = '\\';
1793 }
1794 else if (remote[0] != '\\' || remote[1] != '\\')
1795 FIXME("Don't know how to convert %s to an unc\n", debugstr_w(remote));
1796
1797 if (strlenW(remote) + 1 > *lpBufferSize)
1798 {
1799 *lpBufferSize = strlenW(remote) + 1;
1800 ret = WN_MORE_DATA;
1801 }
1802 else
1803 {
1804 strcpyW( lpRemoteName, remote );
1805 *lpBufferSize = strlenW(lpRemoteName) + 1;
1806 ret = WN_SUCCESS;
1807 }
1808 break;
1809 }
1810 case DRIVE_REMOVABLE:
1811 case DRIVE_FIXED:
1812 case DRIVE_CDROM:
1813 TRACE("file is local\n");
1814 ret = WN_NOT_CONNECTED;
1815 break;
1816 default:
1817 ret = WN_BAD_LOCALNAME;
1818 }
1819 }
1820 else
1821 ret = WN_BAD_LOCALNAME;
1822 }
1823 if (ret)
1824 SetLastError(ret);
1825 TRACE("Returning %d\n", ret);
1826 return ret;
1827 }
1828
1829 /**************************************************************************
1830 * WNetSetConnectionA [MPR.@]
1831 */
1832 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
1833 LPVOID pvValue )
1834 {
1835 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
1836
1837 SetLastError(WN_NO_NETWORK);
1838 return WN_NO_NETWORK;
1839 }
1840
1841 /**************************************************************************
1842 * WNetSetConnectionW [MPR.@]
1843 */
1844 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
1845 LPVOID pvValue )
1846 {
1847 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
1848
1849 SetLastError(WN_NO_NETWORK);
1850 return WN_NO_NETWORK;
1851 }
1852
1853 /*****************************************************************
1854 * WNetGetUniversalNameA [MPR.@]
1855 */
1856 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
1857 LPVOID lpBuffer, LPDWORD lpBufferSize )
1858 {
1859 DWORD err, size;
1860
1861 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1862 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1863
1864 switch (dwInfoLevel)
1865 {
1866 case UNIVERSAL_NAME_INFO_LEVEL:
1867 {
1868 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
1869
1870 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
1871 if (*lpBufferSize < size)
1872 {
1873 err = WN_MORE_DATA;
1874 break;
1875 }
1876 info->lpUniversalName = (char *)info + sizeof(*info);
1877 lstrcpyA(info->lpUniversalName, lpLocalPath);
1878 *lpBufferSize = size;
1879 err = WN_NO_ERROR;
1880 break;
1881 }
1882 case REMOTE_NAME_INFO_LEVEL:
1883 err = WN_NO_NETWORK;
1884 break;
1885
1886 default:
1887 err = WN_BAD_VALUE;
1888 break;
1889 }
1890
1891 SetLastError(err);
1892 return err;
1893 }
1894
1895 /*****************************************************************
1896 * WNetGetUniversalNameW [MPR.@]
1897 */
1898 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
1899 LPVOID lpBuffer, LPDWORD lpBufferSize )
1900 {
1901 DWORD err, size;
1902
1903 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1904 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
1905
1906 switch (dwInfoLevel)
1907 {
1908 case UNIVERSAL_NAME_INFO_LEVEL:
1909 {
1910 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
1911
1912 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
1913 if (*lpBufferSize < size)
1914 {
1915 err = WN_MORE_DATA;
1916 break;
1917 }
1918 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
1919 lstrcpyW(info->lpUniversalName, lpLocalPath);
1920 *lpBufferSize = size;
1921 err = WN_NO_ERROR;
1922 break;
1923 }
1924 case REMOTE_NAME_INFO_LEVEL:
1925 err = WN_NO_NETWORK;
1926 break;
1927
1928 default:
1929 err = WN_BAD_VALUE;
1930 break;
1931 }
1932
1933 if (err != WN_NO_ERROR) SetLastError(err);
1934 return err;
1935 }
1936
1937
1938
1939 /*
1940 * Other Functions
1941 */
1942
1943 /**************************************************************************
1944 * WNetGetUserA [MPR.@]
1945 *
1946 * FIXME: we should not return ourselves, but the owner of the drive lpName
1947 */
1948 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
1949 {
1950 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
1951 return GetLastError();
1952 }
1953
1954 /*****************************************************************
1955 * WNetGetUserW [MPR.@]
1956 *
1957 * FIXME: we should not return ourselves, but the owner of the drive lpName
1958 */
1959 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
1960 {
1961 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
1962 return GetLastError();
1963 }
1964
1965 /*********************************************************************
1966 * WNetConnectionDialog [MPR.@]
1967 */
1968 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
1969 {
1970 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
1971
1972 SetLastError(WN_NO_NETWORK);
1973 return WN_NO_NETWORK;
1974 }
1975
1976 /*********************************************************************
1977 * WNetConnectionDialog1A [MPR.@]
1978 */
1979 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
1980 {
1981 FIXME( "(%p): stub\n", lpConnDlgStruct );
1982
1983 SetLastError(WN_NO_NETWORK);
1984 return WN_NO_NETWORK;
1985 }
1986
1987 /*********************************************************************
1988 * WNetConnectionDialog1W [MPR.@]
1989 */
1990 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
1991 {
1992 FIXME( "(%p): stub\n", lpConnDlgStruct );
1993
1994 SetLastError(WN_NO_NETWORK);
1995 return WN_NO_NETWORK;
1996 }
1997
1998 /*********************************************************************
1999 * WNetDisconnectDialog [MPR.@]
2000 */
2001 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2002 {
2003 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2004
2005 SetLastError(WN_NO_NETWORK);
2006 return WN_NO_NETWORK;
2007 }
2008
2009 /*********************************************************************
2010 * WNetDisconnectDialog1A [MPR.@]
2011 */
2012 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2013 {
2014 FIXME( "(%p): stub\n", lpConnDlgStruct );
2015
2016 SetLastError(WN_NO_NETWORK);
2017 return WN_NO_NETWORK;
2018 }
2019
2020 /*********************************************************************
2021 * WNetDisconnectDialog1W [MPR.@]
2022 */
2023 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2024 {
2025 FIXME( "(%p): stub\n", lpConnDlgStruct );
2026
2027 SetLastError(WN_NO_NETWORK);
2028 return WN_NO_NETWORK;
2029 }
2030
2031 /*********************************************************************
2032 * WNetGetLastErrorA [MPR.@]
2033 */
2034 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2035 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2036 LPSTR lpNameBuf, DWORD nNameBufSize )
2037 {
2038 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2039 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2040
2041 SetLastError(WN_NO_NETWORK);
2042 return WN_NO_NETWORK;
2043 }
2044
2045 /*********************************************************************
2046 * WNetGetLastErrorW [MPR.@]
2047 */
2048 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2049 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2050 LPWSTR lpNameBuf, DWORD nNameBufSize )
2051 {
2052 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2053 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2054
2055 SetLastError(WN_NO_NETWORK);
2056 return WN_NO_NETWORK;
2057 }
2058
2059 /*********************************************************************
2060 * WNetGetNetworkInformationA [MPR.@]
2061 */
2062 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2063 LPNETINFOSTRUCT lpNetInfoStruct )
2064 {
2065 DWORD ret;
2066
2067 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2068
2069 if (!lpProvider)
2070 ret = WN_BAD_POINTER;
2071 else
2072 {
2073 int len;
2074
2075 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2076 if (len)
2077 {
2078 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2079
2080 if (wideProvider)
2081 {
2082 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2083 len);
2084 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2085 HeapFree(GetProcessHeap(), 0, wideProvider);
2086 }
2087 else
2088 ret = WN_OUT_OF_MEMORY;
2089 }
2090 else
2091 ret = GetLastError();
2092 }
2093 if (ret)
2094 SetLastError(ret);
2095 TRACE("Returning %d\n", ret);
2096 return ret;
2097 }
2098
2099 /*********************************************************************
2100 * WNetGetNetworkInformationW [MPR.@]
2101 */
2102 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2103 LPNETINFOSTRUCT lpNetInfoStruct )
2104 {
2105 DWORD ret;
2106
2107 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2108
2109 if (!lpProvider)
2110 ret = WN_BAD_POINTER;
2111 else if (!lpNetInfoStruct)
2112 ret = WN_BAD_POINTER;
2113 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2114 ret = WN_BAD_VALUE;
2115 else
2116 {
2117 if (providerTable && providerTable->numProviders)
2118 {
2119 DWORD providerIndex = _findProviderIndexW(lpProvider);
2120
2121 if (providerIndex != BAD_PROVIDER_INDEX)
2122 {
2123 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2124 lpNetInfoStruct->dwProviderVersion =
2125 providerTable->table[providerIndex].dwSpecVersion;
2126 lpNetInfoStruct->dwStatus = NO_ERROR;
2127 lpNetInfoStruct->dwCharacteristics = 0;
2128 lpNetInfoStruct->dwHandle = 0;
2129 lpNetInfoStruct->wNetType =
2130 HIWORD(providerTable->table[providerIndex].dwNetType);
2131 lpNetInfoStruct->dwPrinters = -1;
2132 lpNetInfoStruct->dwDrives = -1;
2133 ret = WN_SUCCESS;
2134 }
2135 else
2136 ret = WN_BAD_PROVIDER;
2137 }
2138 else
2139 ret = WN_NO_NETWORK;
2140 }
2141 if (ret)
2142 SetLastError(ret);
2143 TRACE("Returning %d\n", ret);
2144 return ret;
2145 }
2146
2147 /*****************************************************************
2148 * WNetGetProviderNameA [MPR.@]
2149 */
2150 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2151 LPSTR lpProvider, LPDWORD lpBufferSize )
2152 {
2153 DWORD ret;
2154
2155 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2156 lpBufferSize);
2157
2158 if (!lpProvider)
2159 ret = WN_BAD_POINTER;
2160 else if (!lpBufferSize)
2161 ret = WN_BAD_POINTER;
2162 else
2163 {
2164 if (providerTable)
2165 {
2166 DWORD i;
2167
2168 ret = WN_NO_NETWORK;
2169 for (i = 0; i < providerTable->numProviders &&
2170 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2171 i++)
2172 ;
2173 if (i < providerTable->numProviders)
2174 {
2175 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2176 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2177
2178 if (*lpBufferSize < sizeNeeded)
2179 {
2180 *lpBufferSize = sizeNeeded;
2181 ret = WN_MORE_DATA;
2182 }
2183 else
2184 {
2185 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2186 -1, lpProvider, *lpBufferSize, NULL, NULL);
2187 ret = WN_SUCCESS;
2188 /* FIXME: is *lpBufferSize set to the number of characters
2189 * copied? */
2190 }
2191 }
2192 }
2193 else
2194 ret = WN_NO_NETWORK;
2195 }
2196 if (ret)
2197 SetLastError(ret);
2198 TRACE("Returning %d\n", ret);
2199 return ret;
2200 }
2201
2202 /*****************************************************************
2203 * WNetGetProviderNameW [MPR.@]
2204 */
2205 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2206 LPWSTR lpProvider, LPDWORD lpBufferSize )
2207 {
2208 DWORD ret;
2209
2210 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2211 lpBufferSize);
2212
2213 if (!lpProvider)
2214 ret = WN_BAD_POINTER;
2215 else if (!lpBufferSize)
2216 ret = WN_BAD_POINTER;
2217 else
2218 {
2219 if (providerTable)
2220 {
2221 DWORD i;
2222
2223 ret = WN_NO_NETWORK;
2224 for (i = 0; i < providerTable->numProviders &&
2225 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2226 i++)
2227 ;
2228 if (i < providerTable->numProviders)
2229 {
2230 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2231
2232 if (*lpBufferSize < sizeNeeded)
2233 {
2234 *lpBufferSize = sizeNeeded;
2235 ret = WN_MORE_DATA;
2236 }
2237 else
2238 {
2239 strcpyW(lpProvider, providerTable->table[i].name);
2240 ret = WN_SUCCESS;
2241 /* FIXME: is *lpBufferSize set to the number of characters
2242 * copied? */
2243 }
2244 }
2245 }
2246 else
2247 ret = WN_NO_NETWORK;
2248 }
2249 if (ret)
2250 SetLastError(ret);
2251 TRACE("Returning %d\n", ret);
2252 return ret;
2253 }