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