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