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