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