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