[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 #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 DWORD wnet_use_connection( struct use_connection_context *ctxt )
1617 {
1618 WNetProvider *provider;
1619 DWORD index, ret, caps;
1620 BOOLEAN redirect = FALSE;
1621 WCHAR letter[3] = {'z', ':', 0};
1622
1623 if (!providerTable || providerTable->numProviders == 0)
1624 return WN_NO_NETWORK;
1625
1626 if (!ctxt->resource)
1627 return ERROR_INVALID_PARAMETER;
1628
1629 if (!ctxt->resource->lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
1630 {
1631 if (ctxt->resource->dwType != RESOURCETYPE_DISK && ctxt->resource->dwType != RESOURCETYPE_PRINT)
1632 {
1633 return ERROR_BAD_DEV_TYPE;
1634 }
1635
1636 if (ctxt->resource->dwType == RESOURCETYPE_PRINT)
1637 {
1638 FIXME("Locale device selection is not implemented for printers.\n");
1639 return WN_NO_NETWORK;
1640 }
1641
1642 redirect = TRUE;
1643 ctxt->resource->lpLocalName = letter;
1644 }
1645
1646 if (!ctxt->resource->lpProvider)
1647 {
1648 FIXME("Networking provider selection is not implemented.\n");
1649 ret = WN_NO_NETWORK;
1650 goto done;
1651 }
1652
1653 if (ctxt->flags & CONNECT_INTERACTIVE)
1654 {
1655 ret = ERROR_BAD_NET_NAME;
1656 goto done;
1657 }
1658
1659 index = _findProviderIndexW(ctxt->resource->lpProvider);
1660 if (index == BAD_PROVIDER_INDEX)
1661 {
1662 ret = ERROR_BAD_PROVIDER;
1663 goto done;
1664 }
1665
1666 provider = &providerTable->table[index];
1667 caps = provider->getCaps(WNNC_CONNECTION);
1668 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1669 {
1670 ret = ERROR_BAD_PROVIDER;
1671 goto done;
1672 }
1673
1674 if ((ret = ctxt->pre_set_accessname(ctxt)))
1675 {
1676 goto done;
1677 }
1678
1679 ret = WN_ACCESS_DENIED;
1680 do
1681 {
1682 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1683 ret = provider->addConnection3(ctxt->hwndOwner, ctxt->resource, ctxt->password, ctxt->userid, ctxt->flags);
1684 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1685 ret = provider->addConnection(ctxt->resource, ctxt->password, ctxt->userid);
1686
1687 if (redirect)
1688 letter[0] -= 1;
1689 } while (redirect && ret == WN_ALREADY_CONNECTED && letter[0] >= 'c');
1690
1691 if (ret == WN_SUCCESS && ctxt->accessname)
1692 ctxt->set_accessname(ctxt);
1693
1694 done:
1695 if (redirect)
1696 ctxt->resource->lpLocalName = NULL;
1697
1698 return ret;
1699 }
1700
1701 /*****************************************************************
1702 * WNetUseConnectionW [MPR.@]
1703 */
1704 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
1705 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
1706 {
1707 struct use_connection_context ctxt;
1708
1709 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1710 hwndOwner, resource, password, debugstr_w(userid), flags,
1711 accessname, buffer_size, result );
1712
1713 ctxt.hwndOwner = hwndOwner;
1714 ctxt.resource = resource;
1715 ctxt.resourceA = NULL;
1716 ctxt.password = (WCHAR*)password;
1717 ctxt.userid = (WCHAR*)userid;
1718 ctxt.flags = flags;
1719 ctxt.accessname = accessname;
1720 ctxt.buffer_size = buffer_size;
1721 ctxt.result = result;
1722 ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
1723 ctxt.set_accessname = use_connection_set_accessnameW;
1724
1725 return wnet_use_connection(&ctxt);
1726 }
1727
1728 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt)
1729 {
1730 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1731 {
1732 DWORD len;
1733
1734 if (ctxt->resourceA->lpLocalName)
1735 len = strlen(ctxt->resourceA->lpLocalName);
1736 else
1737 len = strlen(ctxt->resourceA->lpRemoteName);
1738
1739 if (++len > *ctxt->buffer_size)
1740 {
1741 *ctxt->buffer_size = len;
1742 return ERROR_MORE_DATA;
1743 }
1744 }
1745 else
1746 ctxt->accessname = NULL;
1747
1748 return ERROR_SUCCESS;
1749 }
1750
1751 static void use_connection_set_accessnameA(struct use_connection_context *ctxt)
1752 {
1753 char *accessname = ctxt->accessname;
1754 if (ctxt->resourceA->lpLocalName)
1755 strcpy(accessname, ctxt->resourceA->lpLocalName);
1756 else
1757 strcpy(accessname, ctxt->resourceA->lpRemoteName);
1758 }
1759
1760 static LPWSTR strdupAtoW( LPCSTR str )
1761 {
1762 LPWSTR ret;
1763 INT len;
1764
1765 if (!str) return NULL;
1766 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
1767 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1768 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
1769 return ret;
1770 }
1771
1772 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
1773 {
1774 resourceW->dwScope = resourceA->dwScope;
1775 resourceW->dwType = resourceA->dwType;
1776 resourceW->dwDisplayType = resourceA->dwDisplayType;
1777 resourceW->dwUsage = resourceA->dwUsage;
1778 resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
1779 resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
1780 resourceW->lpComment = strdupAtoW(resourceA->lpComment);
1781 resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
1782 }
1783
1784 static void free_netresourceW( NETRESOURCEW *resource )
1785 {
1786 HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
1787 HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
1788 HeapFree(GetProcessHeap(), 0, resource->lpComment);
1789 HeapFree(GetProcessHeap(), 0, resource->lpProvider);
1790 }
1791
1792 /*****************************************************************
1793 * WNetUseConnectionA [MPR.@]
1794 */
1795 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
1796 LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
1797 DWORD *buffer_size, DWORD *result )
1798 {
1799 struct use_connection_context ctxt;
1800 NETRESOURCEW resourceW;
1801 DWORD ret;
1802
1803 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
1804 accessname, buffer_size, result );
1805
1806 netresource_a_to_w(resource, &resourceW);
1807
1808 ctxt.hwndOwner = hwndOwner;
1809 ctxt.resource = &resourceW;
1810 ctxt.resourceA = resource;
1811 ctxt.password = strdupAtoW(password);
1812 ctxt.userid = strdupAtoW(userid);
1813 ctxt.flags = flags;
1814 ctxt.accessname = accessname;
1815 ctxt.buffer_size = buffer_size;
1816 ctxt.result = result;
1817 ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
1818 ctxt.set_accessname = use_connection_set_accessnameA;
1819
1820 ret = wnet_use_connection(&ctxt);
1821
1822 free_netresourceW(&resourceW);
1823 HeapFree(GetProcessHeap(), 0, ctxt.password);
1824 HeapFree(GetProcessHeap(), 0, ctxt.userid);
1825
1826 return ret;
1827 }
1828
1829 /*********************************************************************
1830 * WNetCancelConnectionA [MPR.@]
1831 */
1832 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1833 {
1834 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1835
1836 return WN_SUCCESS;
1837 }
1838
1839 /*********************************************************************
1840 * WNetCancelConnectionW [MPR.@]
1841 */
1842 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1843 {
1844 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1845
1846 return WN_SUCCESS;
1847 }
1848
1849 /*********************************************************************
1850 * WNetCancelConnection2A [MPR.@]
1851 */
1852 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1853 {
1854 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1855
1856 return WN_SUCCESS;
1857 }
1858
1859 /*********************************************************************
1860 * WNetCancelConnection2W [MPR.@]
1861 */
1862 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1863 {
1864 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1865
1866 return WN_SUCCESS;
1867 }
1868
1869 /*****************************************************************
1870 * WNetRestoreConnectionA [MPR.@]
1871 */
1872 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
1873 {
1874 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1875
1876 SetLastError(WN_NO_NETWORK);
1877 return WN_NO_NETWORK;
1878 }
1879
1880 /*****************************************************************
1881 * WNetRestoreConnectionW [MPR.@]
1882 */
1883 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
1884 {
1885 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1886
1887 SetLastError(WN_NO_NETWORK);
1888 return WN_NO_NETWORK;
1889 }
1890
1891 /**************************************************************************
1892 * WNetGetConnectionA [MPR.@]
1893 *
1894 * RETURNS
1895 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1896 * - WN_NOT_CONNECTED drive is a local drive
1897 * - WN_MORE_DATA buffer isn't big enough
1898 * - WN_SUCCESS success (net path in buffer)
1899 *
1900 * FIXME: need to test return values under different errors
1901 */
1902 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1903 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1904 {
1905 DWORD ret;
1906
1907 if (!lpLocalName)
1908 ret = WN_BAD_POINTER;
1909 else if (!lpBufferSize)
1910 ret = WN_BAD_POINTER;
1911 else if (!lpRemoteName && *lpBufferSize)
1912 ret = WN_BAD_POINTER;
1913 else
1914 {
1915 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1916
1917 if (len)
1918 {
1919 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1920
1921 if (wideLocalName)
1922 {
1923 WCHAR wideRemoteStatic[MAX_PATH];
1924 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1925
1926 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1927
1928 /* try once without memory allocation */
1929 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1930 &wideRemoteSize);
1931 if (ret == WN_SUCCESS)
1932 {
1933 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1934 -1, NULL, 0, NULL, NULL);
1935
1936 if (len <= *lpBufferSize)
1937 {
1938 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1939 lpRemoteName, *lpBufferSize, NULL, NULL);
1940 ret = WN_SUCCESS;
1941 }
1942 else
1943 {
1944 *lpBufferSize = len;
1945 ret = WN_MORE_DATA;
1946 }
1947 }
1948 else if (ret == WN_MORE_DATA)
1949 {
1950 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1951 wideRemoteSize * sizeof(WCHAR));
1952
1953 if (wideRemote)
1954 {
1955 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1956 &wideRemoteSize);
1957 if (ret == WN_SUCCESS)
1958 {
1959 if (len <= *lpBufferSize)
1960 {
1961 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1962 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1963 ret = WN_SUCCESS;
1964 }
1965 else
1966 {
1967 *lpBufferSize = len;
1968 ret = WN_MORE_DATA;
1969 }
1970 }
1971 HeapFree(GetProcessHeap(), 0, wideRemote);
1972 }
1973 else
1974 ret = WN_OUT_OF_MEMORY;
1975 }
1976 HeapFree(GetProcessHeap(), 0, wideLocalName);
1977 }
1978 else
1979 ret = WN_OUT_OF_MEMORY;
1980 }
1981 else
1982 ret = WN_BAD_LOCALNAME;
1983 }
1984 if (ret)
1985 SetLastError(ret);
1986 TRACE("Returning %d\n", ret);
1987 return ret;
1988 }
1989
1990 /* find the network connection for a given drive; helper for WNetGetConnection */
1991 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
1992 {
1993 #ifndef __REACTOS__
1994 char buffer[1024];
1995 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
1996 HANDLE mgr;
1997 DWORD ret = WN_NOT_CONNECTED;
1998 DWORD bytes_returned;
1999
2000 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
2001 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
2002 0, 0 )) == INVALID_HANDLE_VALUE)
2003 {
2004 ERR( "failed to open mount manager err %u\n", GetLastError() );
2005 return ret;
2006 }
2007 memset( data, 0, sizeof(*data) );
2008 data->letter = letter;
2009 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
2010 data, sizeof(buffer), &bytes_returned, NULL ))
2011 {
2012 char *p, *mount_point = buffer + data->mount_point_offset;
2013 DWORD len;
2014
2015 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
2016 {
2017 mount_point += 2;
2018 mount_point[0] = '\\';
2019 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
2020
2021 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
2022 if (len > *size)
2023 {
2024 *size = len;
2025 ret = WN_MORE_DATA;
2026 }
2027 else
2028 {
2029 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
2030 ret = WN_SUCCESS;
2031 }
2032 }
2033 }
2034 CloseHandle( mgr );
2035 return ret;
2036 #else
2037 DWORD ret = WN_NO_NETWORK;
2038 DWORD index;
2039 WCHAR local[3] = {letter, ':', 0};
2040
2041 if (providerTable != NULL)
2042 {
2043 for (index = 0; index < providerTable->numProviders; index++)
2044 {
2045 if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2046 WNNC_CON_GETCONNECTIONS)
2047 {
2048 if (providerTable->table[index].getConnection)
2049 ret = providerTable->table[index].getConnection(
2050 local, remote, size);
2051 else
2052 ret = WN_NO_NETWORK;
2053 if (ret == WN_SUCCESS || ret == WN_MORE_DATA)
2054 break;
2055 }
2056 }
2057 }
2058 if (ret)
2059 SetLastError(ret);
2060 return ret;
2061 #endif
2062 }
2063
2064 /**************************************************************************
2065 * WNetGetConnectionW [MPR.@]
2066 *
2067 * FIXME: need to test return values under different errors
2068 */
2069 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
2070 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
2071 {
2072 DWORD ret;
2073
2074 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
2075 lpBufferSize);
2076
2077 if (!lpLocalName)
2078 ret = WN_BAD_POINTER;
2079 else if (!lpBufferSize)
2080 ret = WN_BAD_POINTER;
2081 else if (!lpRemoteName && *lpBufferSize)
2082 ret = WN_BAD_POINTER;
2083 else if (!lpLocalName[0])
2084 ret = WN_BAD_LOCALNAME;
2085 else
2086 {
2087 if (lpLocalName[1] == ':')
2088 {
2089 switch(GetDriveTypeW(lpLocalName))
2090 {
2091 case DRIVE_REMOTE:
2092 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
2093 break;
2094 case DRIVE_REMOVABLE:
2095 case DRIVE_FIXED:
2096 case DRIVE_CDROM:
2097 TRACE("file is local\n");
2098 ret = WN_NOT_CONNECTED;
2099 break;
2100 default:
2101 ret = WN_BAD_LOCALNAME;
2102 }
2103 }
2104 else
2105 ret = WN_BAD_LOCALNAME;
2106 }
2107 if (ret)
2108 SetLastError(ret);
2109 TRACE("Returning %d\n", ret);
2110 return ret;
2111 }
2112
2113 /**************************************************************************
2114 * WNetSetConnectionA [MPR.@]
2115 */
2116 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
2117 LPVOID pvValue )
2118 {
2119 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
2120
2121 SetLastError(WN_NO_NETWORK);
2122 return WN_NO_NETWORK;
2123 }
2124
2125 /**************************************************************************
2126 * WNetSetConnectionW [MPR.@]
2127 */
2128 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2129 LPVOID pvValue )
2130 {
2131 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2132
2133 SetLastError(WN_NO_NETWORK);
2134 return WN_NO_NETWORK;
2135 }
2136
2137 /*****************************************************************
2138 * WNetGetUniversalNameA [MPR.@]
2139 */
2140 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2141 LPVOID lpBuffer, LPDWORD lpBufferSize )
2142 {
2143 DWORD err, size;
2144
2145 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2146 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2147
2148 switch (dwInfoLevel)
2149 {
2150 case UNIVERSAL_NAME_INFO_LEVEL:
2151 {
2152 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2153
2154 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2155 {
2156 err = ERROR_NOT_CONNECTED;
2157 break;
2158 }
2159
2160 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2161 if (*lpBufferSize < size)
2162 {
2163 err = WN_MORE_DATA;
2164 break;
2165 }
2166 info->lpUniversalName = (char *)info + sizeof(*info);
2167 lstrcpyA(info->lpUniversalName, lpLocalPath);
2168 err = WN_NO_ERROR;
2169 break;
2170 }
2171 case REMOTE_NAME_INFO_LEVEL:
2172 err = WN_NOT_CONNECTED;
2173 break;
2174
2175 default:
2176 err = WN_BAD_VALUE;
2177 break;
2178 }
2179
2180 SetLastError(err);
2181 return err;
2182 }
2183
2184 /*****************************************************************
2185 * WNetGetUniversalNameW [MPR.@]
2186 */
2187 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2188 LPVOID lpBuffer, LPDWORD lpBufferSize )
2189 {
2190 DWORD err, size;
2191
2192 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2193 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2194
2195 switch (dwInfoLevel)
2196 {
2197 case UNIVERSAL_NAME_INFO_LEVEL:
2198 {
2199 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2200
2201 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2202 {
2203 err = ERROR_NOT_CONNECTED;
2204 break;
2205 }
2206
2207 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2208 if (*lpBufferSize < size)
2209 {
2210 err = WN_MORE_DATA;
2211 break;
2212 }
2213 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2214 lstrcpyW(info->lpUniversalName, lpLocalPath);
2215 err = WN_NO_ERROR;
2216 break;
2217 }
2218 case REMOTE_NAME_INFO_LEVEL:
2219 err = WN_NO_NETWORK;
2220 break;
2221
2222 default:
2223 err = WN_BAD_VALUE;
2224 break;
2225 }
2226
2227 if (err != WN_NO_ERROR) SetLastError(err);
2228 return err;
2229 }
2230
2231
2232
2233 /*
2234 * Other Functions
2235 */
2236
2237 /**************************************************************************
2238 * WNetGetUserA [MPR.@]
2239 *
2240 * FIXME: we should not return ourselves, but the owner of the drive lpName
2241 */
2242 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2243 {
2244 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2245 return GetLastError();
2246 }
2247
2248 /*****************************************************************
2249 * WNetGetUserW [MPR.@]
2250 *
2251 * FIXME: we should not return ourselves, but the owner of the drive lpName
2252 */
2253 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2254 {
2255 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2256 return GetLastError();
2257 }
2258
2259 /*********************************************************************
2260 * WNetConnectionDialog [MPR.@]
2261 */
2262 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2263 {
2264 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2265
2266 SetLastError(WN_NO_NETWORK);
2267 return WN_NO_NETWORK;
2268 }
2269
2270 /*********************************************************************
2271 * WNetConnectionDialog1A [MPR.@]
2272 */
2273 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2274 {
2275 FIXME( "(%p): stub\n", lpConnDlgStruct );
2276
2277 SetLastError(WN_NO_NETWORK);
2278 return WN_NO_NETWORK;
2279 }
2280
2281 /*********************************************************************
2282 * WNetConnectionDialog1W [MPR.@]
2283 */
2284 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2285 {
2286 FIXME( "(%p): stub\n", lpConnDlgStruct );
2287
2288 SetLastError(WN_NO_NETWORK);
2289 return WN_NO_NETWORK;
2290 }
2291
2292 /*********************************************************************
2293 * WNetDisconnectDialog [MPR.@]
2294 */
2295 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2296 {
2297 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2298
2299 SetLastError(WN_NO_NETWORK);
2300 return WN_NO_NETWORK;
2301 }
2302
2303 /*********************************************************************
2304 * WNetDisconnectDialog1A [MPR.@]
2305 */
2306 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2307 {
2308 FIXME( "(%p): stub\n", lpConnDlgStruct );
2309
2310 SetLastError(WN_NO_NETWORK);
2311 return WN_NO_NETWORK;
2312 }
2313
2314 /*********************************************************************
2315 * WNetDisconnectDialog1W [MPR.@]
2316 */
2317 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2318 {
2319 FIXME( "(%p): stub\n", lpConnDlgStruct );
2320
2321 SetLastError(WN_NO_NETWORK);
2322 return WN_NO_NETWORK;
2323 }
2324
2325 /*********************************************************************
2326 * WNetGetLastErrorA [MPR.@]
2327 */
2328 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2329 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2330 LPSTR lpNameBuf, DWORD nNameBufSize )
2331 {
2332 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2333 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2334
2335 SetLastError(WN_NO_NETWORK);
2336 return WN_NO_NETWORK;
2337 }
2338
2339 /*********************************************************************
2340 * WNetGetLastErrorW [MPR.@]
2341 */
2342 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2343 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2344 LPWSTR lpNameBuf, DWORD nNameBufSize )
2345 {
2346 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2347 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2348
2349 SetLastError(WN_NO_NETWORK);
2350 return WN_NO_NETWORK;
2351 }
2352
2353 /*********************************************************************
2354 * WNetGetNetworkInformationA [MPR.@]
2355 */
2356 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2357 LPNETINFOSTRUCT lpNetInfoStruct )
2358 {
2359 DWORD ret;
2360
2361 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2362
2363 if (!lpProvider)
2364 ret = WN_BAD_POINTER;
2365 else
2366 {
2367 int len;
2368
2369 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2370 if (len)
2371 {
2372 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2373
2374 if (wideProvider)
2375 {
2376 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2377 len);
2378 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2379 HeapFree(GetProcessHeap(), 0, wideProvider);
2380 }
2381 else
2382 ret = WN_OUT_OF_MEMORY;
2383 }
2384 else
2385 ret = GetLastError();
2386 }
2387 if (ret)
2388 SetLastError(ret);
2389 TRACE("Returning %d\n", ret);
2390 return ret;
2391 }
2392
2393 /*********************************************************************
2394 * WNetGetNetworkInformationW [MPR.@]
2395 */
2396 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2397 LPNETINFOSTRUCT lpNetInfoStruct )
2398 {
2399 DWORD ret;
2400
2401 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2402
2403 if (!lpProvider)
2404 ret = WN_BAD_POINTER;
2405 else if (!lpNetInfoStruct)
2406 ret = WN_BAD_POINTER;
2407 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2408 ret = WN_BAD_VALUE;
2409 else
2410 {
2411 if (providerTable && providerTable->numProviders)
2412 {
2413 DWORD providerIndex = _findProviderIndexW(lpProvider);
2414
2415 if (providerIndex != BAD_PROVIDER_INDEX)
2416 {
2417 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2418 lpNetInfoStruct->dwProviderVersion =
2419 providerTable->table[providerIndex].dwSpecVersion;
2420 lpNetInfoStruct->dwStatus = NO_ERROR;
2421 lpNetInfoStruct->dwCharacteristics = 0;
2422 lpNetInfoStruct->dwHandle = 0;
2423 lpNetInfoStruct->wNetType =
2424 HIWORD(providerTable->table[providerIndex].dwNetType);
2425 lpNetInfoStruct->dwPrinters = -1;
2426 lpNetInfoStruct->dwDrives = -1;
2427 ret = WN_SUCCESS;
2428 }
2429 else
2430 ret = WN_BAD_PROVIDER;
2431 }
2432 else
2433 ret = WN_NO_NETWORK;
2434 }
2435 if (ret)
2436 SetLastError(ret);
2437 TRACE("Returning %d\n", ret);
2438 return ret;
2439 }
2440
2441 /*****************************************************************
2442 * WNetGetProviderNameA [MPR.@]
2443 */
2444 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2445 LPSTR lpProvider, LPDWORD lpBufferSize )
2446 {
2447 DWORD ret;
2448
2449 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2450 lpBufferSize);
2451
2452 if (!lpProvider)
2453 ret = WN_BAD_POINTER;
2454 else if (!lpBufferSize)
2455 ret = WN_BAD_POINTER;
2456 else
2457 {
2458 if (providerTable)
2459 {
2460 DWORD i;
2461
2462 ret = WN_NO_NETWORK;
2463 for (i = 0; i < providerTable->numProviders &&
2464 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2465 i++)
2466 ;
2467 if (i < providerTable->numProviders)
2468 {
2469 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2470 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2471
2472 if (*lpBufferSize < sizeNeeded)
2473 {
2474 *lpBufferSize = sizeNeeded;
2475 ret = WN_MORE_DATA;
2476 }
2477 else
2478 {
2479 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2480 -1, lpProvider, *lpBufferSize, NULL, NULL);
2481 ret = WN_SUCCESS;
2482 /* FIXME: is *lpBufferSize set to the number of characters
2483 * copied? */
2484 }
2485 }
2486 }
2487 else
2488 ret = WN_NO_NETWORK;
2489 }
2490 if (ret)
2491 SetLastError(ret);
2492 TRACE("Returning %d\n", ret);
2493 return ret;
2494 }
2495
2496 /*****************************************************************
2497 * WNetGetProviderNameW [MPR.@]
2498 */
2499 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2500 LPWSTR lpProvider, LPDWORD lpBufferSize )
2501 {
2502 DWORD ret;
2503
2504 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2505 lpBufferSize);
2506
2507 if (!lpProvider)
2508 ret = WN_BAD_POINTER;
2509 else if (!lpBufferSize)
2510 ret = WN_BAD_POINTER;
2511 else
2512 {
2513 if (providerTable)
2514 {
2515 DWORD i;
2516
2517 ret = WN_NO_NETWORK;
2518 for (i = 0; i < providerTable->numProviders &&
2519 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2520 i++)
2521 ;
2522 if (i < providerTable->numProviders)
2523 {
2524 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2525
2526 if (*lpBufferSize < sizeNeeded)
2527 {
2528 *lpBufferSize = sizeNeeded;
2529 ret = WN_MORE_DATA;
2530 }
2531 else
2532 {
2533 strcpyW(lpProvider, providerTable->table[i].name);
2534 ret = WN_SUCCESS;
2535 /* FIXME: is *lpBufferSize set to the number of characters
2536 * copied? */
2537 }
2538 }
2539 }
2540 else
2541 ret = WN_NO_NETWORK;
2542 }
2543 if (ret)
2544 SetLastError(ret);
2545 TRACE("Returning %d\n", ret);
2546 return ret;
2547 }