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