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