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