[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
754 ret = providerTable->table[index].openEnum(
755 dwScope, dwType, dwUsage, lpNet, &handle);
756 if (ret == WN_SUCCESS)
757 {
758 *lphEnum = _createProviderEnumerator(
759 dwScope, dwType, dwUsage, index, handle);
760 ret = *lphEnum ? WN_SUCCESS :
761 WN_OUT_OF_MEMORY;
762 }
763 }
764 else
765 ret = WN_NOT_SUPPORTED;
766 }
767 else
768 ret = WN_BAD_PROVIDER;
769 }
770 else if (lpNet->lpRemoteName)
771 {
772 *lphEnum = _createGlobalEnumeratorW(dwScope,
773 dwType, dwUsage, lpNet);
774 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
775 }
776 else
777 {
778 if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
779 providerTable->entireNetwork))
780 {
781 /* comment matches the "Entire Network", enumerate
782 * global scope of every provider
783 */
784 *lphEnum = _createGlobalEnumeratorW(dwScope,
785 dwType, dwUsage, lpNet);
786 }
787 else
788 {
789 /* this is the same as not having passed lpNet */
790 *lphEnum = _createGlobalEnumeratorW(dwScope,
791 dwType, dwUsage, NULL);
792 }
793 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
794 }
795 }
796 else
797 {
798 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
799 dwUsage, lpNet);
800 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
801 }
802 break;
803 case RESOURCE_CONTEXT:
804 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
805 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
806 break;
807 case RESOURCE_REMEMBERED:
808 case RESOURCE_CONNECTED:
809 *lphEnum = _createNullEnumerator();
810 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
811 break;
812 default:
813 WARN("unknown scope 0x%08x\n", dwScope);
814 ret = WN_BAD_VALUE;
815 }
816 }
817 if (ret)
818 SetLastError(ret);
819 TRACE("Returning %d\n", ret);
820 return ret;
821 }
822
823 /*********************************************************************
824 * WNetEnumResourceA [MPR.@]
825 */
826 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
827 LPVOID lpBuffer, LPDWORD lpBufferSize )
828 {
829 DWORD ret;
830
831 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
832
833 if (!hEnum)
834 ret = WN_BAD_POINTER;
835 else if (!lpcCount)
836 ret = WN_BAD_POINTER;
837 else if (!lpBuffer)
838 ret = WN_BAD_POINTER;
839 else if (!lpBufferSize)
840 ret = WN_BAD_POINTER;
841 else if (*lpBufferSize < sizeof(NETRESOURCEA))
842 {
843 *lpBufferSize = sizeof(NETRESOURCEA);
844 ret = WN_MORE_DATA;
845 }
846 else
847 {
848 DWORD localCount = *lpcCount, localSize = *lpBufferSize;
849 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
850
851 if (localBuffer)
852 {
853 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
854 &localSize);
855 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
856 {
857 /* FIXME: this isn't necessarily going to work in the case of
858 * WN_MORE_DATA, because our enumerator may have moved on to
859 * the next provider. MSDN states that a large (16KB) buffer
860 * size is the appropriate usage of this function, so
861 * hopefully it won't be an issue.
862 */
863 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
864 lpBuffer, lpBufferSize);
865 *lpcCount = localCount;
866 }
867 HeapFree(GetProcessHeap(), 0, localBuffer);
868 }
869 else
870 ret = WN_OUT_OF_MEMORY;
871 }
872 if (ret)
873 SetLastError(ret);
874 TRACE("Returning %d\n", ret);
875 return ret;
876 }
877
878 static DWORD _countProviderBytesW(PWNetProvider provider)
879 {
880 DWORD ret;
881
882 if (provider)
883 {
884 ret = sizeof(NETRESOURCEW);
885 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
886 }
887 else
888 ret = 0;
889 return ret;
890 }
891
892 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
893 LPVOID lpBuffer, const DWORD *lpBufferSize)
894 {
895 DWORD ret;
896
897 if (!enumerator)
898 return WN_BAD_POINTER;
899 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
900 return WN_BAD_VALUE;
901 if (!lpcCount)
902 return WN_BAD_POINTER;
903 if (!lpBuffer)
904 return WN_BAD_POINTER;
905 if (!lpBufferSize)
906 return WN_BAD_POINTER;
907 if (*lpBufferSize < sizeof(NETRESOURCEA))
908 return WN_MORE_DATA;
909
910 if (!providerTable || enumerator->providerIndex >=
911 providerTable->numProviders)
912 ret = WN_NO_MORE_ENTRIES;
913 else
914 {
915 DWORD bytes = 0, count = 0, countLimit, i;
916 LPNETRESOURCEW resource;
917 LPWSTR strNext;
918
919 countLimit = *lpcCount == -1 ?
920 providerTable->numProviders - enumerator->providerIndex : *lpcCount;
921 while (count < countLimit && bytes < *lpBufferSize)
922 {
923 DWORD bytesNext = _countProviderBytesW(
924 &providerTable->table[count + enumerator->providerIndex]);
925
926 if (bytes + bytesNext < *lpBufferSize)
927 {
928 bytes += bytesNext;
929 count++;
930 }
931 }
932 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
933 for (i = 0, resource = lpBuffer; i < count; i++, resource++)
934 {
935 resource->dwScope = RESOURCE_GLOBALNET;
936 resource->dwType = RESOURCETYPE_ANY;
937 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
938 resource->dwUsage = RESOURCEUSAGE_CONTAINER |
939 RESOURCEUSAGE_RESERVED;
940 resource->lpLocalName = NULL;
941 resource->lpRemoteName = strNext;
942 strcpyW(resource->lpRemoteName,
943 providerTable->table[i + enumerator->providerIndex].name);
944 strNext += strlenW(resource->lpRemoteName) + 1;
945 resource->lpComment = NULL;
946 resource->lpProvider = strNext;
947 strcpyW(resource->lpProvider,
948 providerTable->table[i + enumerator->providerIndex].name);
949 strNext += strlenW(resource->lpProvider) + 1;
950 }
951 enumerator->providerIndex += count;
952 *lpcCount = count;
953 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
954 }
955 TRACE("Returning %d\n", ret);
956 return ret;
957 }
958
959 /* Advances the enumerator (assumed to be a global enumerator) to the next
960 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
961 * not open a handle with the next provider.
962 * If the existing handle is NULL, may leave the enumerator unchanged, since
963 * the current provider may support the desired scope.
964 * If the existing handle is not NULL, closes it before moving on.
965 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
966 * provider, and another error on failure.
967 */
968 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
969 {
970 if (!enumerator)
971 return WN_BAD_POINTER;
972 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
973 return WN_BAD_VALUE;
974 if (!providerTable || enumerator->providerIndex >=
975 providerTable->numProviders)
976 return WN_NO_MORE_ENTRIES;
977
978 if (enumerator->providerDone)
979 {
980 DWORD dwEnum = 0;
981 enumerator->providerDone = FALSE;
982 if (enumerator->handle)
983 {
984 providerTable->table[enumerator->providerIndex].closeEnum(
985 enumerator->handle);
986 enumerator->handle = NULL;
987 enumerator->providerIndex++;
988 }
989 if (enumerator->dwScope == RESOURCE_CONNECTED)
990 dwEnum = WNNC_ENUM_LOCAL;
991 else if (enumerator->dwScope == RESOURCE_GLOBALNET)
992 dwEnum = WNNC_ENUM_GLOBAL;
993 else if (enumerator->dwScope == RESOURCE_CONTEXT)
994 dwEnum = WNNC_ENUM_CONTEXT;
995 for (; enumerator->providerIndex < providerTable->numProviders &&
996 !(providerTable->table[enumerator->providerIndex].dwEnumScopes
997 & dwEnum); enumerator->providerIndex++)
998 ;
999 }
1000 return enumerator->providerIndex < providerTable->numProviders ?
1001 WN_SUCCESS : WN_NO_MORE_ENTRIES;
1002 }
1003
1004 /* "Passes through" call to the next provider that supports the enumeration
1005 * type.
1006 * FIXME: if one call to a provider's enumerator succeeds while there's still
1007 * space in lpBuffer, I don't call to the next provider. The caller may not
1008 * expect that it should call EnumResourceW again with a return value of
1009 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1010 * may have to be moved around a bit, ick.
1011 */
1012 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
1013 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
1014 {
1015 DWORD ret;
1016
1017 if (!enumerator)
1018 return WN_BAD_POINTER;
1019 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1020 return WN_BAD_VALUE;
1021 if (!lpcCount)
1022 return WN_BAD_POINTER;
1023 if (!lpBuffer)
1024 return WN_BAD_POINTER;
1025 if (!lpBufferSize)
1026 return WN_BAD_POINTER;
1027 if (*lpBufferSize < sizeof(NETRESOURCEW))
1028 return WN_MORE_DATA;
1029
1030 ret = _globalEnumeratorAdvance(enumerator);
1031 if (ret == WN_SUCCESS)
1032 {
1033 ret = providerTable->table[enumerator->providerIndex].
1034 openEnum(enumerator->dwScope, enumerator->dwType,
1035 enumerator->dwUsage, enumerator->lpNet,
1036 &enumerator->handle);
1037 if (ret == WN_SUCCESS)
1038 {
1039 ret = providerTable->table[enumerator->providerIndex].
1040 enumResource(enumerator->handle, lpcCount, lpBuffer,
1041 lpBufferSize);
1042 if (ret != WN_MORE_DATA)
1043 enumerator->providerDone = TRUE;
1044 }
1045 }
1046 TRACE("Returning %d\n", ret);
1047 return ret;
1048 }
1049
1050 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1051 LPVOID lpBuffer, LPDWORD lpBufferSize)
1052 {
1053 DWORD ret;
1054
1055 if (!enumerator)
1056 return WN_BAD_POINTER;
1057 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
1058 return WN_BAD_VALUE;
1059 if (!lpcCount)
1060 return WN_BAD_POINTER;
1061 if (!lpBuffer)
1062 return WN_BAD_POINTER;
1063 if (!lpBufferSize)
1064 return WN_BAD_POINTER;
1065 if (*lpBufferSize < sizeof(NETRESOURCEW))
1066 return WN_MORE_DATA;
1067 if (!providerTable)
1068 return WN_NO_NETWORK;
1069
1070 switch (enumerator->dwScope)
1071 {
1072 case RESOURCE_GLOBALNET:
1073 if (enumerator->lpNet)
1074 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
1075 lpBuffer, lpBufferSize);
1076 else
1077 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
1078 lpBufferSize);
1079 break;
1080 case RESOURCE_CONTEXT:
1081 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
1082 lpBufferSize);
1083 break;
1084 default:
1085 WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
1086 ret = WN_NO_MORE_ENTRIES;
1087 }
1088 TRACE("Returning %d\n", ret);
1089 return ret;
1090 }
1091
1092 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1093 LPVOID lpBuffer, LPDWORD lpBufferSize)
1094 {
1095 if (!enumerator)
1096 return WN_BAD_POINTER;
1097 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
1098 return WN_BAD_VALUE;
1099 if (!enumerator->handle)
1100 return WN_BAD_VALUE;
1101 if (!lpcCount)
1102 return WN_BAD_POINTER;
1103 if (!lpBuffer)
1104 return WN_BAD_POINTER;
1105 if (!lpBufferSize)
1106 return WN_BAD_POINTER;
1107 if (!providerTable)
1108 return WN_NO_NETWORK;
1109 if (enumerator->providerIndex >= providerTable->numProviders)
1110 return WN_NO_MORE_ENTRIES;
1111 if (!providerTable->table[enumerator->providerIndex].enumResource)
1112 return WN_BAD_VALUE;
1113 return providerTable->table[enumerator->providerIndex].enumResource(
1114 enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
1115 }
1116
1117 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
1118 LPVOID lpBuffer, LPDWORD lpBufferSize)
1119 {
1120 DWORD ret;
1121 size_t cchEntireNetworkLen, bytesNeeded;
1122
1123 if (!enumerator)
1124 return WN_BAD_POINTER;
1125 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
1126 return WN_BAD_VALUE;
1127 if (!lpcCount)
1128 return WN_BAD_POINTER;
1129 if (!lpBuffer)
1130 return WN_BAD_POINTER;
1131 if (!lpBufferSize)
1132 return WN_BAD_POINTER;
1133 if (!providerTable)
1134 return WN_NO_NETWORK;
1135
1136 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
1137 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
1138 if (*lpBufferSize < bytesNeeded)
1139 {
1140 *lpBufferSize = bytesNeeded;
1141 ret = WN_MORE_DATA;
1142 }
1143 else
1144 {
1145 LPNETRESOURCEW lpNet = lpBuffer;
1146
1147 lpNet->dwScope = RESOURCE_GLOBALNET;
1148 lpNet->dwType = enumerator->dwType;
1149 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
1150 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
1151 lpNet->lpLocalName = NULL;
1152 lpNet->lpRemoteName = NULL;
1153 lpNet->lpProvider = NULL;
1154 /* odd, but correct: put comment at end of buffer, so it won't get
1155 * overwritten by subsequent calls to a provider's enumResource
1156 */
1157 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
1158 (cchEntireNetworkLen * sizeof(WCHAR)));
1159 strcpyW(lpNet->lpComment, providerTable->entireNetwork);
1160 ret = WN_SUCCESS;
1161 }
1162 if (ret == WN_SUCCESS)
1163 {
1164 DWORD bufferSize = *lpBufferSize - bytesNeeded;
1165
1166 /* "Entire Network" entry enumerated--morph this into a global
1167 * enumerator. enumerator->lpNet continues to be NULL, since it has
1168 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1169 */
1170 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
1171 ret = _enumerateGlobalW(enumerator, lpcCount,
1172 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
1173 if (ret == WN_SUCCESS)
1174 {
1175 /* reflect the fact that we already enumerated "Entire Network" */
1176 (*lpcCount)++;
1177 *lpBufferSize = bufferSize + bytesNeeded;
1178 }
1179 else
1180 {
1181 /* the provider enumeration failed, but we already succeeded in
1182 * enumerating "Entire Network"--leave type as global to allow a
1183 * retry, but indicate success with a count of one.
1184 */
1185 ret = WN_SUCCESS;
1186 *lpcCount = 1;
1187 *lpBufferSize = bytesNeeded;
1188 }
1189 }
1190 TRACE("Returning %d\n", ret);
1191 return ret;
1192 }
1193
1194 /*********************************************************************
1195 * WNetEnumResourceW [MPR.@]
1196 */
1197 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
1198 LPVOID lpBuffer, LPDWORD lpBufferSize )
1199 {
1200 DWORD ret;
1201
1202 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
1203
1204 if (!hEnum)
1205 ret = WN_BAD_POINTER;
1206 else if (!lpcCount)
1207 ret = WN_BAD_POINTER;
1208 else if (!lpBuffer)
1209 ret = WN_BAD_POINTER;
1210 else if (!lpBufferSize)
1211 ret = WN_BAD_POINTER;
1212 else if (*lpBufferSize < sizeof(NETRESOURCEW))
1213 {
1214 *lpBufferSize = sizeof(NETRESOURCEW);
1215 ret = WN_MORE_DATA;
1216 }
1217 else
1218 {
1219 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1220
1221 switch (enumerator->enumType)
1222 {
1223 case WNET_ENUMERATOR_TYPE_NULL:
1224 ret = WN_NO_MORE_ENTRIES;
1225 break;
1226 case WNET_ENUMERATOR_TYPE_GLOBAL:
1227 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
1228 lpBufferSize);
1229 break;
1230 case WNET_ENUMERATOR_TYPE_PROVIDER:
1231 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
1232 lpBufferSize);
1233 break;
1234 case WNET_ENUMERATOR_TYPE_CONTEXT:
1235 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
1236 lpBufferSize);
1237 break;
1238 default:
1239 WARN("bogus enumerator type!\n");
1240 ret = WN_NO_NETWORK;
1241 }
1242 }
1243 if (ret)
1244 SetLastError(ret);
1245 TRACE("Returning %d\n", ret);
1246 return ret;
1247 }
1248
1249 /*********************************************************************
1250 * WNetCloseEnum [MPR.@]
1251 */
1252 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
1253 {
1254 DWORD ret;
1255
1256 TRACE( "(%p)\n", hEnum );
1257
1258 if (hEnum)
1259 {
1260 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
1261
1262 switch (enumerator->enumType)
1263 {
1264 case WNET_ENUMERATOR_TYPE_NULL:
1265 ret = WN_SUCCESS;
1266 break;
1267 case WNET_ENUMERATOR_TYPE_GLOBAL:
1268 if (enumerator->lpNet)
1269 _freeEnumNetResource(enumerator->lpNet);
1270 if (enumerator->handle)
1271 providerTable->table[enumerator->providerIndex].
1272 closeEnum(enumerator->handle);
1273 ret = WN_SUCCESS;
1274 break;
1275 case WNET_ENUMERATOR_TYPE_PROVIDER:
1276 if (enumerator->handle)
1277 providerTable->table[enumerator->providerIndex].
1278 closeEnum(enumerator->handle);
1279 ret = WN_SUCCESS;
1280 break;
1281 default:
1282 WARN("bogus enumerator type!\n");
1283 ret = WN_BAD_HANDLE;
1284 }
1285 HeapFree(GetProcessHeap(), 0, hEnum);
1286 }
1287 else
1288 ret = WN_BAD_HANDLE;
1289 if (ret)
1290 SetLastError(ret);
1291 TRACE("Returning %d\n", ret);
1292 return ret;
1293 }
1294
1295 /*********************************************************************
1296 * WNetGetResourceInformationA [MPR.@]
1297 *
1298 * See WNetGetResourceInformationW
1299 */
1300 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1301 LPVOID lpBuffer, LPDWORD cbBuffer,
1302 LPSTR *lplpSystem )
1303 {
1304 DWORD ret;
1305
1306 TRACE( "(%p, %p, %p, %p)\n",
1307 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1308
1309 if (!providerTable || providerTable->numProviders == 0)
1310 ret = WN_NO_NETWORK;
1311 else if (lpNetResource)
1312 {
1313 LPNETRESOURCEW lpNetResourceW = NULL;
1314 DWORD size = 1024, count = 1;
1315 DWORD len;
1316
1317 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1318 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1319 if (ret == WN_MORE_DATA)
1320 {
1321 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1322 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1323 if (lpNetResourceW)
1324 ret = _thunkNetResourceArrayAToW(lpNetResource,
1325 &count, lpNetResourceW, &size);
1326 else
1327 ret = WN_OUT_OF_MEMORY;
1328 }
1329 if (ret == WN_SUCCESS)
1330 {
1331 LPWSTR lpSystemW = NULL;
1332 LPVOID lpBufferW;
1333 size = 1024;
1334 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1335 if (lpBufferW)
1336 {
1337 ret = WNetGetResourceInformationW(lpNetResourceW,
1338 lpBufferW, &size, &lpSystemW);
1339 if (ret == WN_MORE_DATA)
1340 {
1341 HeapFree(GetProcessHeap(), 0, lpBufferW);
1342 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1343 if (lpBufferW)
1344 ret = WNetGetResourceInformationW(lpNetResourceW,
1345 lpBufferW, &size, &lpSystemW);
1346 else
1347 ret = WN_OUT_OF_MEMORY;
1348 }
1349 if (ret == WN_SUCCESS)
1350 {
1351 ret = _thunkNetResourceArrayWToA(lpBufferW,
1352 &count, lpBuffer, cbBuffer);
1353 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1354 lpNetResourceW = lpBufferW;
1355 size = sizeof(NETRESOURCEA);
1356 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1357 -1, NULL, 0, NULL, NULL);
1358 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1359 -1, NULL, 0, NULL, NULL);
1360
1361 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1362 -1, NULL, 0, NULL, NULL);
1363 if ((len) && ( size + len < *cbBuffer))
1364 {
1365 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1366 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1367 *lplpSystem, len, NULL, NULL);
1368 ret = WN_SUCCESS;
1369 }
1370 else
1371 ret = WN_MORE_DATA;
1372 }
1373 else
1374 ret = WN_OUT_OF_MEMORY;
1375 HeapFree(GetProcessHeap(), 0, lpBufferW);
1376 }
1377 else
1378 ret = WN_OUT_OF_MEMORY;
1379 HeapFree(GetProcessHeap(), 0, lpSystemW);
1380 }
1381 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1382 }
1383 else
1384 ret = WN_NO_NETWORK;
1385
1386 if (ret)
1387 SetLastError(ret);
1388 TRACE("Returning %d\n", ret);
1389 return ret;
1390 }
1391
1392 /*********************************************************************
1393 * WNetGetResourceInformationW [MPR.@]
1394 *
1395 * WNetGetResourceInformationW function identifies the network provider
1396 * that owns the resource and gets information about the type of the resource.
1397 *
1398 * PARAMS:
1399 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1400 * defines a network resource.
1401 * lpBuffer [ O] the pointer to buffer, containing result. It
1402 * contains NETRESOURCEW structure and strings to
1403 * which the members of the NETRESOURCEW structure
1404 * point.
1405 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1406 * in bytes.
1407 * lplpSystem [ O] the pointer to string in the output buffer,
1408 * containing the part of the resource name without
1409 * names of the server and share.
1410 *
1411 * RETURNS:
1412 * NO_ERROR if the function succeeds. System error code if the function fails.
1413 */
1414
1415 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1416 LPVOID lpBuffer, LPDWORD cbBuffer,
1417 LPWSTR *lplpSystem )
1418 {
1419 DWORD ret = WN_NO_NETWORK;
1420 DWORD index;
1421
1422 TRACE( "(%p, %p, %p, %p)\n",
1423 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1424
1425 if (!(lpBuffer))
1426 ret = WN_OUT_OF_MEMORY;
1427 else if (providerTable != NULL)
1428 {
1429 /* FIXME: For function value of a variable is indifferent, it does
1430 * search of all providers in a network.
1431 */
1432 for (index = 0; index < providerTable->numProviders; index++)
1433 {
1434 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1435 WNNC_DLG_GETRESOURCEINFORMATION)
1436 {
1437 if (providerTable->table[index].getResourceInformation)
1438 ret = providerTable->table[index].getResourceInformation(
1439 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1440 else
1441 ret = WN_NO_NETWORK;
1442 if (ret == WN_SUCCESS)
1443 break;
1444 }
1445 }
1446 }
1447 if (ret)
1448 SetLastError(ret);
1449 return ret;
1450 }
1451
1452 /*********************************************************************
1453 * WNetGetResourceParentA [MPR.@]
1454 */
1455 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1456 LPVOID lpBuffer, LPDWORD lpBufferSize )
1457 {
1458 FIXME( "(%p, %p, %p): stub\n",
1459 lpNetResource, lpBuffer, lpBufferSize );
1460
1461 SetLastError(WN_NO_NETWORK);
1462 return WN_NO_NETWORK;
1463 }
1464
1465 /*********************************************************************
1466 * WNetGetResourceParentW [MPR.@]
1467 */
1468 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1469 LPVOID lpBuffer, LPDWORD lpBufferSize )
1470 {
1471 FIXME( "(%p, %p, %p): stub\n",
1472 lpNetResource, lpBuffer, lpBufferSize );
1473
1474 SetLastError(WN_NO_NETWORK);
1475 return WN_NO_NETWORK;
1476 }
1477
1478
1479
1480 /*
1481 * Connection Functions
1482 */
1483
1484 /*********************************************************************
1485 * WNetAddConnectionA [MPR.@]
1486 */
1487 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1488 LPCSTR lpLocalName )
1489 {
1490 NETRESOURCEA resourcesA;
1491
1492 memset(&resourcesA, 0, sizeof(resourcesA));
1493 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1494 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1495 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1496 }
1497
1498 /*********************************************************************
1499 * WNetAddConnectionW [MPR.@]
1500 */
1501 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1502 LPCWSTR lpLocalName )
1503 {
1504 NETRESOURCEW resourcesW;
1505
1506 memset(&resourcesW, 0, sizeof(resourcesW));
1507 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1508 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1509 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1510 }
1511
1512 /*********************************************************************
1513 * WNetAddConnection2A [MPR.@]
1514 */
1515 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1516 LPCSTR lpPassword, LPCSTR lpUserID,
1517 DWORD dwFlags )
1518 {
1519 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1520 NULL, 0, NULL);
1521 }
1522
1523 /*********************************************************************
1524 * WNetAddConnection2W [MPR.@]
1525 */
1526 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1527 LPCWSTR lpPassword, LPCWSTR lpUserID,
1528 DWORD dwFlags )
1529 {
1530 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1531 NULL, 0, NULL);
1532 }
1533
1534 /*********************************************************************
1535 * WNetAddConnection3A [MPR.@]
1536 */
1537 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1538 LPCSTR lpPassword, LPCSTR lpUserID,
1539 DWORD dwFlags )
1540 {
1541 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1542 dwFlags, NULL, 0, NULL);
1543 }
1544
1545 /*********************************************************************
1546 * WNetAddConnection3W [MPR.@]
1547 */
1548 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1549 LPCWSTR lpPassword, LPCWSTR lpUserID,
1550 DWORD dwFlags )
1551 {
1552 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1553 dwFlags, NULL, 0, NULL);
1554 }
1555
1556 /* Convert an ANSI string to wide */
1557 static LPWSTR strdupAtoW( LPCSTR str )
1558 {
1559 LPWSTR ret;
1560 INT len;
1561
1562 if (!str) return NULL;
1563 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
1564 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1565 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
1566 return ret;
1567 }
1568
1569 /* Convert ANSI NETRESOURCE struct to wide structure */
1570 static VOID convert_netresourcea_to_w( LPNETRESOURCEA lpNetResourceA,
1571 LPNETRESOURCEW lpNetResourceW )
1572 {
1573 lpNetResourceW->dwScope = lpNetResourceA->dwScope;
1574 lpNetResourceW->dwType = lpNetResourceA->dwType;
1575 lpNetResourceW->dwDisplayType = lpNetResourceA->dwDisplayType;
1576 lpNetResourceW->dwUsage = lpNetResourceA->dwUsage;
1577 lpNetResourceW->lpLocalName = strdupAtoW(lpNetResourceA->lpLocalName);
1578 lpNetResourceW->lpRemoteName = strdupAtoW(lpNetResourceA->lpRemoteName);
1579 lpNetResourceW->lpComment = strdupAtoW(lpNetResourceA->lpComment);
1580 lpNetResourceW->lpProvider = strdupAtoW(lpNetResourceA->lpProvider);
1581 }
1582
1583 /*****************************************************************
1584 * WNetUseConnectionA [MPR.@]
1585 */
1586 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1587 LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
1588 LPSTR lpAccessName, LPDWORD lpBufferSize,
1589 LPDWORD lpResult )
1590 {
1591 NETRESOURCEW resourcesW, *pRes = NULL;
1592 PWSTR passW, userIDW, accessNameW = NULL;
1593 DWORD ret = WN_MORE_DATA;
1594 DWORD bufferSize = 1;
1595 int len;
1596
1597 if (lpNetResource)
1598 {
1599 convert_netresourcea_to_w(lpNetResource, &resourcesW);
1600 pRes = &resourcesW;
1601 }
1602
1603 passW = strdupAtoW(lpPassword);
1604 userIDW = strdupAtoW(lpUserID);
1605
1606 if (lpAccessName && lpBufferSize && *lpBufferSize)
1607 {
1608 WCHAR probe;
1609
1610 ret = WNetUseConnectionW(hwndOwner, pRes, passW, userIDW, dwFlags,
1611 &probe, &bufferSize, lpResult);
1612 if (ret == WN_MORE_DATA)
1613 accessNameW = HeapAlloc(GetProcessHeap(), 0, bufferSize * sizeof(WCHAR));
1614 }
1615
1616 if (ret == WN_MORE_DATA)
1617 {
1618 ret = WNetUseConnectionW(hwndOwner, pRes, passW, userIDW, dwFlags,
1619 accessNameW, &bufferSize, lpResult);
1620 if (ret == WN_SUCCESS)
1621 {
1622 if (lpAccessName && lpBufferSize && *lpBufferSize && accessNameW)
1623 {
1624 len = WideCharToMultiByte(CP_ACP, 0, accessNameW, -1, NULL, 0, NULL, NULL);
1625 if (len)
1626 {
1627 if (len <= *lpBufferSize)
1628 WideCharToMultiByte(CP_ACP, 0, accessNameW, -1, lpAccessName, len, NULL, NULL);
1629 else
1630 {
1631 WNetCancelConnectionW(accessNameW, TRUE);
1632 *lpBufferSize = len;
1633 ret = WN_MORE_DATA;
1634 }
1635 }
1636 }
1637 }
1638 }
1639
1640 if (lpNetResource)
1641 {
1642 HeapFree(GetProcessHeap(), 0, resourcesW.lpLocalName);
1643 HeapFree(GetProcessHeap(), 0, resourcesW.lpRemoteName);
1644 HeapFree(GetProcessHeap(), 0, resourcesW.lpComment);
1645 HeapFree(GetProcessHeap(), 0, resourcesW.lpProvider);
1646 }
1647 HeapFree(GetProcessHeap(), 0, passW);
1648 HeapFree(GetProcessHeap(), 0, userIDW);
1649 HeapFree(GetProcessHeap(), 0, accessNameW);
1650
1651 return ret;
1652 }
1653
1654 /*****************************************************************
1655 * WNetUseConnectionW [MPR.@]
1656 */
1657 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1658 LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags,
1659 LPWSTR lpAccessName, LPDWORD lpBufferSize,
1660 LPDWORD lpResult )
1661 {
1662 DWORD provider;
1663 DWORD cap;
1664 char id;
1665 DWORD drives;
1666 DWORD ret;
1667 PF_NPAddConnection3 addConn3;
1668 PF_NPAddConnection addConn;
1669
1670 if (!providerTable || providerTable->numProviders == 0) {
1671 SetLastError(WN_NO_NETWORK);
1672 return WN_NO_NETWORK;
1673 }
1674
1675 if (!lpNetResource) {
1676 SetLastError(ERROR_INVALID_PARAMETER);
1677 return ERROR_INVALID_PARAMETER;
1678 }
1679
1680 if (!lpNetResource->lpProvider || !*lpNetResource->lpProvider) {
1681 SetLastError(ERROR_BAD_PROVIDER);
1682 return ERROR_BAD_PROVIDER;
1683 }
1684
1685 if (!lpNetResource->lpLocalName || !*lpNetResource->lpLocalName) {
1686 SetLastError(ERROR_BAD_DEVICE);
1687 return ERROR_BAD_DEVICE;
1688 }
1689
1690 if ((!(lpNetResource->lpLocalName[0] >= 'a' && lpNetResource->lpLocalName[0] <= 'z') &&
1691 !(lpNetResource->lpLocalName[0] >= 'A' && lpNetResource->lpLocalName[0] <= 'Z')) ||
1692 lpNetResource->lpLocalName[1] != ':' || lpNetResource->lpLocalName[2]) {
1693 SetLastError(ERROR_BAD_DEVICE);
1694 return ERROR_BAD_DEVICE;
1695 }
1696
1697 id = (lpNetResource->lpLocalName[0] >= 'a') ? lpNetResource->lpLocalName[0] - 'a' : lpNetResource->lpLocalName[0] - 'A';
1698 drives = GetLogicalDrives();
1699 if (drives & (1 << id)) {
1700 SetLastError(ERROR_ALREADY_ASSIGNED);
1701 return ERROR_ALREADY_ASSIGNED;
1702 }
1703
1704 provider = _findProviderIndexW(lpNetResource->lpProvider);
1705 if (provider == BAD_PROVIDER_INDEX) {
1706 SetLastError(ERROR_BAD_PROVIDER);
1707 return ERROR_BAD_PROVIDER;
1708 }
1709
1710 cap = providerTable->table[provider].getCaps(WNNC_CONNECTION);
1711 if (!(cap & WNNC_CON_ADDCONNECTION) && !(cap & WNNC_CON_ADDCONNECTION3)) {
1712 SetLastError(ERROR_BAD_PROVIDER);
1713 return ERROR_BAD_PROVIDER;
1714 }
1715
1716 ret = WN_ACCESS_DENIED;
1717 if (cap & WNNC_CON_ADDCONNECTION3) {
1718 addConn3 = (PF_NPAddConnection3)GetProcAddress(providerTable->table[provider].hLib, "NPAddConnection3");
1719 if (addConn3) {
1720 ret = addConn3(hwndOwner, lpNetResource, (LPWSTR)lpPassword, (LPWSTR)lpUserID, dwFlags);
1721 }
1722 }
1723 else if (cap & WNNC_CON_ADDCONNECTION) {
1724 addConn = (PF_NPAddConnection)GetProcAddress(providerTable->table[provider].hLib, "NPAddConnection");
1725 if (addConn) {
1726 ret = addConn(lpNetResource, (LPWSTR)lpPassword, (LPWSTR)lpUserID);
1727 }
1728 }
1729
1730 return ret;
1731 }
1732
1733 /*********************************************************************
1734 * WNetCancelConnectionA [MPR.@]
1735 */
1736 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
1737 {
1738 FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
1739
1740 return WN_SUCCESS;
1741 }
1742
1743 /*********************************************************************
1744 * WNetCancelConnectionW [MPR.@]
1745 */
1746 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
1747 {
1748 FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
1749
1750 return WN_SUCCESS;
1751 }
1752
1753 /*********************************************************************
1754 * WNetCancelConnection2A [MPR.@]
1755 */
1756 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
1757 {
1758 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
1759
1760 return WN_SUCCESS;
1761 }
1762
1763 /*********************************************************************
1764 * WNetCancelConnection2W [MPR.@]
1765 */
1766 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
1767 {
1768 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
1769
1770 return WN_SUCCESS;
1771 }
1772
1773 /*****************************************************************
1774 * WNetRestoreConnectionA [MPR.@]
1775 */
1776 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
1777 {
1778 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
1779
1780 SetLastError(WN_NO_NETWORK);
1781 return WN_NO_NETWORK;
1782 }
1783
1784 /*****************************************************************
1785 * WNetRestoreConnectionW [MPR.@]
1786 */
1787 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
1788 {
1789 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
1790
1791 SetLastError(WN_NO_NETWORK);
1792 return WN_NO_NETWORK;
1793 }
1794
1795 /**************************************************************************
1796 * WNetGetConnectionA [MPR.@]
1797 *
1798 * RETURNS
1799 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1800 * - WN_NOT_CONNECTED drive is a local drive
1801 * - WN_MORE_DATA buffer isn't big enough
1802 * - WN_SUCCESS success (net path in buffer)
1803 *
1804 * FIXME: need to test return values under different errors
1805 */
1806 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
1807 LPSTR lpRemoteName, LPDWORD lpBufferSize )
1808 {
1809 DWORD ret;
1810
1811 if (!lpLocalName)
1812 ret = WN_BAD_POINTER;
1813 else if (!lpBufferSize)
1814 ret = WN_BAD_POINTER;
1815 else if (!lpRemoteName && *lpBufferSize)
1816 ret = WN_BAD_POINTER;
1817 else
1818 {
1819 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
1820
1821 if (len)
1822 {
1823 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1824
1825 if (wideLocalName)
1826 {
1827 WCHAR wideRemoteStatic[MAX_PATH];
1828 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
1829
1830 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
1831
1832 /* try once without memory allocation */
1833 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
1834 &wideRemoteSize);
1835 if (ret == WN_SUCCESS)
1836 {
1837 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1838 -1, NULL, 0, NULL, NULL);
1839
1840 if (len <= *lpBufferSize)
1841 {
1842 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
1843 lpRemoteName, *lpBufferSize, NULL, NULL);
1844 ret = WN_SUCCESS;
1845 }
1846 else
1847 {
1848 *lpBufferSize = len;
1849 ret = WN_MORE_DATA;
1850 }
1851 }
1852 else if (ret == WN_MORE_DATA)
1853 {
1854 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
1855 wideRemoteSize * sizeof(WCHAR));
1856
1857 if (wideRemote)
1858 {
1859 ret = WNetGetConnectionW(wideLocalName, wideRemote,
1860 &wideRemoteSize);
1861 if (ret == WN_SUCCESS)
1862 {
1863 if (len <= *lpBufferSize)
1864 {
1865 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
1866 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
1867 ret = WN_SUCCESS;
1868 }
1869 else
1870 {
1871 *lpBufferSize = len;
1872 ret = WN_MORE_DATA;
1873 }
1874 }
1875 HeapFree(GetProcessHeap(), 0, wideRemote);
1876 }
1877 else
1878 ret = WN_OUT_OF_MEMORY;
1879 }
1880 HeapFree(GetProcessHeap(), 0, wideLocalName);
1881 }
1882 else
1883 ret = WN_OUT_OF_MEMORY;
1884 }
1885 else
1886 ret = WN_BAD_LOCALNAME;
1887 }
1888 if (ret)
1889 SetLastError(ret);
1890 TRACE("Returning %d\n", ret);
1891 return ret;
1892 }
1893
1894 /* find the network connection for a given drive; helper for WNetGetConnection */
1895 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
1896 {
1897 char buffer[1024];
1898 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
1899 HANDLE mgr;
1900 DWORD ret = WN_NOT_CONNECTED;
1901 DWORD bytes_returned;
1902
1903 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
1904 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1905 0, 0 )) == INVALID_HANDLE_VALUE)
1906 {
1907 ERR( "failed to open mount manager err %u\n", GetLastError() );
1908 return ret;
1909 }
1910 memset( data, 0, sizeof(*data) );
1911 data->letter = letter;
1912 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
1913 data, sizeof(buffer), &bytes_returned, NULL ))
1914 {
1915 char *p, *mount_point = buffer + data->mount_point_offset;
1916 DWORD len;
1917
1918 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
1919 {
1920 mount_point += 2;
1921 mount_point[0] = '\\';
1922 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
1923
1924 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
1925 if (len > *size)
1926 {
1927 *size = len;
1928 ret = WN_MORE_DATA;
1929 }
1930 else
1931 {
1932 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
1933 ret = WN_SUCCESS;
1934 }
1935 }
1936 }
1937 CloseHandle( mgr );
1938 return ret;
1939 }
1940
1941 /**************************************************************************
1942 * WNetGetConnectionW [MPR.@]
1943 *
1944 * FIXME: need to test return values under different errors
1945 */
1946 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
1947 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
1948 {
1949 DWORD ret;
1950
1951 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
1952 lpBufferSize);
1953
1954 if (!lpLocalName)
1955 ret = WN_BAD_POINTER;
1956 else if (!lpBufferSize)
1957 ret = WN_BAD_POINTER;
1958 else if (!lpRemoteName && *lpBufferSize)
1959 ret = WN_BAD_POINTER;
1960 else if (!lpLocalName[0])
1961 ret = WN_BAD_LOCALNAME;
1962 else
1963 {
1964 if (lpLocalName[1] == ':')
1965 {
1966 switch(GetDriveTypeW(lpLocalName))
1967 {
1968 case DRIVE_REMOTE:
1969 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
1970 break;
1971 case DRIVE_REMOVABLE:
1972 case DRIVE_FIXED:
1973 case DRIVE_CDROM:
1974 TRACE("file is local\n");
1975 ret = WN_NOT_CONNECTED;
1976 break;
1977 default:
1978 ret = WN_BAD_LOCALNAME;
1979 }
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 /**************************************************************************
1991 * WNetSetConnectionA [MPR.@]
1992 */
1993 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
1994 LPVOID pvValue )
1995 {
1996 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
1997
1998 SetLastError(WN_NO_NETWORK);
1999 return WN_NO_NETWORK;
2000 }
2001
2002 /**************************************************************************
2003 * WNetSetConnectionW [MPR.@]
2004 */
2005 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2006 LPVOID pvValue )
2007 {
2008 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2009
2010 SetLastError(WN_NO_NETWORK);
2011 return WN_NO_NETWORK;
2012 }
2013
2014 /*****************************************************************
2015 * WNetGetUniversalNameA [MPR.@]
2016 */
2017 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2018 LPVOID lpBuffer, LPDWORD lpBufferSize )
2019 {
2020 DWORD err, size;
2021
2022 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2023 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2024
2025 switch (dwInfoLevel)
2026 {
2027 case UNIVERSAL_NAME_INFO_LEVEL:
2028 {
2029 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2030
2031 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2032 {
2033 err = ERROR_NOT_CONNECTED;
2034 break;
2035 }
2036
2037 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2038 if (*lpBufferSize < size)
2039 {
2040 err = WN_MORE_DATA;
2041 break;
2042 }
2043 info->lpUniversalName = (char *)info + sizeof(*info);
2044 lstrcpyA(info->lpUniversalName, lpLocalPath);
2045 err = WN_NO_ERROR;
2046 break;
2047 }
2048 case REMOTE_NAME_INFO_LEVEL:
2049 err = WN_NO_NETWORK;
2050 break;
2051
2052 default:
2053 err = WN_BAD_VALUE;
2054 break;
2055 }
2056
2057 SetLastError(err);
2058 return err;
2059 }
2060
2061 /*****************************************************************
2062 * WNetGetUniversalNameW [MPR.@]
2063 */
2064 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2065 LPVOID lpBuffer, LPDWORD lpBufferSize )
2066 {
2067 DWORD err, size;
2068
2069 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2070 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2071
2072 switch (dwInfoLevel)
2073 {
2074 case UNIVERSAL_NAME_INFO_LEVEL:
2075 {
2076 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2077
2078 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2079 {
2080 err = ERROR_NOT_CONNECTED;
2081 break;
2082 }
2083
2084 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2085 if (*lpBufferSize < size)
2086 {
2087 err = WN_MORE_DATA;
2088 break;
2089 }
2090 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2091 lstrcpyW(info->lpUniversalName, lpLocalPath);
2092 err = WN_NO_ERROR;
2093 break;
2094 }
2095 case REMOTE_NAME_INFO_LEVEL:
2096 err = WN_NOT_CONNECTED;
2097 break;
2098
2099 default:
2100 err = WN_BAD_VALUE;
2101 break;
2102 }
2103
2104 if (err != WN_NO_ERROR) SetLastError(err);
2105 return err;
2106 }
2107
2108
2109
2110 /*
2111 * Other Functions
2112 */
2113
2114 /**************************************************************************
2115 * WNetGetUserA [MPR.@]
2116 *
2117 * FIXME: we should not return ourselves, but the owner of the drive lpName
2118 */
2119 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2120 {
2121 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2122 return GetLastError();
2123 }
2124
2125 /*****************************************************************
2126 * WNetGetUserW [MPR.@]
2127 *
2128 * FIXME: we should not return ourselves, but the owner of the drive lpName
2129 */
2130 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2131 {
2132 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2133 return GetLastError();
2134 }
2135
2136 /*********************************************************************
2137 * WNetConnectionDialog [MPR.@]
2138 */
2139 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2140 {
2141 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2142
2143 SetLastError(WN_NO_NETWORK);
2144 return WN_NO_NETWORK;
2145 }
2146
2147 /*********************************************************************
2148 * WNetConnectionDialog1A [MPR.@]
2149 */
2150 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2151 {
2152 FIXME( "(%p): stub\n", lpConnDlgStruct );
2153
2154 SetLastError(WN_NO_NETWORK);
2155 return WN_NO_NETWORK;
2156 }
2157
2158 /*********************************************************************
2159 * WNetConnectionDialog1W [MPR.@]
2160 */
2161 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2162 {
2163 FIXME( "(%p): stub\n", lpConnDlgStruct );
2164
2165 SetLastError(WN_NO_NETWORK);
2166 return WN_NO_NETWORK;
2167 }
2168
2169 /*********************************************************************
2170 * WNetDisconnectDialog [MPR.@]
2171 */
2172 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2173 {
2174 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2175
2176 SetLastError(WN_NO_NETWORK);
2177 return WN_NO_NETWORK;
2178 }
2179
2180 /*********************************************************************
2181 * WNetDisconnectDialog1A [MPR.@]
2182 */
2183 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2184 {
2185 FIXME( "(%p): stub\n", lpConnDlgStruct );
2186
2187 SetLastError(WN_NO_NETWORK);
2188 return WN_NO_NETWORK;
2189 }
2190
2191 /*********************************************************************
2192 * WNetDisconnectDialog1W [MPR.@]
2193 */
2194 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2195 {
2196 FIXME( "(%p): stub\n", lpConnDlgStruct );
2197
2198 SetLastError(WN_NO_NETWORK);
2199 return WN_NO_NETWORK;
2200 }
2201
2202 /*********************************************************************
2203 * WNetGetLastErrorA [MPR.@]
2204 */
2205 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2206 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2207 LPSTR lpNameBuf, DWORD nNameBufSize )
2208 {
2209 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2210 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2211
2212 SetLastError(WN_NO_NETWORK);
2213 return WN_NO_NETWORK;
2214 }
2215
2216 /*********************************************************************
2217 * WNetGetLastErrorW [MPR.@]
2218 */
2219 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2220 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2221 LPWSTR lpNameBuf, DWORD nNameBufSize )
2222 {
2223 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2224 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2225
2226 SetLastError(WN_NO_NETWORK);
2227 return WN_NO_NETWORK;
2228 }
2229
2230 /*********************************************************************
2231 * WNetGetNetworkInformationA [MPR.@]
2232 */
2233 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2234 LPNETINFOSTRUCT lpNetInfoStruct )
2235 {
2236 DWORD ret;
2237
2238 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2239
2240 if (!lpProvider)
2241 ret = WN_BAD_POINTER;
2242 else
2243 {
2244 int len;
2245
2246 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2247 if (len)
2248 {
2249 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2250
2251 if (wideProvider)
2252 {
2253 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2254 len);
2255 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2256 HeapFree(GetProcessHeap(), 0, wideProvider);
2257 }
2258 else
2259 ret = WN_OUT_OF_MEMORY;
2260 }
2261 else
2262 ret = GetLastError();
2263 }
2264 if (ret)
2265 SetLastError(ret);
2266 TRACE("Returning %d\n", ret);
2267 return ret;
2268 }
2269
2270 /*********************************************************************
2271 * WNetGetNetworkInformationW [MPR.@]
2272 */
2273 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2274 LPNETINFOSTRUCT lpNetInfoStruct )
2275 {
2276 DWORD ret;
2277
2278 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2279
2280 if (!lpProvider)
2281 ret = WN_BAD_POINTER;
2282 else if (!lpNetInfoStruct)
2283 ret = WN_BAD_POINTER;
2284 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2285 ret = WN_BAD_VALUE;
2286 else
2287 {
2288 if (providerTable && providerTable->numProviders)
2289 {
2290 DWORD providerIndex = _findProviderIndexW(lpProvider);
2291
2292 if (providerIndex != BAD_PROVIDER_INDEX)
2293 {
2294 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2295 lpNetInfoStruct->dwProviderVersion =
2296 providerTable->table[providerIndex].dwSpecVersion;
2297 lpNetInfoStruct->dwStatus = NO_ERROR;
2298 lpNetInfoStruct->dwCharacteristics = 0;
2299 lpNetInfoStruct->dwHandle = 0;
2300 lpNetInfoStruct->wNetType =
2301 HIWORD(providerTable->table[providerIndex].dwNetType);
2302 lpNetInfoStruct->dwPrinters = -1;
2303 lpNetInfoStruct->dwDrives = -1;
2304 ret = WN_SUCCESS;
2305 }
2306 else
2307 ret = WN_BAD_PROVIDER;
2308 }
2309 else
2310 ret = WN_NO_NETWORK;
2311 }
2312 if (ret)
2313 SetLastError(ret);
2314 TRACE("Returning %d\n", ret);
2315 return ret;
2316 }
2317
2318 /*****************************************************************
2319 * WNetGetProviderNameA [MPR.@]
2320 */
2321 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2322 LPSTR lpProvider, LPDWORD lpBufferSize )
2323 {
2324 DWORD ret;
2325
2326 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2327 lpBufferSize);
2328
2329 if (!lpProvider)
2330 ret = WN_BAD_POINTER;
2331 else if (!lpBufferSize)
2332 ret = WN_BAD_POINTER;
2333 else
2334 {
2335 if (providerTable)
2336 {
2337 DWORD i;
2338
2339 ret = WN_NO_NETWORK;
2340 for (i = 0; i < providerTable->numProviders &&
2341 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2342 i++)
2343 ;
2344 if (i < providerTable->numProviders)
2345 {
2346 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2347 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2348
2349 if (*lpBufferSize < sizeNeeded)
2350 {
2351 *lpBufferSize = sizeNeeded;
2352 ret = WN_MORE_DATA;
2353 }
2354 else
2355 {
2356 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2357 -1, lpProvider, *lpBufferSize, NULL, NULL);
2358 ret = WN_SUCCESS;
2359 /* FIXME: is *lpBufferSize set to the number of characters
2360 * copied? */
2361 }
2362 }
2363 }
2364 else
2365 ret = WN_NO_NETWORK;
2366 }
2367 if (ret)
2368 SetLastError(ret);
2369 TRACE("Returning %d\n", ret);
2370 return ret;
2371 }
2372
2373 /*****************************************************************
2374 * WNetGetProviderNameW [MPR.@]
2375 */
2376 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2377 LPWSTR lpProvider, LPDWORD lpBufferSize )
2378 {
2379 DWORD ret;
2380
2381 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2382 lpBufferSize);
2383
2384 if (!lpProvider)
2385 ret = WN_BAD_POINTER;
2386 else if (!lpBufferSize)
2387 ret = WN_BAD_POINTER;
2388 else
2389 {
2390 if (providerTable)
2391 {
2392 DWORD i;
2393
2394 ret = WN_NO_NETWORK;
2395 for (i = 0; i < providerTable->numProviders &&
2396 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2397 i++)
2398 ;
2399 if (i < providerTable->numProviders)
2400 {
2401 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2402
2403 if (*lpBufferSize < sizeNeeded)
2404 {
2405 *lpBufferSize = sizeNeeded;
2406 ret = WN_MORE_DATA;
2407 }
2408 else
2409 {
2410 strcpyW(lpProvider, providerTable->table[i].name);
2411 ret = WN_SUCCESS;
2412 /* FIXME: is *lpBufferSize set to the number of characters
2413 * copied? */
2414 }
2415 }
2416 }
2417 else
2418 ret = WN_NO_NETWORK;
2419 }
2420 if (ret)
2421 SetLastError(ret);
2422 TRACE("Returning %d\n", ret);
2423 return ret;
2424 }