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