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