2cf1c8ba053ad8bde0c4a8dd44e3e9b9ae172e3b
[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 PF_NPAddConnection addConnection;
50 PF_NPAddConnection3 addConnection3;
51 } WNetProvider, *PWNetProvider;
52
53 typedef struct _WNetProviderTable
54 {
55 LPWSTR entireNetwork;
56 DWORD numAllocated;
57 DWORD numProviders;
58 WNetProvider table[1];
59 } WNetProviderTable, *PWNetProviderTable;
60
61 #define WNET_ENUMERATOR_TYPE_NULL 0
62 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
63 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
64 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
65
66 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
67 * the enumeration; it represents one of the following types:
68 * - a 'null' enumeration, one that contains no members
69 * - a global enumeration, one that's executed across all providers
70 * - a provider-specific enumeration, one that's only executed by a single
71 * provider
72 * - a context enumeration. I know this contradicts what I just said about
73 * there being no correspondence between the scope and the type, but it's
74 * necessary for the special case that a "Entire Network" entry needs to
75 * be enumerated in an enumeration of the context scope. Thus an enumeration
76 * of the context scope results in a context type enumerator, which morphs
77 * into a global enumeration (so the enumeration continues across all
78 * providers).
79 */
80 typedef struct _WNetEnumerator
81 {
82 DWORD enumType;
83 DWORD providerIndex;
84 HANDLE handle;
85 BOOL providerDone;
86 DWORD dwScope;
87 DWORD dwType;
88 DWORD dwUsage;
89 LPNETRESOURCEW lpNet;
90 } WNetEnumerator, *PWNetEnumerator;
91
92 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
93
94 /* Returns an index (into the global WNetProviderTable) of the provider with
95 * the given name, or BAD_PROVIDER_INDEX if not found.
96 */
97 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
98
99 static PWNetProviderTable providerTable;
100
101 /*
102 * Global provider table functions
103 */
104
105 static void _tryLoadProvider(PCWSTR provider)
106 {
107 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
108 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
109 'S','e','r','v','i','c','e','s','\\',0 };
110 static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
111 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
112 WCHAR serviceName[MAX_PATH];
113 HKEY hKey;
114
115 TRACE("%s\n", debugstr_w(provider));
116 snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt,
117 servicePrefix, provider);
118 serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0';
119 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
120 ERROR_SUCCESS)
121 {
122 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
123 'P','a','t','h',0 };
124 WCHAR providerPath[MAX_PATH];
125 DWORD type, size = sizeof(providerPath);
126
127 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
128 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && (type == REG_SZ || type == REG_EXPAND_SZ))
129 {
130 static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
131 PWSTR name = NULL;
132
133 if (type == REG_EXPAND_SZ)
134 {
135 WCHAR path[MAX_PATH];
136 if (ExpandEnvironmentStringsW(providerPath, path, MAX_PATH)) lstrcpyW( providerPath, path );
137 }
138
139 size = 0;
140 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
141 if (size)
142 {
143 name = HeapAlloc(GetProcessHeap(), 0, size);
144 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
145 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
146 {
147 HeapFree(GetProcessHeap(), 0, name);
148 name = NULL;
149 }
150 }
151 if (name)
152 {
153 HMODULE hLib = LoadLibraryW(providerPath);
154
155 if (hLib)
156 {
157 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
158
159 PF_NPGetCaps getCaps = MPR_GETPROC(NPGetCaps);
160
161 TRACE("loaded lib %p\n", hLib);
162 if (getCaps)
163 {
164 PWNetProvider provider =
165 &providerTable->table[providerTable->numProviders];
166
167 provider->hLib = hLib;
168 provider->name = name;
169 TRACE("name is %s\n", debugstr_w(name));
170 provider->getCaps = getCaps;
171 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
172 provider->dwNetType = getCaps(WNNC_NET_TYPE);
173 TRACE("net type is 0x%08x\n", provider->dwNetType);
174 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
175 if (provider->dwEnumScopes)
176 {
177 TRACE("supports enumeration\n");
178 provider->openEnum = MPR_GETPROC(NPOpenEnum);
179 TRACE("NPOpenEnum %p\n", provider->openEnum);
180 provider->enumResource = MPR_GETPROC(NPEnumResource);
181 TRACE("NPEnumResource %p\n", provider->enumResource);
182 provider->closeEnum = MPR_GETPROC(NPCloseEnum);
183 TRACE("NPCloseEnum %p\n", provider->closeEnum);
184 provider->getResourceInformation = MPR_GETPROC(NPGetResourceInformation);
185 TRACE("NPGetResourceInformation %p\n", provider->getResourceInformation);
186 if (!provider->openEnum ||
187 !provider->enumResource ||
188 !provider->closeEnum)
189 {
190 provider->openEnum = NULL;
191 provider->enumResource = NULL;
192 provider->closeEnum = NULL;
193 provider->dwEnumScopes = 0;
194 WARN("Couldn't load enumeration functions\n");
195 }
196 }
197 provider->addConnection = MPR_GETPROC(NPAddConnection);
198 provider->addConnection3 = MPR_GETPROC(NPAddConnection3);
199 TRACE("NPAddConnection %p\n", provider->addConnection);
200 TRACE("NPAddConnection3 %p\n", provider->addConnection3);
201 providerTable->numProviders++;
202 }
203 else
204 {
205 WARN("Provider %s didn't export NPGetCaps\n",
206 debugstr_w(provider));
207 HeapFree(GetProcessHeap(), 0, name);
208 FreeLibrary(hLib);
209 }
210
211 #undef MPR_GETPROC
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 NETRESOURCEA resourcesA;
1491
1492 memset(&resourcesA, 0, sizeof(resourcesA));
1493 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1494 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1495 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1496 }
1497
1498 /*********************************************************************
1499 * WNetAddConnectionW [MPR.@]
1500 */
1501 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1502 LPCWSTR lpLocalName )
1503 {
1504 NETRESOURCEW resourcesW;
1505
1506 memset(&resourcesW, 0, sizeof(resourcesW));
1507 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1508 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1509 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1510 }
1511
1512 /*********************************************************************
1513 * WNetAddConnection2A [MPR.@]
1514 */
1515 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1516 LPCSTR lpPassword, LPCSTR lpUserID,
1517 DWORD dwFlags )
1518 {
1519 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1520 NULL, 0, NULL);
1521 }
1522
1523 /*********************************************************************
1524 * WNetAddConnection2W [MPR.@]
1525 */
1526 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1527 LPCWSTR lpPassword, LPCWSTR lpUserID,
1528 DWORD dwFlags )
1529 {
1530 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1531 NULL, 0, NULL);
1532 }
1533
1534 /*********************************************************************
1535 * WNetAddConnection3A [MPR.@]
1536 */
1537 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1538 LPCSTR lpPassword, LPCSTR lpUserID,
1539 DWORD dwFlags )
1540 {
1541 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1542 dwFlags, NULL, 0, NULL);
1543 }
1544
1545 /*********************************************************************
1546 * WNetAddConnection3W [MPR.@]
1547 */
1548 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1549 LPCWSTR lpPassword, LPCWSTR lpUserID,
1550 DWORD dwFlags )
1551 {
1552 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1553 dwFlags, NULL, 0, NULL);
1554 }
1555
1556 /* Convert an ANSI string to wide */
1557 static LPWSTR strdupAtoW( LPCSTR str )
1558 {
1559 LPWSTR ret;
1560 INT len;
1561
1562 if (!str) return NULL;
1563 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
1564 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1565 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
1566 return ret;
1567 }
1568
1569 /* Convert ANSI NETRESOURCE struct to wide structure */
1570 static VOID convert_netresourcea_to_w( LPNETRESOURCEA lpNetResourceA,
1571 LPNETRESOURCEW lpNetResourceW )
1572 {
1573 lpNetResourceW->dwScope = lpNetResourceA->dwScope;
1574 lpNetResourceW->dwType = lpNetResourceA->dwType;
1575 lpNetResourceW->dwDisplayType = lpNetResourceA->dwDisplayType;
1576 lpNetResourceW->dwUsage = lpNetResourceA->dwUsage;
1577 lpNetResourceW->lpLocalName = strdupAtoW(lpNetResourceA->lpLocalName);
1578 lpNetResourceW->lpRemoteName = strdupAtoW(lpNetResourceA->lpRemoteName);
1579 lpNetResourceW->lpComment = strdupAtoW(lpNetResourceA->lpComment);
1580 lpNetResourceW->lpProvider = strdupAtoW(lpNetResourceA->lpProvider);
1581 }
1582
1583 /*****************************************************************
1584 * WNetUseConnectionA [MPR.@]
1585 */
1586 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1587 LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
1588 LPSTR lpAccessName, LPDWORD lpBufferSize,
1589 LPDWORD lpResult )
1590 {
1591 NETRESOURCEW resourcesW, *pRes = NULL;
1592 PWSTR passW, userIDW, accessNameW = NULL;
1593 DWORD ret = WN_MORE_DATA;
1594 DWORD bufferSize = 1;
1595 int len;
1596
1597 if (lpNetResource)
1598 {
1599 convert_netresourcea_to_w(lpNetResource, &resourcesW);
1600 pRes = &resourcesW;
1601 }
1602
1603 passW = strdupAtoW(lpPassword);
1604 userIDW = strdupAtoW(lpUserID);
1605
1606 if (lpAccessName && lpBufferSize && *lpBufferSize)
1607 {
1608 WCHAR probe;
1609
1610 ret = WNetUseConnectionW(hwndOwner, pRes, passW, userIDW, dwFlags,
1611 &probe, &bufferSize, lpResult);
1612 if (ret == WN_MORE_DATA)
1613 accessNameW = HeapAlloc(GetProcessHeap(), 0, bufferSize * sizeof(WCHAR));
1614 }
1615
1616 if (ret == WN_MORE_DATA)
1617 {
1618 ret = WNetUseConnectionW(hwndOwner, pRes, passW, userIDW, dwFlags,
1619 accessNameW, &bufferSize, lpResult);
1620 if (ret == WN_SUCCESS)
1621 {
1622 if (lpAccessName && lpBufferSize && *lpBufferSize && accessNameW)
1623 {
1624 len = WideCharToMultiByte(CP_ACP, 0, accessNameW, -1, NULL, 0, NULL, NULL);
1625 if (len)
1626 {
1627 if (len <= *lpBufferSize)
1628 WideCharToMultiByte(CP_ACP, 0, accessNameW, -1, lpAccessName, len, NULL, NULL);
1629 else
1630 {
1631 WNetCancelConnectionW(accessNameW, TRUE);
1632 *lpBufferSize = len;
1633 ret = WN_MORE_DATA;
1634 }
1635 }
1636 }
1637 }
1638 }
1639
1640 if (lpNetResource)
1641 {
1642 HeapFree(GetProcessHeap(), 0, resourcesW.lpLocalName);
1643 HeapFree(GetProcessHeap(), 0, resourcesW.lpRemoteName);
1644 HeapFree(GetProcessHeap(), 0, resourcesW.lpComment);
1645 HeapFree(GetProcessHeap(), 0, resourcesW.lpProvider);
1646 }
1647 HeapFree(GetProcessHeap(), 0, passW);
1648 HeapFree(GetProcessHeap(), 0, userIDW);
1649 HeapFree(GetProcessHeap(), 0, accessNameW);
1650
1651 return ret;
1652 }
1653
1654 /*****************************************************************
1655 * WNetUseConnectionW [MPR.@]
1656 */
1657 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
1658 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
1659 {
1660 WNetProvider *provider;
1661 DWORD index, ret, caps;
1662
1663 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1664 hwndOwner, resource, password, debugstr_w(userid), flags,
1665 accessname, buffer_size, result );
1666
1667 if (!providerTable || providerTable->numProviders == 0)
1668 return WN_NO_NETWORK;
1669
1670 if (!resource)
1671 return ERROR_INVALID_PARAMETER;
1672
1673 if (!resource->lpProvider)
1674 {
1675 FIXME("Networking provider selection is not implemented.\n");
1676 return WN_NO_NETWORK;
1677 }
1678
1679 if (!resource->lpLocalName && (flags & CONNECT_REDIRECT))
1680 {
1681 FIXME("Locale device selection is not implemented.\n");
1682 return WN_NO_NETWORK;
1683 }
1684
1685 if (flags & CONNECT_INTERACTIVE)
1686 return ERROR_BAD_NET_NAME;
1687
1688 index = _findProviderIndexW(resource->lpProvider);
1689 if (index == BAD_PROVIDER_INDEX)
1690 return ERROR_BAD_PROVIDER;
1691
1692 provider = &providerTable->table[index];
1693 caps = provider->getCaps(WNNC_CONNECTION);
1694 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1695 return ERROR_BAD_PROVIDER;
1696
1697 if (accessname && buffer_size && *buffer_size)
1698 {
1699 DWORD len;
1700
1701 if (resource->lpLocalName)
1702 len = strlenW(resource->lpLocalName);
1703 else
1704 len = strlenW(resource->lpRemoteName);
1705
1706 if (++len > *buffer_size)
1707 {
1708 *buffer_size = len;
1709 return ERROR_MORE_DATA;
1710 }
1711 }
1712 else
1713 accessname = NULL;
1714
1715 ret = WN_ACCESS_DENIED;
1716 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1717 ret = provider->addConnection3(hwndOwner, resource, (LPWSTR)password, (LPWSTR)userid, flags);
1718 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1719 ret = provider->addConnection(resource, (LPWSTR)password, (LPWSTR)userid);
1720
1721 if (ret == WN_SUCCESS && accessname)
1722 {
1723 if (resource->lpLocalName)
1724 strcpyW(accessname, resource->lpLocalName);
1725 else
1726 strcpyW(accessname, resource->lpRemoteName);
1727 }
1728
1729 return ret;
1730 }
1731
1732 /*********************************************************************
1733 * WNetCancelConnectionA [MPR.@]
1734 */
1735 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1736 {
1737 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1738
1739 return WN_SUCCESS;
1740 }
1741
1742 /*********************************************************************
1743 * WNetCancelConnectionW [MPR.@]
1744 */
1745 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1746 {
1747 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1748
1749 return WN_SUCCESS;
1750 }
1751
1752 /*********************************************************************
1753 * WNetCancelConnection2A [MPR.@]
1754 */
1755 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1756 {
1757 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1758
1759 return WN_SUCCESS;
1760 }
1761
1762 /*********************************************************************
1763 * WNetCancelConnection2W [MPR.@]
1764 */
1765 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1766 {
1767 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1768
1769 return WN_SUCCESS;
1770 }
1771
1772 /*****************************************************************
1773 * WNetRestoreConnectionA [MPR.@]
1774 */
1775 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
1776 {
1777 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1778
1779 SetLastError(WN_NO_NETWORK);
1780 return WN_NO_NETWORK;
1781 }
1782
1783 /*****************************************************************
1784 * WNetRestoreConnectionW [MPR.@]
1785 */
1786 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
1787 {
1788 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1789
1790 SetLastError(WN_NO_NETWORK);
1791 return WN_NO_NETWORK;
1792 }
1793
1794 /**************************************************************************
1795 * WNetGetConnectionA [MPR.@]
1796 *
1797 * RETURNS
1798 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1799 * - WN_NOT_CONNECTED drive is a local drive
1800 * - WN_MORE_DATA buffer isn't big enough
1801 * - WN_SUCCESS success (net path in buffer)
1802 *
1803 * FIXME: need to test return values under different errors
1804 */
1805 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1806 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1807 {
1808 DWORD ret;
1809
1810 if (!lpLocalName)
1811 ret = WN_BAD_POINTER;
1812 else if (!lpBufferSize)
1813 ret = WN_BAD_POINTER;
1814 else if (!lpRemoteName && *lpBufferSize)
1815 ret = WN_BAD_POINTER;
1816 else
1817 {
1818 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1819
1820 if (len)
1821 {
1822 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1823
1824 if (wideLocalName)
1825 {
1826 WCHAR wideRemoteStatic[MAX_PATH];
1827 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1828
1829 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1830
1831 /* try once without memory allocation */
1832 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1833 &wideRemoteSize);
1834 if (ret == WN_SUCCESS)
1835 {
1836 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1837 -1, NULL, 0, NULL, NULL);
1838
1839 if (len <= *lpBufferSize)
1840 {
1841 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1842 lpRemoteName, *lpBufferSize, NULL, NULL);
1843 ret = WN_SUCCESS;
1844 }
1845 else
1846 {
1847 *lpBufferSize = len;
1848 ret = WN_MORE_DATA;
1849 }
1850 }
1851 else if (ret == WN_MORE_DATA)
1852 {
1853 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1854 wideRemoteSize * sizeof(WCHAR));
1855
1856 if (wideRemote)
1857 {
1858 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1859 &wideRemoteSize);
1860 if (ret == WN_SUCCESS)
1861 {
1862 if (len <= *lpBufferSize)
1863 {
1864 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1865 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1866 ret = WN_SUCCESS;
1867 }
1868 else
1869 {
1870 *lpBufferSize = len;
1871 ret = WN_MORE_DATA;
1872 }
1873 }
1874 HeapFree(GetProcessHeap(), 0, wideRemote);
1875 }
1876 else
1877 ret = WN_OUT_OF_MEMORY;
1878 }
1879 HeapFree(GetProcessHeap(), 0, wideLocalName);
1880 }
1881 else
1882 ret = WN_OUT_OF_MEMORY;
1883 }
1884 else
1885 ret = WN_BAD_LOCALNAME;
1886 }
1887 if (ret)
1888 SetLastError(ret);
1889 TRACE("Returning %d\n", ret);
1890 return ret;
1891 }
1892
1893 /* find the network connection for a given drive; helper for WNetGetConnection */
1894 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
1895 {
1896 char buffer[1024];
1897 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
1898 HANDLE mgr;
1899 DWORD ret = WN_NOT_CONNECTED;
1900 DWORD bytes_returned;
1901
1902 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
1903 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1904 0, 0 )) == INVALID_HANDLE_VALUE)
1905 {
1906 ERR( "failed to open mount manager err %u\n", GetLastError() );
1907 return ret;
1908 }
1909 memset( data, 0, sizeof(*data) );
1910 data->letter = letter;
1911 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
1912 data, sizeof(buffer), &bytes_returned, NULL ))
1913 {
1914 char *p, *mount_point = buffer + data->mount_point_offset;
1915 DWORD len;
1916
1917 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
1918 {
1919 mount_point += 2;
1920 mount_point[0] = '\\';
1921 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
1922
1923 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
1924 if (len > *size)
1925 {
1926 *size = len;
1927 ret = WN_MORE_DATA;
1928 }
1929 else
1930 {
1931 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
1932 ret = WN_SUCCESS;
1933 }
1934 }
1935 }
1936 CloseHandle( mgr );
1937 return ret;
1938 }
1939
1940 /**************************************************************************
1941 * WNetGetConnectionW [MPR.@]
1942 *
1943 * FIXME: need to test return values under different errors
1944 */
1945 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
1946 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
1947 {
1948 DWORD ret;
1949
1950 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
1951 lpBufferSize);
1952
1953 if (!lpLocalName)
1954 ret = WN_BAD_POINTER;
1955 else if (!lpBufferSize)
1956 ret = WN_BAD_POINTER;
1957 else if (!lpRemoteName && *lpBufferSize)
1958 ret = WN_BAD_POINTER;
1959 else if (!lpLocalName[0])
1960 ret = WN_BAD_LOCALNAME;
1961 else
1962 {
1963 if (lpLocalName[1] == ':')
1964 {
1965 switch(GetDriveTypeW(lpLocalName))
1966 {
1967 case DRIVE_REMOTE:
1968 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
1969 break;
1970 case DRIVE_REMOVABLE:
1971 case DRIVE_FIXED:
1972 case DRIVE_CDROM:
1973 TRACE("file is local\n");
1974 ret = WN_NOT_CONNECTED;
1975 break;
1976 default:
1977 ret = WN_BAD_LOCALNAME;
1978 }
1979 }
1980 else
1981 ret = WN_BAD_LOCALNAME;
1982 }
1983 if (ret)
1984 SetLastError(ret);
1985 TRACE("Returning %d\n", ret);
1986 return ret;
1987 }
1988
1989 /**************************************************************************
1990 * WNetSetConnectionA [MPR.@]
1991 */
1992 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
1993 LPVOID pvValue )
1994 {
1995 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
1996
1997 SetLastError(WN_NO_NETWORK);
1998 return WN_NO_NETWORK;
1999 }
2000
2001 /**************************************************************************
2002 * WNetSetConnectionW [MPR.@]
2003 */
2004 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2005 LPVOID pvValue )
2006 {
2007 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2008
2009 SetLastError(WN_NO_NETWORK);
2010 return WN_NO_NETWORK;
2011 }
2012
2013 /*****************************************************************
2014 * WNetGetUniversalNameA [MPR.@]
2015 */
2016 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2017 LPVOID lpBuffer, LPDWORD lpBufferSize )
2018 {
2019 DWORD err, size;
2020
2021 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2022 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2023
2024 switch (dwInfoLevel)
2025 {
2026 case UNIVERSAL_NAME_INFO_LEVEL:
2027 {
2028 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2029
2030 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2031 {
2032 err = ERROR_NOT_CONNECTED;
2033 break;
2034 }
2035
2036 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2037 if (*lpBufferSize < size)
2038 {
2039 err = WN_MORE_DATA;
2040 break;
2041 }
2042 info->lpUniversalName = (char *)info + sizeof(*info);
2043 lstrcpyA(info->lpUniversalName, lpLocalPath);
2044 err = WN_NO_ERROR;
2045 break;
2046 }
2047 case REMOTE_NAME_INFO_LEVEL:
2048 err = WN_NO_NETWORK;
2049 break;
2050
2051 default:
2052 err = WN_BAD_VALUE;
2053 break;
2054 }
2055
2056 SetLastError(err);
2057 return err;
2058 }
2059
2060 /*****************************************************************
2061 * WNetGetUniversalNameW [MPR.@]
2062 */
2063 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2064 LPVOID lpBuffer, LPDWORD lpBufferSize )
2065 {
2066 DWORD err, size;
2067
2068 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2069 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2070
2071 switch (dwInfoLevel)
2072 {
2073 case UNIVERSAL_NAME_INFO_LEVEL:
2074 {
2075 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2076
2077 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2078 {
2079 err = ERROR_NOT_CONNECTED;
2080 break;
2081 }
2082
2083 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2084 if (*lpBufferSize < size)
2085 {
2086 err = WN_MORE_DATA;
2087 break;
2088 }
2089 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2090 lstrcpyW(info->lpUniversalName, lpLocalPath);
2091 err = WN_NO_ERROR;
2092 break;
2093 }
2094 case REMOTE_NAME_INFO_LEVEL:
2095 err = WN_NOT_CONNECTED;
2096 break;
2097
2098 default:
2099 err = WN_BAD_VALUE;
2100 break;
2101 }
2102
2103 if (err != WN_NO_ERROR) SetLastError(err);
2104 return err;
2105 }
2106
2107
2108
2109 /*
2110 * Other Functions
2111 */
2112
2113 /**************************************************************************
2114 * WNetGetUserA [MPR.@]
2115 *
2116 * FIXME: we should not return ourselves, but the owner of the drive lpName
2117 */
2118 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2119 {
2120 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2121 return GetLastError();
2122 }
2123
2124 /*****************************************************************
2125 * WNetGetUserW [MPR.@]
2126 *
2127 * FIXME: we should not return ourselves, but the owner of the drive lpName
2128 */
2129 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2130 {
2131 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2132 return GetLastError();
2133 }
2134
2135 /*********************************************************************
2136 * WNetConnectionDialog [MPR.@]
2137 */
2138 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2139 {
2140 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2141
2142 SetLastError(WN_NO_NETWORK);
2143 return WN_NO_NETWORK;
2144 }
2145
2146 /*********************************************************************
2147 * WNetConnectionDialog1A [MPR.@]
2148 */
2149 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2150 {
2151 FIXME( "(%p): stub\n", lpConnDlgStruct );
2152
2153 SetLastError(WN_NO_NETWORK);
2154 return WN_NO_NETWORK;
2155 }
2156
2157 /*********************************************************************
2158 * WNetConnectionDialog1W [MPR.@]
2159 */
2160 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2161 {
2162 FIXME( "(%p): stub\n", lpConnDlgStruct );
2163
2164 SetLastError(WN_NO_NETWORK);
2165 return WN_NO_NETWORK;
2166 }
2167
2168 /*********************************************************************
2169 * WNetDisconnectDialog [MPR.@]
2170 */
2171 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2172 {
2173 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2174
2175 SetLastError(WN_NO_NETWORK);
2176 return WN_NO_NETWORK;
2177 }
2178
2179 /*********************************************************************
2180 * WNetDisconnectDialog1A [MPR.@]
2181 */
2182 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2183 {
2184 FIXME( "(%p): stub\n", lpConnDlgStruct );
2185
2186 SetLastError(WN_NO_NETWORK);
2187 return WN_NO_NETWORK;
2188 }
2189
2190 /*********************************************************************
2191 * WNetDisconnectDialog1W [MPR.@]
2192 */
2193 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2194 {
2195 FIXME( "(%p): stub\n", lpConnDlgStruct );
2196
2197 SetLastError(WN_NO_NETWORK);
2198 return WN_NO_NETWORK;
2199 }
2200
2201 /*********************************************************************
2202 * WNetGetLastErrorA [MPR.@]
2203 */
2204 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2205 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2206 LPSTR lpNameBuf, DWORD nNameBufSize )
2207 {
2208 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2209 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2210
2211 SetLastError(WN_NO_NETWORK);
2212 return WN_NO_NETWORK;
2213 }
2214
2215 /*********************************************************************
2216 * WNetGetLastErrorW [MPR.@]
2217 */
2218 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2219 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2220 LPWSTR lpNameBuf, DWORD nNameBufSize )
2221 {
2222 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2223 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2224
2225 SetLastError(WN_NO_NETWORK);
2226 return WN_NO_NETWORK;
2227 }
2228
2229 /*********************************************************************
2230 * WNetGetNetworkInformationA [MPR.@]
2231 */
2232 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2233 LPNETINFOSTRUCT lpNetInfoStruct )
2234 {
2235 DWORD ret;
2236
2237 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2238
2239 if (!lpProvider)
2240 ret = WN_BAD_POINTER;
2241 else
2242 {
2243 int len;
2244
2245 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2246 if (len)
2247 {
2248 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2249
2250 if (wideProvider)
2251 {
2252 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2253 len);
2254 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2255 HeapFree(GetProcessHeap(), 0, wideProvider);
2256 }
2257 else
2258 ret = WN_OUT_OF_MEMORY;
2259 }
2260 else
2261 ret = GetLastError();
2262 }
2263 if (ret)
2264 SetLastError(ret);
2265 TRACE("Returning %d\n", ret);
2266 return ret;
2267 }
2268
2269 /*********************************************************************
2270 * WNetGetNetworkInformationW [MPR.@]
2271 */
2272 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2273 LPNETINFOSTRUCT lpNetInfoStruct )
2274 {
2275 DWORD ret;
2276
2277 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2278
2279 if (!lpProvider)
2280 ret = WN_BAD_POINTER;
2281 else if (!lpNetInfoStruct)
2282 ret = WN_BAD_POINTER;
2283 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2284 ret = WN_BAD_VALUE;
2285 else
2286 {
2287 if (providerTable && providerTable->numProviders)
2288 {
2289 DWORD providerIndex = _findProviderIndexW(lpProvider);
2290
2291 if (providerIndex != BAD_PROVIDER_INDEX)
2292 {
2293 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2294 lpNetInfoStruct->dwProviderVersion =
2295 providerTable->table[providerIndex].dwSpecVersion;
2296 lpNetInfoStruct->dwStatus = NO_ERROR;
2297 lpNetInfoStruct->dwCharacteristics = 0;
2298 lpNetInfoStruct->dwHandle = 0;
2299 lpNetInfoStruct->wNetType =
2300 HIWORD(providerTable->table[providerIndex].dwNetType);
2301 lpNetInfoStruct->dwPrinters = -1;
2302 lpNetInfoStruct->dwDrives = -1;
2303 ret = WN_SUCCESS;
2304 }
2305 else
2306 ret = WN_BAD_PROVIDER;
2307 }
2308 else
2309 ret = WN_NO_NETWORK;
2310 }
2311 if (ret)
2312 SetLastError(ret);
2313 TRACE("Returning %d\n", ret);
2314 return ret;
2315 }
2316
2317 /*****************************************************************
2318 * WNetGetProviderNameA [MPR.@]
2319 */
2320 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2321 LPSTR lpProvider, LPDWORD lpBufferSize )
2322 {
2323 DWORD ret;
2324
2325 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2326 lpBufferSize);
2327
2328 if (!lpProvider)
2329 ret = WN_BAD_POINTER;
2330 else if (!lpBufferSize)
2331 ret = WN_BAD_POINTER;
2332 else
2333 {
2334 if (providerTable)
2335 {
2336 DWORD i;
2337
2338 ret = WN_NO_NETWORK;
2339 for (i = 0; i < providerTable->numProviders &&
2340 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2341 i++)
2342 ;
2343 if (i < providerTable->numProviders)
2344 {
2345 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2346 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2347
2348 if (*lpBufferSize < sizeNeeded)
2349 {
2350 *lpBufferSize = sizeNeeded;
2351 ret = WN_MORE_DATA;
2352 }
2353 else
2354 {
2355 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2356 -1, lpProvider, *lpBufferSize, NULL, NULL);
2357 ret = WN_SUCCESS;
2358 /* FIXME: is *lpBufferSize set to the number of characters
2359 * copied? */
2360 }
2361 }
2362 }
2363 else
2364 ret = WN_NO_NETWORK;
2365 }
2366 if (ret)
2367 SetLastError(ret);
2368 TRACE("Returning %d\n", ret);
2369 return ret;
2370 }
2371
2372 /*****************************************************************
2373 * WNetGetProviderNameW [MPR.@]
2374 */
2375 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2376 LPWSTR lpProvider, LPDWORD lpBufferSize )
2377 {
2378 DWORD ret;
2379
2380 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2381 lpBufferSize);
2382
2383 if (!lpProvider)
2384 ret = WN_BAD_POINTER;
2385 else if (!lpBufferSize)
2386 ret = WN_BAD_POINTER;
2387 else
2388 {
2389 if (providerTable)
2390 {
2391 DWORD i;
2392
2393 ret = WN_NO_NETWORK;
2394 for (i = 0; i < providerTable->numProviders &&
2395 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2396 i++)
2397 ;
2398 if (i < providerTable->numProviders)
2399 {
2400 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2401
2402 if (*lpBufferSize < sizeNeeded)
2403 {
2404 *lpBufferSize = sizeNeeded;
2405 ret = WN_MORE_DATA;
2406 }
2407 else
2408 {
2409 strcpyW(lpProvider, providerTable->table[i].name);
2410 ret = WN_SUCCESS;
2411 /* FIXME: is *lpBufferSize set to the number of characters
2412 * copied? */
2413 }
2414 }
2415 }
2416 else
2417 ret = WN_NO_NETWORK;
2418 }
2419 if (ret)
2420 SetLastError(ret);
2421 TRACE("Returning %d\n", ret);
2422 return ret;
2423 }