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