[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 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 case WNET_ENUMERATOR_TYPE_NULL:
1458 ret = WN_SUCCESS;
1459 break;
1460 case WNET_ENUMERATOR_TYPE_GLOBAL:
1461 if (enumerator->lpBuffer)
1462 _freeEnumNetResource(enumerator->lpBuffer);
1463 if (enumerator->handle)
1464 providerTable->table[enumerator->providerIndex].
1465 closeEnum(enumerator->handle);
1466 ret = WN_SUCCESS;
1467 break;
1468 case WNET_ENUMERATOR_TYPE_PROVIDER:
1469 if (enumerator->handle)
1470 providerTable->table[enumerator->providerIndex].
1471 closeEnum(enumerator->handle);
1472 ret = WN_SUCCESS;
1473 break;
1474 default:
1475 WARN("bogus enumerator type!\n");
1476 ret = WN_BAD_HANDLE;
1477 }
1478 HeapFree(GetProcessHeap(), 0, hEnum);
1479 }
1480 else
1481 ret = WN_BAD_HANDLE;
1482 if (ret)
1483 SetLastError(ret);
1484 TRACE("Returning %d\n", ret);
1485 return ret;
1486 }
1487
1488 /*********************************************************************
1489 * WNetGetResourceInformationA [MPR.@]
1490 *
1491 * See WNetGetResourceInformationW
1492 */
1493 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
1494 LPVOID lpBuffer, LPDWORD cbBuffer,
1495 LPSTR *lplpSystem )
1496 {
1497 DWORD ret;
1498
1499 TRACE( "(%p, %p, %p, %p)\n",
1500 lpNetResource, lpBuffer, cbBuffer, lplpSystem );
1501
1502 if (!providerTable || providerTable->numProviders == 0)
1503 ret = WN_NO_NETWORK;
1504 else if (lpNetResource)
1505 {
1506 LPNETRESOURCEW lpNetResourceW = NULL;
1507 DWORD size = 1024, count = 1;
1508 DWORD len;
1509
1510 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1511 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
1512 if (ret == WN_MORE_DATA)
1513 {
1514 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1515 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
1516 if (lpNetResourceW)
1517 ret = _thunkNetResourceArrayAToW(lpNetResource,
1518 &count, lpNetResourceW, &size);
1519 else
1520 ret = WN_OUT_OF_MEMORY;
1521 }
1522 if (ret == WN_SUCCESS)
1523 {
1524 LPWSTR lpSystemW = NULL;
1525 LPVOID lpBufferW;
1526 size = 1024;
1527 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1528 if (lpBufferW)
1529 {
1530 ret = WNetGetResourceInformationW(lpNetResourceW,
1531 lpBufferW, &size, &lpSystemW);
1532 if (ret == WN_MORE_DATA)
1533 {
1534 HeapFree(GetProcessHeap(), 0, lpBufferW);
1535 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
1536 if (lpBufferW)
1537 ret = WNetGetResourceInformationW(lpNetResourceW,
1538 lpBufferW, &size, &lpSystemW);
1539 else
1540 ret = WN_OUT_OF_MEMORY;
1541 }
1542 if (ret == WN_SUCCESS)
1543 {
1544 ret = _thunkNetResourceArrayWToA(lpBufferW,
1545 &count, lpBuffer, cbBuffer);
1546 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1547 lpNetResourceW = lpBufferW;
1548 size = sizeof(NETRESOURCEA);
1549 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
1550 -1, NULL, 0, NULL, NULL);
1551 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
1552 -1, NULL, 0, NULL, NULL);
1553
1554 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
1555 -1, NULL, 0, NULL, NULL);
1556 if ((len) && ( size + len < *cbBuffer))
1557 {
1558 *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
1559 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
1560 *lplpSystem, len, NULL, NULL);
1561 ret = WN_SUCCESS;
1562 }
1563 else
1564 ret = WN_MORE_DATA;
1565 }
1566 else
1567 ret = WN_OUT_OF_MEMORY;
1568 HeapFree(GetProcessHeap(), 0, lpBufferW);
1569 }
1570 else
1571 ret = WN_OUT_OF_MEMORY;
1572 HeapFree(GetProcessHeap(), 0, lpSystemW);
1573 }
1574 HeapFree(GetProcessHeap(), 0, lpNetResourceW);
1575 }
1576 else
1577 ret = WN_NO_NETWORK;
1578
1579 if (ret)
1580 SetLastError(ret);
1581 TRACE("Returning %d\n", ret);
1582 return ret;
1583 }
1584
1585 /*********************************************************************
1586 * WNetGetResourceInformationW [MPR.@]
1587 *
1588 * WNetGetResourceInformationW function identifies the network provider
1589 * that owns the resource and gets information about the type of the resource.
1590 *
1591 * PARAMS:
1592 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1593 * defines a network resource.
1594 * lpBuffer [ O] the pointer to buffer, containing result. It
1595 * contains NETRESOURCEW structure and strings to
1596 * which the members of the NETRESOURCEW structure
1597 * point.
1598 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1599 * in bytes.
1600 * lplpSystem [ O] the pointer to string in the output buffer,
1601 * containing the part of the resource name without
1602 * names of the server and share.
1603 *
1604 * RETURNS:
1605 * NO_ERROR if the function succeeds. System error code if the function fails.
1606 */
1607
1608 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
1609 LPVOID lpBuffer, LPDWORD cbBuffer,
1610 LPWSTR *lplpSystem )
1611 {
1612 DWORD ret = WN_NO_NETWORK;
1613 DWORD index;
1614
1615 TRACE( "(%p, %p, %p, %p)\n",
1616 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1617
1618 if (!(lpBuffer))
1619 ret = WN_OUT_OF_MEMORY;
1620 else if (providerTable != NULL)
1621 {
1622 /* FIXME: For function value of a variable is indifferent, it does
1623 * search of all providers in a network.
1624 */
1625 for (index = 0; index < providerTable->numProviders; index++)
1626 {
1627 if(providerTable->table[index].getCaps(WNNC_DIALOG) &
1628 WNNC_DLG_GETRESOURCEINFORMATION)
1629 {
1630 if (providerTable->table[index].getResourceInformation)
1631 ret = providerTable->table[index].getResourceInformation(
1632 lpNetResource, lpBuffer, cbBuffer, lplpSystem);
1633 else
1634 ret = WN_NO_NETWORK;
1635 if (ret == WN_SUCCESS)
1636 break;
1637 }
1638 }
1639 }
1640 if (ret)
1641 SetLastError(ret);
1642 return ret;
1643 }
1644
1645 /*********************************************************************
1646 * WNetGetResourceParentA [MPR.@]
1647 */
1648 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
1649 LPVOID lpBuffer, LPDWORD lpBufferSize )
1650 {
1651 FIXME( "(%p, %p, %p): stub\n",
1652 lpNetResource, lpBuffer, lpBufferSize );
1653
1654 SetLastError(WN_NO_NETWORK);
1655 return WN_NO_NETWORK;
1656 }
1657
1658 /*********************************************************************
1659 * WNetGetResourceParentW [MPR.@]
1660 */
1661 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
1662 LPVOID lpBuffer, LPDWORD lpBufferSize )
1663 {
1664 FIXME( "(%p, %p, %p): stub\n",
1665 lpNetResource, lpBuffer, lpBufferSize );
1666
1667 SetLastError(WN_NO_NETWORK);
1668 return WN_NO_NETWORK;
1669 }
1670
1671
1672
1673 /*
1674 * Connection Functions
1675 */
1676
1677 /*********************************************************************
1678 * WNetAddConnectionA [MPR.@]
1679 */
1680 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
1681 LPCSTR lpLocalName )
1682 {
1683 NETRESOURCEA resourcesA;
1684
1685 memset(&resourcesA, 0, sizeof(resourcesA));
1686 resourcesA.lpRemoteName = (LPSTR)lpRemoteName;
1687 resourcesA.lpLocalName = (LPSTR)lpLocalName;
1688 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL);
1689 }
1690
1691 /*********************************************************************
1692 * WNetAddConnectionW [MPR.@]
1693 */
1694 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
1695 LPCWSTR lpLocalName )
1696 {
1697 NETRESOURCEW resourcesW;
1698
1699 memset(&resourcesW, 0, sizeof(resourcesW));
1700 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName;
1701 resourcesW.lpLocalName = (LPWSTR)lpLocalName;
1702 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL);
1703 }
1704
1705 /*********************************************************************
1706 * WNetAddConnection2A [MPR.@]
1707 */
1708 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
1709 LPCSTR lpPassword, LPCSTR lpUserID,
1710 DWORD dwFlags )
1711 {
1712 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1713 NULL, 0, NULL);
1714 }
1715
1716 /*********************************************************************
1717 * WNetAddConnection2W [MPR.@]
1718 */
1719 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
1720 LPCWSTR lpPassword, LPCWSTR lpUserID,
1721 DWORD dwFlags )
1722 {
1723 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags,
1724 NULL, 0, NULL);
1725 }
1726
1727 /*********************************************************************
1728 * WNetAddConnection3A [MPR.@]
1729 */
1730 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
1731 LPCSTR lpPassword, LPCSTR lpUserID,
1732 DWORD dwFlags )
1733 {
1734 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID,
1735 dwFlags, NULL, 0, NULL);
1736 }
1737
1738 /*********************************************************************
1739 * WNetAddConnection3W [MPR.@]
1740 */
1741 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
1742 LPCWSTR lpPassword, LPCWSTR lpUserID,
1743 DWORD dwFlags )
1744 {
1745 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID,
1746 dwFlags, NULL, 0, NULL);
1747 }
1748
1749 struct use_connection_context
1750 {
1751 HWND hwndOwner;
1752 NETRESOURCEW *resource;
1753 NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */
1754 WCHAR *password;
1755 WCHAR *userid;
1756 DWORD flags;
1757 void *accessname;
1758 DWORD *buffer_size;
1759 DWORD *result;
1760 DWORD (*pre_set_accessname)(struct use_connection_context*, WCHAR *);
1761 void (*set_accessname)(struct use_connection_context*, WCHAR *);
1762 };
1763
1764 static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1765 {
1766 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1767 {
1768 DWORD len;
1769
1770 if (local_name)
1771 len = strlenW(local_name);
1772 else
1773 len = strlenW(ctxt->resource->lpRemoteName);
1774
1775 if (++len > *ctxt->buffer_size)
1776 {
1777 *ctxt->buffer_size = len;
1778 return ERROR_MORE_DATA;
1779 }
1780 }
1781 else
1782 ctxt->accessname = NULL;
1783
1784 return ERROR_SUCCESS;
1785 }
1786
1787 static void use_connection_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
1788 {
1789 WCHAR *accessname = ctxt->accessname;
1790 if (local_name)
1791 {
1792 strcpyW(accessname, local_name);
1793 if (ctxt->result)
1794 *ctxt->result = CONNECT_LOCALDRIVE;
1795 }
1796 else
1797 strcpyW(accessname, ctxt->resource->lpRemoteName);
1798 }
1799
1800 static WCHAR * select_provider(struct use_connection_context *ctxt)
1801 {
1802 DWORD ret, prov_size = 0x1000, len;
1803 LPNETRESOURCEW provider;
1804 WCHAR * system;
1805 WCHAR * provider_name;
1806
1807 provider = HeapAlloc(GetProcessHeap(), 0, prov_size);
1808 if (!provider)
1809 {
1810 return NULL;
1811 }
1812
1813 ret = WNetGetResourceInformationW(ctxt->resource, provider, &prov_size, &system);
1814 if (ret == ERROR_MORE_DATA)
1815 {
1816 HeapFree(GetProcessHeap(), 0, provider);
1817 provider = HeapAlloc(GetProcessHeap(), 0, prov_size);
1818 if (!provider)
1819 {
1820 return NULL;
1821 }
1822
1823 ret = WNetGetResourceInformationW(ctxt->resource, provider, &prov_size, &system);
1824 }
1825
1826 if (ret != NO_ERROR)
1827 {
1828 HeapFree(GetProcessHeap(), 0, provider);
1829 return NULL;
1830 }
1831
1832 len = WideCharToMultiByte(CP_ACP, 0, provider->lpProvider, -1, NULL, 0, NULL, NULL);
1833 provider_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1834 if (provider_name)
1835 memcpy(provider_name, provider->lpProvider, len * sizeof(WCHAR));
1836
1837 HeapFree(GetProcessHeap(), 0, provider);
1838
1839 return provider_name;
1840 }
1841
1842 static DWORD wnet_use_connection( struct use_connection_context *ctxt )
1843 {
1844 WNetProvider *provider;
1845 DWORD index, ret, caps;
1846 BOOLEAN redirect = FALSE, prov = FALSE;
1847 WCHAR letter[3] = {'z', ':', 0};
1848 NETRESOURCEW netres;
1849
1850 if (!providerTable || providerTable->numProviders == 0)
1851 return WN_NO_NETWORK;
1852
1853 if (!ctxt->resource)
1854 return ERROR_INVALID_PARAMETER;
1855 netres = *ctxt->resource;
1856
1857 if (!netres.lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
1858 {
1859 if (netres.dwType != RESOURCETYPE_DISK && netres.dwType != RESOURCETYPE_PRINT)
1860 {
1861 return ERROR_BAD_DEV_TYPE;
1862 }
1863
1864 if (netres.dwType == RESOURCETYPE_PRINT)
1865 {
1866 FIXME("Locale device selection is not implemented for printers.\n");
1867 return WN_NO_NETWORK;
1868 }
1869
1870 redirect = TRUE;
1871 netres.lpLocalName = letter;
1872 }
1873
1874 if (ctxt->flags & CONNECT_INTERACTIVE)
1875 {
1876 return ERROR_BAD_NET_NAME;
1877 }
1878
1879 if (ctxt->flags & CONNECT_UPDATE_PROFILE)
1880 FIXME("Connection saving is not implemented\n");
1881
1882 if (!netres.lpProvider)
1883 {
1884 netres.lpProvider = select_provider(ctxt);
1885 if (!netres.lpProvider)
1886 {
1887 return ERROR_NO_NET_OR_BAD_PATH;
1888 }
1889
1890 prov = TRUE;
1891 }
1892
1893 index = _findProviderIndexW(netres.lpProvider);
1894 if (index == BAD_PROVIDER_INDEX)
1895 {
1896 ret = ERROR_BAD_PROVIDER;
1897 goto done;
1898 }
1899
1900 provider = &providerTable->table[index];
1901 caps = provider->getCaps(WNNC_CONNECTION);
1902 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
1903 {
1904 ret = ERROR_BAD_PROVIDER;
1905 goto done;
1906 }
1907
1908 if ((ret = ctxt->pre_set_accessname(ctxt, netres.lpLocalName)))
1909 {
1910 goto done;
1911 }
1912
1913 ret = WN_ACCESS_DENIED;
1914 do
1915 {
1916 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
1917 ret = provider->addConnection3(ctxt->hwndOwner, &netres, ctxt->password, ctxt->userid, ctxt->flags);
1918 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
1919 ret = provider->addConnection(&netres, ctxt->password, ctxt->userid);
1920
1921 if (ret != NO_ERROR && redirect)
1922 letter[0] -= 1;
1923 } while (redirect && ret == WN_ALREADY_CONNECTED && letter[0] >= 'c');
1924
1925 if (ret == WN_SUCCESS && ctxt->accessname)
1926 ctxt->set_accessname(ctxt, netres.lpLocalName);
1927
1928 done:
1929 if (prov)
1930 HeapFree(GetProcessHeap(), 0, netres.lpProvider);
1931
1932 return ret;
1933 }
1934
1935 /*****************************************************************
1936 * WNetUseConnectionW [MPR.@]
1937 */
1938 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
1939 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
1940 {
1941 struct use_connection_context ctxt;
1942
1943 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1944 hwndOwner, resource, password, debugstr_w(userid), flags,
1945 accessname, buffer_size, result );
1946
1947 ctxt.hwndOwner = hwndOwner;
1948 ctxt.resource = resource;
1949 ctxt.resourceA = NULL;
1950 ctxt.password = (WCHAR*)password;
1951 ctxt.userid = (WCHAR*)userid;
1952 ctxt.flags = flags;
1953 ctxt.accessname = accessname;
1954 ctxt.buffer_size = buffer_size;
1955 ctxt.result = result;
1956 ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
1957 ctxt.set_accessname = use_connection_set_accessnameW;
1958
1959 return wnet_use_connection(&ctxt);
1960 }
1961
1962 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
1963 {
1964 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
1965 {
1966 DWORD len;
1967
1968 if (local_name)
1969 len = WideCharToMultiByte(CP_ACP, 0, local_name, -1, NULL, 0, NULL, NULL) - 1;
1970 else
1971 len = strlen(ctxt->resourceA->lpRemoteName);
1972
1973 if (++len > *ctxt->buffer_size)
1974 {
1975 *ctxt->buffer_size = len;
1976 return ERROR_MORE_DATA;
1977 }
1978 }
1979 else
1980 ctxt->accessname = NULL;
1981
1982 return ERROR_SUCCESS;
1983 }
1984
1985 static void use_connection_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
1986 {
1987 char *accessname = ctxt->accessname;
1988 if (local_name)
1989 {
1990 WideCharToMultiByte(CP_ACP, 0, local_name, -1, accessname, *ctxt->buffer_size, NULL, NULL);
1991 if (ctxt->result)
1992 *ctxt->result = CONNECT_LOCALDRIVE;
1993 }
1994 else
1995 strcpy(accessname, ctxt->resourceA->lpRemoteName);
1996 }
1997
1998 static LPWSTR strdupAtoW( LPCSTR str )
1999 {
2000 LPWSTR ret;
2001 INT len;
2002
2003 if (!str) return NULL;
2004 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
2005 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2006 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
2007 return ret;
2008 }
2009
2010 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
2011 {
2012 resourceW->dwScope = resourceA->dwScope;
2013 resourceW->dwType = resourceA->dwType;
2014 resourceW->dwDisplayType = resourceA->dwDisplayType;
2015 resourceW->dwUsage = resourceA->dwUsage;
2016 resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
2017 resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
2018 resourceW->lpComment = strdupAtoW(resourceA->lpComment);
2019 resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
2020 }
2021
2022 static void free_netresourceW( NETRESOURCEW *resource )
2023 {
2024 HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
2025 HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
2026 HeapFree(GetProcessHeap(), 0, resource->lpComment);
2027 HeapFree(GetProcessHeap(), 0, resource->lpProvider);
2028 }
2029
2030 /*****************************************************************
2031 * WNetUseConnectionA [MPR.@]
2032 */
2033 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
2034 LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
2035 DWORD *buffer_size, DWORD *result )
2036 {
2037 struct use_connection_context ctxt;
2038 NETRESOURCEW resourceW;
2039 DWORD ret;
2040
2041 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
2042 accessname, buffer_size, result );
2043
2044 netresource_a_to_w(resource, &resourceW);
2045
2046 ctxt.hwndOwner = hwndOwner;
2047 ctxt.resource = &resourceW;
2048 ctxt.resourceA = resource;
2049 ctxt.password = strdupAtoW(password);
2050 ctxt.userid = strdupAtoW(userid);
2051 ctxt.flags = flags;
2052 ctxt.accessname = accessname;
2053 ctxt.buffer_size = buffer_size;
2054 ctxt.result = result;
2055 ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
2056 ctxt.set_accessname = use_connection_set_accessnameA;
2057
2058 ret = wnet_use_connection(&ctxt);
2059
2060 free_netresourceW(&resourceW);
2061 HeapFree(GetProcessHeap(), 0, ctxt.password);
2062 HeapFree(GetProcessHeap(), 0, ctxt.userid);
2063
2064 return ret;
2065 }
2066
2067 /*********************************************************************
2068 * WNetCancelConnectionA [MPR.@]
2069 */
2070 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
2071 {
2072 return WNetCancelConnection2A(lpName, 0, fForce);
2073 }
2074
2075 /*********************************************************************
2076 * WNetCancelConnectionW [MPR.@]
2077 */
2078 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
2079 {
2080 return WNetCancelConnection2W(lpName, 0, fForce);
2081 }
2082
2083 /*********************************************************************
2084 * WNetCancelConnection2A [MPR.@]
2085 */
2086 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
2087 {
2088 DWORD ret;
2089 WCHAR * name = strdupAtoW(lpName);
2090 if (!name)
2091 return ERROR_NOT_CONNECTED;
2092
2093 ret = WNetCancelConnection2W(name, dwFlags, fForce);
2094 HeapFree(GetProcessHeap(), 0, name);
2095
2096 return ret;
2097 }
2098
2099 /*********************************************************************
2100 * WNetCancelConnection2W [MPR.@]
2101 */
2102 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
2103 {
2104 DWORD ret = WN_NO_NETWORK;
2105 DWORD index;
2106
2107 if (providerTable != NULL)
2108 {
2109 for (index = 0; index < providerTable->numProviders; index++)
2110 {
2111 if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2112 WNNC_CON_GETCONNECTIONS)
2113 {
2114 if (providerTable->table[index].cancelConnection)
2115 ret = providerTable->table[index].cancelConnection((LPWSTR)lpName, fForce);
2116 else
2117 ret = WN_NO_NETWORK;
2118 if (ret == WN_SUCCESS || ret == WN_OPEN_FILES)
2119 break;
2120 }
2121 }
2122 }
2123 return ret;
2124 }
2125
2126 /*****************************************************************
2127 * WNetRestoreConnectionA [MPR.@]
2128 */
2129 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
2130 {
2131 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
2132
2133 SetLastError(WN_NO_NETWORK);
2134 return WN_NO_NETWORK;
2135 }
2136
2137 /*****************************************************************
2138 * WNetRestoreConnectionW [MPR.@]
2139 */
2140 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
2141 {
2142 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
2143
2144 SetLastError(WN_NO_NETWORK);
2145 return WN_NO_NETWORK;
2146 }
2147
2148 /**************************************************************************
2149 * WNetGetConnectionA [MPR.@]
2150 *
2151 * RETURNS
2152 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2153 * - WN_NOT_CONNECTED drive is a local drive
2154 * - WN_MORE_DATA buffer isn't big enough
2155 * - WN_SUCCESS success (net path in buffer)
2156 *
2157 * FIXME: need to test return values under different errors
2158 */
2159 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
2160 LPSTR lpRemoteName, LPDWORD lpBufferSize )
2161 {
2162 DWORD ret;
2163
2164 if (!lpLocalName)
2165 ret = WN_BAD_POINTER;
2166 else if (!lpBufferSize)
2167 ret = WN_BAD_POINTER;
2168 else if (!lpRemoteName && *lpBufferSize)
2169 ret = WN_BAD_POINTER;
2170 else
2171 {
2172 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
2173
2174 if (len)
2175 {
2176 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2177
2178 if (wideLocalName)
2179 {
2180 WCHAR wideRemoteStatic[MAX_PATH];
2181 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
2182
2183 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
2184
2185 /* try once without memory allocation */
2186 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
2187 &wideRemoteSize);
2188 if (ret == WN_SUCCESS)
2189 {
2190 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2191 -1, NULL, 0, NULL, NULL);
2192
2193 if (len <= *lpBufferSize)
2194 {
2195 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
2196 lpRemoteName, *lpBufferSize, NULL, NULL);
2197 ret = WN_SUCCESS;
2198 }
2199 else
2200 {
2201 *lpBufferSize = len;
2202 ret = WN_MORE_DATA;
2203 }
2204 }
2205 else if (ret == WN_MORE_DATA)
2206 {
2207 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
2208 wideRemoteSize * sizeof(WCHAR));
2209
2210 if (wideRemote)
2211 {
2212 ret = WNetGetConnectionW(wideLocalName, wideRemote,
2213 &wideRemoteSize);
2214 if (ret == WN_SUCCESS)
2215 {
2216 if (len <= *lpBufferSize)
2217 {
2218 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
2219 -1, lpRemoteName, *lpBufferSize, NULL, NULL);
2220 ret = WN_SUCCESS;
2221 }
2222 else
2223 {
2224 *lpBufferSize = len;
2225 ret = WN_MORE_DATA;
2226 }
2227 }
2228 HeapFree(GetProcessHeap(), 0, wideRemote);
2229 }
2230 else
2231 ret = WN_OUT_OF_MEMORY;
2232 }
2233 HeapFree(GetProcessHeap(), 0, wideLocalName);
2234 }
2235 else
2236 ret = WN_OUT_OF_MEMORY;
2237 }
2238 else
2239 ret = WN_BAD_LOCALNAME;
2240 }
2241 if (ret)
2242 SetLastError(ret);
2243 TRACE("Returning %d\n", ret);
2244 return ret;
2245 }
2246
2247 /* find the network connection for a given drive; helper for WNetGetConnection */
2248 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
2249 {
2250 #ifndef __REACTOS__
2251 char buffer[1024];
2252 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
2253 HANDLE mgr;
2254 DWORD ret = WN_NOT_CONNECTED;
2255 DWORD bytes_returned;
2256
2257 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
2258 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
2259 0, 0 )) == INVALID_HANDLE_VALUE)
2260 {
2261 ERR( "failed to open mount manager err %u\n", GetLastError() );
2262 return ret;
2263 }
2264 memset( data, 0, sizeof(*data) );
2265 data->letter = letter;
2266 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
2267 data, sizeof(buffer), &bytes_returned, NULL ))
2268 {
2269 char *p, *mount_point = buffer + data->mount_point_offset;
2270 DWORD len;
2271
2272 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
2273 {
2274 mount_point += 2;
2275 mount_point[0] = '\\';
2276 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
2277
2278 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
2279 if (len > *size)
2280 {
2281 *size = len;
2282 ret = WN_MORE_DATA;
2283 }
2284 else
2285 {
2286 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
2287 ret = WN_SUCCESS;
2288 }
2289 }
2290 }
2291 CloseHandle( mgr );
2292 return ret;
2293 #else
2294 DWORD ret = WN_NO_NETWORK;
2295 DWORD index;
2296 WCHAR local[3] = {letter, ':', 0};
2297
2298 if (providerTable != NULL)
2299 {
2300 for (index = 0; index < providerTable->numProviders; index++)
2301 {
2302 if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
2303 WNNC_CON_GETCONNECTIONS)
2304 {
2305 if (providerTable->table[index].getConnection)
2306 ret = providerTable->table[index].getConnection(
2307 local, remote, size);
2308 else
2309 ret = WN_NO_NETWORK;
2310 if (ret == WN_SUCCESS || ret == WN_MORE_DATA)
2311 break;
2312 }
2313 }
2314 }
2315 if (ret)
2316 SetLastError(ret);
2317 return ret;
2318 #endif
2319 }
2320
2321 /**************************************************************************
2322 * WNetGetConnectionW [MPR.@]
2323 *
2324 * FIXME: need to test return values under different errors
2325 */
2326 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
2327 LPWSTR lpRemoteName, LPDWORD lpBufferSize )
2328 {
2329 DWORD ret;
2330
2331 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
2332 lpBufferSize);
2333
2334 if (!lpLocalName)
2335 ret = WN_BAD_POINTER;
2336 else if (!lpBufferSize)
2337 ret = WN_BAD_POINTER;
2338 else if (!lpRemoteName && *lpBufferSize)
2339 ret = WN_BAD_POINTER;
2340 else if (!lpLocalName[0])
2341 ret = WN_BAD_LOCALNAME;
2342 else
2343 {
2344 if (lpLocalName[1] == ':')
2345 {
2346 switch(GetDriveTypeW(lpLocalName))
2347 {
2348 case DRIVE_REMOTE:
2349 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
2350 break;
2351 case DRIVE_REMOVABLE:
2352 case DRIVE_FIXED:
2353 case DRIVE_CDROM:
2354 TRACE("file is local\n");
2355 ret = WN_NOT_CONNECTED;
2356 break;
2357 default:
2358 ret = WN_BAD_LOCALNAME;
2359 }
2360 }
2361 else
2362 ret = WN_BAD_LOCALNAME;
2363 }
2364 if (ret)
2365 SetLastError(ret);
2366 TRACE("Returning %d\n", ret);
2367 return ret;
2368 }
2369
2370 /**************************************************************************
2371 * WNetSetConnectionA [MPR.@]
2372 */
2373 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
2374 LPVOID pvValue )
2375 {
2376 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
2377
2378 SetLastError(WN_NO_NETWORK);
2379 return WN_NO_NETWORK;
2380 }
2381
2382 /**************************************************************************
2383 * WNetSetConnectionW [MPR.@]
2384 */
2385 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
2386 LPVOID pvValue )
2387 {
2388 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
2389
2390 SetLastError(WN_NO_NETWORK);
2391 return WN_NO_NETWORK;
2392 }
2393
2394 /*****************************************************************
2395 * WNetGetUniversalNameA [MPR.@]
2396 */
2397 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
2398 LPVOID lpBuffer, LPDWORD lpBufferSize )
2399 {
2400 DWORD err, size;
2401
2402 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2403 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2404
2405 switch (dwInfoLevel)
2406 {
2407 case UNIVERSAL_NAME_INFO_LEVEL:
2408 {
2409 LPUNIVERSAL_NAME_INFOA info = lpBuffer;
2410
2411 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE)
2412 {
2413 err = ERROR_NOT_CONNECTED;
2414 break;
2415 }
2416
2417 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
2418 if (*lpBufferSize < size)
2419 {
2420 err = WN_MORE_DATA;
2421 break;
2422 }
2423 info->lpUniversalName = (char *)info + sizeof(*info);
2424 lstrcpyA(info->lpUniversalName, lpLocalPath);
2425 err = WN_NO_ERROR;
2426 break;
2427 }
2428 case REMOTE_NAME_INFO_LEVEL:
2429 err = WN_NOT_CONNECTED;
2430 break;
2431
2432 default:
2433 err = WN_BAD_VALUE;
2434 break;
2435 }
2436
2437 SetLastError(err);
2438 return err;
2439 }
2440
2441 /*****************************************************************
2442 * WNetGetUniversalNameW [MPR.@]
2443 */
2444 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
2445 LPVOID lpBuffer, LPDWORD lpBufferSize )
2446 {
2447 DWORD err, size;
2448
2449 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2450 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
2451
2452 switch (dwInfoLevel)
2453 {
2454 case UNIVERSAL_NAME_INFO_LEVEL:
2455 {
2456 LPUNIVERSAL_NAME_INFOW info = lpBuffer;
2457
2458 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE)
2459 {
2460 err = ERROR_NOT_CONNECTED;
2461 break;
2462 }
2463
2464 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
2465 if (*lpBufferSize < size)
2466 {
2467 err = WN_MORE_DATA;
2468 break;
2469 }
2470 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
2471 lstrcpyW(info->lpUniversalName, lpLocalPath);
2472 err = WN_NO_ERROR;
2473 break;
2474 }
2475 case REMOTE_NAME_INFO_LEVEL:
2476 err = WN_NO_NETWORK;
2477 break;
2478
2479 default:
2480 err = WN_BAD_VALUE;
2481 break;
2482 }
2483
2484 if (err != WN_NO_ERROR) SetLastError(err);
2485 return err;
2486 }
2487
2488
2489
2490 /*
2491 * Other Functions
2492 */
2493
2494 /**************************************************************************
2495 * WNetGetUserA [MPR.@]
2496 *
2497 * FIXME: we should not return ourselves, but the owner of the drive lpName
2498 */
2499 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
2500 {
2501 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
2502 return GetLastError();
2503 }
2504
2505 /*****************************************************************
2506 * WNetGetUserW [MPR.@]
2507 *
2508 * FIXME: we should not return ourselves, but the owner of the drive lpName
2509 */
2510 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
2511 {
2512 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
2513 return GetLastError();
2514 }
2515
2516 /*********************************************************************
2517 * WNetConnectionDialog [MPR.@]
2518 */
2519 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
2520 {
2521 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2522
2523 SetLastError(WN_NO_NETWORK);
2524 return WN_NO_NETWORK;
2525 }
2526
2527 /*********************************************************************
2528 * WNetConnectionDialog1A [MPR.@]
2529 */
2530 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
2531 {
2532 FIXME( "(%p): stub\n", lpConnDlgStruct );
2533
2534 SetLastError(WN_NO_NETWORK);
2535 return WN_NO_NETWORK;
2536 }
2537
2538 /*********************************************************************
2539 * WNetConnectionDialog1W [MPR.@]
2540 */
2541 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
2542 {
2543 FIXME( "(%p): stub\n", lpConnDlgStruct );
2544
2545 SetLastError(WN_NO_NETWORK);
2546 return WN_NO_NETWORK;
2547 }
2548
2549 /*********************************************************************
2550 * WNetDisconnectDialog [MPR.@]
2551 */
2552 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
2553 {
2554 FIXME( "(%p, %08X): stub\n", hwnd, dwType );
2555
2556 SetLastError(WN_NO_NETWORK);
2557 return WN_NO_NETWORK;
2558 }
2559
2560 /*********************************************************************
2561 * WNetDisconnectDialog1A [MPR.@]
2562 */
2563 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
2564 {
2565 FIXME( "(%p): stub\n", lpConnDlgStruct );
2566
2567 SetLastError(WN_NO_NETWORK);
2568 return WN_NO_NETWORK;
2569 }
2570
2571 /*********************************************************************
2572 * WNetDisconnectDialog1W [MPR.@]
2573 */
2574 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
2575 {
2576 FIXME( "(%p): stub\n", lpConnDlgStruct );
2577
2578 SetLastError(WN_NO_NETWORK);
2579 return WN_NO_NETWORK;
2580 }
2581
2582 /*********************************************************************
2583 * WNetGetLastErrorA [MPR.@]
2584 */
2585 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
2586 LPSTR lpErrorBuf, DWORD nErrorBufSize,
2587 LPSTR lpNameBuf, DWORD nNameBufSize )
2588 {
2589 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2590 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2591
2592 SetLastError(WN_NO_NETWORK);
2593 return WN_NO_NETWORK;
2594 }
2595
2596 /*********************************************************************
2597 * WNetGetLastErrorW [MPR.@]
2598 */
2599 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
2600 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
2601 LPWSTR lpNameBuf, DWORD nNameBufSize )
2602 {
2603 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2604 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
2605
2606 SetLastError(WN_NO_NETWORK);
2607 return WN_NO_NETWORK;
2608 }
2609
2610 /*********************************************************************
2611 * WNetGetNetworkInformationA [MPR.@]
2612 */
2613 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
2614 LPNETINFOSTRUCT lpNetInfoStruct )
2615 {
2616 DWORD ret;
2617
2618 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
2619
2620 if (!lpProvider)
2621 ret = WN_BAD_POINTER;
2622 else
2623 {
2624 int len;
2625
2626 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
2627 if (len)
2628 {
2629 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2630
2631 if (wideProvider)
2632 {
2633 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
2634 len);
2635 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
2636 HeapFree(GetProcessHeap(), 0, wideProvider);
2637 }
2638 else
2639 ret = WN_OUT_OF_MEMORY;
2640 }
2641 else
2642 ret = GetLastError();
2643 }
2644 if (ret)
2645 SetLastError(ret);
2646 TRACE("Returning %d\n", ret);
2647 return ret;
2648 }
2649
2650 /*********************************************************************
2651 * WNetGetNetworkInformationW [MPR.@]
2652 */
2653 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
2654 LPNETINFOSTRUCT lpNetInfoStruct )
2655 {
2656 DWORD ret;
2657
2658 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
2659
2660 if (!lpProvider)
2661 ret = WN_BAD_POINTER;
2662 else if (!lpNetInfoStruct)
2663 ret = WN_BAD_POINTER;
2664 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
2665 ret = WN_BAD_VALUE;
2666 else
2667 {
2668 if (providerTable && providerTable->numProviders)
2669 {
2670 DWORD providerIndex = _findProviderIndexW(lpProvider);
2671
2672 if (providerIndex != BAD_PROVIDER_INDEX)
2673 {
2674 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
2675 lpNetInfoStruct->dwProviderVersion =
2676 providerTable->table[providerIndex].dwSpecVersion;
2677 lpNetInfoStruct->dwStatus = NO_ERROR;
2678 lpNetInfoStruct->dwCharacteristics = 0;
2679 lpNetInfoStruct->dwHandle = 0;
2680 lpNetInfoStruct->wNetType =
2681 HIWORD(providerTable->table[providerIndex].dwNetType);
2682 lpNetInfoStruct->dwPrinters = -1;
2683 lpNetInfoStruct->dwDrives = -1;
2684 ret = WN_SUCCESS;
2685 }
2686 else
2687 ret = WN_BAD_PROVIDER;
2688 }
2689 else
2690 ret = WN_NO_NETWORK;
2691 }
2692 if (ret)
2693 SetLastError(ret);
2694 TRACE("Returning %d\n", ret);
2695 return ret;
2696 }
2697
2698 /*****************************************************************
2699 * WNetGetProviderNameA [MPR.@]
2700 */
2701 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
2702 LPSTR lpProvider, LPDWORD lpBufferSize )
2703 {
2704 DWORD ret;
2705
2706 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
2707 lpBufferSize);
2708
2709 if (!lpProvider)
2710 ret = WN_BAD_POINTER;
2711 else if (!lpBufferSize)
2712 ret = WN_BAD_POINTER;
2713 else
2714 {
2715 if (providerTable)
2716 {
2717 DWORD i;
2718
2719 ret = WN_NO_NETWORK;
2720 for (i = 0; i < providerTable->numProviders &&
2721 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2722 i++)
2723 ;
2724 if (i < providerTable->numProviders)
2725 {
2726 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
2727 providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
2728
2729 if (*lpBufferSize < sizeNeeded)
2730 {
2731 *lpBufferSize = sizeNeeded;
2732 ret = WN_MORE_DATA;
2733 }
2734 else
2735 {
2736 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
2737 -1, lpProvider, *lpBufferSize, NULL, NULL);
2738 ret = WN_SUCCESS;
2739 /* FIXME: is *lpBufferSize set to the number of characters
2740 * copied? */
2741 }
2742 }
2743 }
2744 else
2745 ret = WN_NO_NETWORK;
2746 }
2747 if (ret)
2748 SetLastError(ret);
2749 TRACE("Returning %d\n", ret);
2750 return ret;
2751 }
2752
2753 /*****************************************************************
2754 * WNetGetProviderNameW [MPR.@]
2755 */
2756 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
2757 LPWSTR lpProvider, LPDWORD lpBufferSize )
2758 {
2759 DWORD ret;
2760
2761 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
2762 lpBufferSize);
2763
2764 if (!lpProvider)
2765 ret = WN_BAD_POINTER;
2766 else if (!lpBufferSize)
2767 ret = WN_BAD_POINTER;
2768 else
2769 {
2770 if (providerTable)
2771 {
2772 DWORD i;
2773
2774 ret = WN_NO_NETWORK;
2775 for (i = 0; i < providerTable->numProviders &&
2776 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
2777 i++)
2778 ;
2779 if (i < providerTable->numProviders)
2780 {
2781 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
2782
2783 if (*lpBufferSize < sizeNeeded)
2784 {
2785 *lpBufferSize = sizeNeeded;
2786 ret = WN_MORE_DATA;
2787 }
2788 else
2789 {
2790 strcpyW(lpProvider, providerTable->table[i].name);
2791 ret = WN_SUCCESS;
2792 /* FIXME: is *lpBufferSize set to the number of characters
2793 * copied? */
2794 }
2795 }
2796 }
2797 else
2798 ret = WN_NO_NETWORK;
2799 }
2800 if (ret)
2801 SetLastError(ret);
2802 TRACE("Returning %d\n", ret);
2803 return ret;
2804 }