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