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