4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
7 * Copyright 2016-2018 Pierre Schweitzer
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.
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.
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
33 #define WINE_MOUNTMGR_EXTENSIONS
34 #include "ddk/mountmgr.h"
35 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(mpr
);
41 /* Data structures representing network service providers. Assumes only one
42 * thread creates them, and that they are constant for the life of the process
43 * (and therefore doesn't synchronize access).
44 * FIXME: only basic provider data and enumeration-related data are implemented
45 * so far, need to implement the rest too.
47 typedef struct _WNetProvider
55 PF_NPOpenEnum openEnum
;
56 PF_NPEnumResource enumResource
;
57 PF_NPCloseEnum closeEnum
;
58 PF_NPGetResourceInformation getResourceInformation
;
59 PF_NPAddConnection addConnection
;
60 PF_NPAddConnection3 addConnection3
;
61 PF_NPCancelConnection cancelConnection
;
62 } WNetProvider
, *PWNetProvider
;
64 typedef struct _WNetProviderTable
69 WNetProvider table
[1];
70 } WNetProviderTable
, *PWNetProviderTable
;
72 #define WNET_ENUMERATOR_TYPE_GLOBAL 0
73 #define WNET_ENUMERATOR_TYPE_PROVIDER 1
74 #define WNET_ENUMERATOR_TYPE_CONTEXT 2
75 #define WNET_ENUMERATOR_TYPE_CONNECTED 3
76 #define WNET_ENUMERATOR_TYPE_REMEMBERED 4
78 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
79 * the enumeration; it represents one of the following types:
80 * - a global enumeration, one that's executed across all providers
81 * - a provider-specific enumeration, one that's only executed by a single
83 * - a context enumeration. I know this contradicts what I just said about
84 * there being no correspondence between the scope and the type, but it's
85 * necessary for the special case that a "Entire Network" entry needs to
86 * be enumerated in an enumeration of the context scope. Thus an enumeration
87 * of the context scope results in a context type enumerator, which morphs
88 * into a global enumeration (so the enumeration continues across all
90 * - a remembered enumeration, not related to providers themselves, but it
91 * is a registry enumeration for saved connections
93 typedef struct _WNetEnumerator
112 } WNetEnumerator
, *PWNetEnumerator
;
114 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
116 /* Returns an index (into the global WNetProviderTable) of the provider with
117 * the given name, or BAD_PROVIDER_INDEX if not found.
119 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
121 static PWNetProviderTable providerTable
;
124 * Global provider table functions
127 static void _tryLoadProvider(PCWSTR provider
)
129 WCHAR serviceName
[MAX_PATH
];
132 TRACE("%s\n", debugstr_w(provider
));
133 swprintf(serviceName
, ARRAY_SIZE(serviceName
), L
"%s%s\\NetworkProvider",
134 L
"System\\CurrentControlSet\\Services\\", provider
);
135 serviceName
[ARRAY_SIZE(serviceName
) - 1] = '\0';
136 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
139 WCHAR providerPath
[MAX_PATH
];
140 DWORD type
, size
= sizeof(providerPath
);
142 if (RegQueryValueExW(hKey
, L
"ProviderPath", NULL
, &type
, (BYTE
*)providerPath
, &size
) == ERROR_SUCCESS
143 && (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
147 if (type
== REG_EXPAND_SZ
)
149 WCHAR path
[MAX_PATH
];
150 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
154 RegQueryValueExW(hKey
, L
"Name", NULL
, NULL
, NULL
, &size
);
157 name
= HeapAlloc(GetProcessHeap(), 0, size
);
158 if (RegQueryValueExW(hKey
, L
"Name", NULL
, &type
, (BYTE
*)name
, &size
) != ERROR_SUCCESS
161 HeapFree(GetProcessHeap(), 0, name
);
167 HMODULE hLib
= LoadLibraryW(providerPath
);
171 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
173 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
175 TRACE("loaded lib %p\n", hLib
);
179 PWNetProvider provider
=
180 &providerTable
->table
[providerTable
->numProviders
];
182 provider
->hLib
= hLib
;
183 provider
->name
= name
;
184 TRACE("name is %s\n", debugstr_w(name
));
185 provider
->getCaps
= getCaps
;
186 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
187 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
188 TRACE("net type is 0x%08lx\n", provider
->dwNetType
);
189 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
190 if (provider
->dwEnumScopes
)
192 TRACE("supports enumeration\n");
193 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
194 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
195 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
196 TRACE("NPEnumResource %p\n", provider
->enumResource
);
197 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
198 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
199 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
200 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
201 if (!provider
->openEnum
||
202 !provider
->enumResource
||
203 !provider
->closeEnum
)
205 provider
->openEnum
= NULL
;
206 provider
->enumResource
= NULL
;
207 provider
->closeEnum
= NULL
;
208 provider
->dwEnumScopes
= 0;
209 WARN("Couldn't load enumeration functions\n");
212 connectCap
= getCaps(WNNC_CONNECTION
);
213 if (connectCap
& WNNC_CON_ADDCONNECTION
)
214 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
215 if (connectCap
& WNNC_CON_ADDCONNECTION3
)
216 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
217 if (connectCap
& WNNC_CON_CANCELCONNECTION
)
218 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
219 TRACE("NPAddConnection %p\n", provider
->addConnection
);
220 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
221 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
222 providerTable
->numProviders
++;
226 WARN("Provider %s didn't export NPGetCaps\n",
227 debugstr_w(provider
));
228 HeapFree(GetProcessHeap(), 0, name
);
236 WARN("Couldn't load library %s for provider %s\n",
237 debugstr_w(providerPath
), debugstr_w(provider
));
238 HeapFree(GetProcessHeap(), 0, name
);
243 WARN("Couldn't get provider name for provider %s\n",
244 debugstr_w(provider
));
248 WARN("Couldn't open value ProviderPath\n");
252 WARN("Couldn't open service key for provider %s\n",
253 debugstr_w(provider
));
256 void wnetInit(HINSTANCE hInstDll
)
260 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, L
"System\\CurrentControlSet\\Control\\NetworkProvider\\Order",
261 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
265 RegQueryValueExW(hKey
, L
"ProviderOrder", NULL
, NULL
, NULL
, &size
);
268 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
274 if (RegQueryValueExW(hKey
, L
"ProviderOrder", NULL
, &type
, (BYTE
*)providers
, &size
)
275 == ERROR_SUCCESS
&& type
== REG_SZ
)
280 TRACE("provider order is %s\n", debugstr_w(providers
));
281 /* first count commas as a heuristic for how many to
282 * allocate space for */
283 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
285 ptr
= wcschr(ptr
, ',');
292 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
293 sizeof(WNetProviderTable
)
294 + (numToAllocate
- 1) * sizeof(WNetProvider
));
298 int entireNetworkLen
;
299 LPCWSTR stringresource
;
301 entireNetworkLen
= LoadStringW(hInstDll
,
302 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
303 providerTable
->entireNetwork
= HeapAlloc(
304 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
306 if (providerTable
->entireNetwork
)
308 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
309 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
311 providerTable
->numAllocated
= numToAllocate
;
312 for (ptr
= providers
; ptr
; )
315 ptr
= wcschr(ptr
, ',');
318 _tryLoadProvider(ptrPrev
);
322 HeapFree(GetProcessHeap(), 0, providers
);
335 for (i
= 0; i
< providerTable
->numProviders
; i
++)
337 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
338 FreeModule(providerTable
->table
[i
].hLib
);
340 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
341 HeapFree(GetProcessHeap(), 0, providerTable
);
342 providerTable
= NULL
;
346 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
348 DWORD ret
= BAD_PROVIDER_INDEX
;
350 if (providerTable
&& providerTable
->numProviders
)
354 for (i
= 0; i
< providerTable
->numProviders
&&
355 ret
== BAD_PROVIDER_INDEX
; i
++)
356 if (!lstrcmpW(lpProvider
, providerTable
->table
[i
].name
))
366 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
372 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
378 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
379 if (lpNet
->lpRemoteName
)
381 len
= lstrlenW(lpNet
->lpRemoteName
) + 1;
382 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
383 if (ret
->lpRemoteName
)
384 lstrcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
393 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
397 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
398 HeapFree(GetProcessHeap(), 0, lpNet
);
402 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
403 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
405 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
406 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
410 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
411 ret
->dwScope
= dwScope
;
412 ret
->dwType
= dwType
;
413 ret
->dwUsage
= dwUsage
;
414 ret
->specific
.net
= _copyNetResourceForEnumW(lpNet
);
419 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
420 DWORD dwUsage
, DWORD index
, HANDLE handle
)
424 if (!providerTable
|| index
>= providerTable
->numProviders
)
428 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
431 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
432 ret
->providerIndex
= index
;
433 ret
->dwScope
= dwScope
;
434 ret
->dwType
= dwType
;
435 ret
->dwUsage
= dwUsage
;
436 ret
->handle
= handle
;
442 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
445 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
446 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
450 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
451 ret
->dwScope
= dwScope
;
452 ret
->dwType
= dwType
;
453 ret
->dwUsage
= dwUsage
;
458 static PWNetEnumerator
_createConnectedEnumerator(DWORD dwScope
, DWORD dwType
,
461 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
464 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONNECTED
;
465 ret
->dwScope
= dwScope
;
466 ret
->dwType
= dwType
;
467 ret
->dwUsage
= dwUsage
;
468 ret
->specific
.handles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HANDLE
) * providerTable
->numProviders
);
469 if (!ret
->specific
.handles
)
471 HeapFree(GetProcessHeap(), 0, ret
);
478 static PWNetEnumerator
_createRememberedEnumerator(DWORD dwScope
, DWORD dwType
,
481 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
484 ret
->enumType
= WNET_ENUMERATOR_TYPE_REMEMBERED
;
485 ret
->dwScope
= dwScope
;
486 ret
->dwType
= dwType
;
487 ret
->specific
.remembered
.registry
= remembered
;
492 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
493 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
494 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
495 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
496 * if not all members of the array could be thunked, and something else on
499 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
500 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
502 DWORD i
, numToThunk
, totalBytes
, ret
;
506 return WN_BAD_POINTER
;
508 return WN_BAD_POINTER
;
512 return WN_BAD_POINTER
;
514 return WN_BAD_POINTER
;
516 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
518 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
520 totalBytes
+= sizeof(NETRESOURCEA
);
521 if (lpNet
->lpLocalName
)
522 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
523 -1, NULL
, 0, NULL
, NULL
);
524 if (lpNet
->lpRemoteName
)
525 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
526 -1, NULL
, 0, NULL
, NULL
);
527 if (lpNet
->lpComment
)
528 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
529 -1, NULL
, 0, NULL
, NULL
);
530 if (lpNet
->lpProvider
)
531 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
532 -1, NULL
, 0, NULL
, NULL
);
533 if (totalBytes
< *lpBufferSize
)
536 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
537 for (i
= 0; i
< numToThunk
; i
++)
539 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
540 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
542 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
543 /* lie about string lengths, we already verified how many
544 * we have space for above
546 if (lpNetIn
->lpLocalName
)
548 lpNetOut
->lpLocalName
= strNext
;
549 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
550 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
552 if (lpNetIn
->lpRemoteName
)
554 lpNetOut
->lpRemoteName
= strNext
;
555 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
556 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
558 if (lpNetIn
->lpComment
)
560 lpNetOut
->lpComment
= strNext
;
561 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
562 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
564 if (lpNetIn
->lpProvider
)
566 lpNetOut
->lpProvider
= strNext
;
567 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
568 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
571 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
572 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk
,
577 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
578 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
579 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
580 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
581 * if not all members of the array could be thunked, and something else on
584 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
585 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
587 DWORD i
, numToThunk
, totalBytes
, ret
;
591 return WN_BAD_POINTER
;
593 return WN_BAD_POINTER
;
597 return WN_BAD_POINTER
;
599 return WN_BAD_POINTER
;
601 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
603 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
605 totalBytes
+= sizeof(NETRESOURCEW
);
606 if (lpNet
->lpLocalName
)
607 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
608 -1, NULL
, 0) * sizeof(WCHAR
);
609 if (lpNet
->lpRemoteName
)
610 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
611 -1, NULL
, 0) * sizeof(WCHAR
);
612 if (lpNet
->lpComment
)
613 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
614 -1, NULL
, 0) * sizeof(WCHAR
);
615 if (lpNet
->lpProvider
)
616 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
617 -1, NULL
, 0) * sizeof(WCHAR
);
618 if (totalBytes
< *lpBufferSize
)
621 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
622 for (i
= 0; i
< numToThunk
; i
++)
624 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
625 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
627 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
628 /* lie about string lengths, we already verified how many
629 * we have space for above
631 if (lpNetIn
->lpLocalName
)
633 lpNetOut
->lpLocalName
= strNext
;
634 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
635 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
637 if (lpNetIn
->lpRemoteName
)
639 lpNetOut
->lpRemoteName
= strNext
;
640 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
641 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
643 if (lpNetIn
->lpComment
)
645 lpNetOut
->lpComment
= strNext
;
646 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
647 -1, lpNetOut
->lpComment
, *lpBufferSize
);
649 if (lpNetIn
->lpProvider
)
651 lpNetOut
->lpProvider
= strNext
;
652 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
653 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
656 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
657 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk
,
662 /*********************************************************************
663 * WNetOpenEnumA [MPR.@]
665 * See comments for WNetOpenEnumW.
667 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
668 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
672 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
673 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
676 ret
= WN_BAD_POINTER
;
677 else if (!providerTable
|| providerTable
->numProviders
== 0)
686 LPNETRESOURCEW lpNetWide
= NULL
;
688 DWORD size
= sizeof(buf
), count
= 1;
689 BOOL allocated
= FALSE
;
691 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
692 if (ret
== WN_MORE_DATA
)
694 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
698 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
703 ret
= WN_OUT_OF_MEMORY
;
705 else if (ret
== WN_SUCCESS
)
706 lpNetWide
= (LPNETRESOURCEW
)buf
;
707 if (ret
== WN_SUCCESS
)
708 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
711 HeapFree(GetProcessHeap(), 0, lpNetWide
);
714 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
718 TRACE("Returning %ld\n", ret
);
722 /*********************************************************************
723 * WNetOpenEnumW [MPR.@]
725 * Network enumeration has way too many parameters, so I'm not positive I got
726 * them right. What I've got so far:
728 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
729 * all the network providers should be enumerated.
731 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
732 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
733 * lpProvider is set, all the network providers should be enumerated.
734 * (This means the enumeration is a list of network providers, not that the
735 * enumeration is passed on to the providers.)
737 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
738 * resource matches the "Entire Network" resource (no remote name, no
739 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
740 * enumeration is done on every network provider.
742 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
743 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
744 * only to the given network provider.
746 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
747 * no lpProvider is set, enumeration will be tried on every network provider,
748 * in the order in which they're loaded.
750 * - The LPNETRESOURCE should be disregarded for scopes besides
751 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
752 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
754 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
755 * resource in the enumerated list, as well as any machines in your
756 * workgroup. The machines in your workgroup come from doing a
757 * RESOURCE_CONTEXT enumeration of every Network Provider.
759 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
760 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
764 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
765 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
768 ret
= WN_BAD_POINTER
;
769 else if (!providerTable
|| providerTable
->numProviders
== 0)
778 case RESOURCE_GLOBALNET
:
781 if (lpNet
->lpProvider
)
783 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
785 if (index
!= BAD_PROVIDER_INDEX
)
787 if (providerTable
->table
[index
].openEnum
&&
788 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
791 PWSTR RemoteName
= lpNet
->lpRemoteName
;
793 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
794 RemoteName
&& !lstrcmpW(RemoteName
, lpNet
->lpProvider
))
795 lpNet
->lpRemoteName
= NULL
;
797 ret
= providerTable
->table
[index
].openEnum(
798 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
799 if (ret
== WN_SUCCESS
)
801 *lphEnum
= _createProviderEnumerator(
802 dwScope
, dwType
, dwUsage
, index
, handle
);
803 ret
= *lphEnum
? WN_SUCCESS
:
807 lpNet
->lpRemoteName
= RemoteName
;
810 ret
= WN_NOT_SUPPORTED
;
813 ret
= WN_BAD_PROVIDER
;
815 else if (lpNet
->lpRemoteName
)
817 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
818 dwType
, dwUsage
, lpNet
);
819 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
823 if (lpNet
->lpComment
&& !lstrcmpW(lpNet
->lpComment
,
824 providerTable
->entireNetwork
))
826 /* comment matches the "Entire Network", enumerate
827 * global scope of every provider
829 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
830 dwType
, dwUsage
, lpNet
);
834 /* this is the same as not having passed lpNet */
835 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
836 dwType
, dwUsage
, NULL
);
838 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
843 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
845 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
848 case RESOURCE_CONTEXT
:
849 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
850 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
852 case RESOURCE_CONNECTED
:
853 *lphEnum
= _createConnectedEnumerator(dwScope
, dwType
, dwUsage
);
854 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
856 case RESOURCE_REMEMBERED
:
858 HKEY remembered
, user_profile
;
860 ret
= WN_OUT_OF_MEMORY
;
861 if (RegOpenCurrentUser(KEY_READ
, &user_profile
) == ERROR_SUCCESS
)
863 WCHAR subkey
[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
865 if (RegOpenKeyExW(user_profile
, subkey
, 0, KEY_READ
, &remembered
) == ERROR_SUCCESS
)
867 *lphEnum
= _createRememberedEnumerator(dwScope
, dwType
, remembered
);
868 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
871 RegCloseKey(user_profile
);
876 WARN("unknown scope 0x%08lx\n", dwScope
);
882 TRACE("Returning %ld\n", ret
);
886 /*********************************************************************
887 * WNetEnumResourceA [MPR.@]
889 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
890 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
894 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
897 ret
= WN_BAD_POINTER
;
899 ret
= WN_BAD_POINTER
;
901 ret
= WN_BAD_POINTER
;
902 else if (!lpBufferSize
)
903 ret
= WN_BAD_POINTER
;
904 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
906 *lpBufferSize
= sizeof(NETRESOURCEA
);
911 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
912 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
916 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
918 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
920 /* FIXME: this isn't necessarily going to work in the case of
921 * WN_MORE_DATA, because our enumerator may have moved on to
922 * the next provider. MSDN states that a large (16KB) buffer
923 * size is the appropriate usage of this function, so
924 * hopefully it won't be an issue.
926 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
927 lpBuffer
, lpBufferSize
);
928 *lpcCount
= localCount
;
930 HeapFree(GetProcessHeap(), 0, localBuffer
);
933 ret
= WN_OUT_OF_MEMORY
;
937 TRACE("Returning %ld\n", ret
);
941 static DWORD
_countProviderBytesW(PWNetProvider provider
)
947 ret
= sizeof(NETRESOURCEW
);
948 ret
+= 2 * (lstrlenW(provider
->name
) + 1) * sizeof(WCHAR
);
955 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
956 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
961 return WN_BAD_POINTER
;
962 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
965 return WN_BAD_POINTER
;
967 return WN_BAD_POINTER
;
969 return WN_BAD_POINTER
;
970 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
973 if (!providerTable
|| enumerator
->providerIndex
>=
974 providerTable
->numProviders
)
975 ret
= WN_NO_MORE_ENTRIES
;
978 DWORD bytes
= 0, count
= 0, countLimit
, i
;
979 LPNETRESOURCEW resource
;
982 countLimit
= *lpcCount
== -1 ?
983 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
984 while (count
< countLimit
&& bytes
< *lpBufferSize
)
986 DWORD bytesNext
= _countProviderBytesW(
987 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
989 if (bytes
+ bytesNext
< *lpBufferSize
)
995 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
996 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
998 resource
->dwScope
= RESOURCE_GLOBALNET
;
999 resource
->dwType
= RESOURCETYPE_ANY
;
1000 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
1001 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
1002 RESOURCEUSAGE_RESERVED
;
1003 resource
->lpLocalName
= NULL
;
1004 resource
->lpRemoteName
= strNext
;
1005 lstrcpyW(resource
->lpRemoteName
,
1006 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1007 strNext
+= lstrlenW(resource
->lpRemoteName
) + 1;
1008 resource
->lpComment
= NULL
;
1009 resource
->lpProvider
= strNext
;
1010 lstrcpyW(resource
->lpProvider
,
1011 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1012 strNext
+= lstrlenW(resource
->lpProvider
) + 1;
1014 enumerator
->providerIndex
+= count
;
1016 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
1018 TRACE("Returning %ld\n", ret
);
1022 /* Advances the enumerator (assumed to be a global enumerator) to the next
1023 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1024 * not open a handle with the next provider.
1025 * If the existing handle is NULL, may leave the enumerator unchanged, since
1026 * the current provider may support the desired scope.
1027 * If the existing handle is not NULL, closes it before moving on.
1028 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1029 * provider, and another error on failure.
1031 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
1034 return WN_BAD_POINTER
;
1035 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1036 return WN_BAD_VALUE
;
1037 if (!providerTable
|| enumerator
->providerIndex
>=
1038 providerTable
->numProviders
)
1039 return WN_NO_MORE_ENTRIES
;
1041 if (enumerator
->providerDone
)
1044 enumerator
->providerDone
= FALSE
;
1045 if (enumerator
->handle
)
1047 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1048 enumerator
->handle
);
1049 enumerator
->handle
= NULL
;
1050 enumerator
->providerIndex
++;
1052 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1053 dwEnum
= WNNC_ENUM_LOCAL
;
1054 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1055 dwEnum
= WNNC_ENUM_GLOBAL
;
1056 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1057 dwEnum
= WNNC_ENUM_CONTEXT
;
1058 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1059 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1060 & dwEnum
); enumerator
->providerIndex
++)
1063 return enumerator
->providerIndex
< providerTable
->numProviders
?
1064 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1067 /* "Passes through" call to the next provider that supports the enumeration
1069 * FIXME: if one call to a provider's enumerator succeeds while there's still
1070 * space in lpBuffer, I don't call to the next provider. The caller may not
1071 * expect that it should call EnumResourceW again with a return value of
1072 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1073 * may have to be moved around a bit, ick.
1075 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1076 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1081 return WN_BAD_POINTER
;
1082 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1083 return WN_BAD_VALUE
;
1085 return WN_BAD_POINTER
;
1087 return WN_BAD_POINTER
;
1089 return WN_BAD_POINTER
;
1090 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1091 return WN_MORE_DATA
;
1093 ret
= _globalEnumeratorAdvance(enumerator
);
1094 if (ret
== WN_SUCCESS
)
1096 ret
= providerTable
->table
[enumerator
->providerIndex
].
1097 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1098 enumerator
->dwUsage
, enumerator
->specific
.net
,
1099 &enumerator
->handle
);
1100 if (ret
== WN_SUCCESS
)
1102 ret
= providerTable
->table
[enumerator
->providerIndex
].
1103 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1105 if (ret
!= WN_MORE_DATA
)
1106 enumerator
->providerDone
= TRUE
;
1109 TRACE("Returning %ld\n", ret
);
1113 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1114 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1119 return WN_BAD_POINTER
;
1120 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1121 return WN_BAD_VALUE
;
1123 return WN_BAD_POINTER
;
1125 return WN_BAD_POINTER
;
1127 return WN_BAD_POINTER
;
1128 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1129 return WN_MORE_DATA
;
1131 return WN_NO_NETWORK
;
1133 switch (enumerator
->dwScope
)
1135 case RESOURCE_GLOBALNET
:
1136 if (enumerator
->specific
.net
)
1137 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1138 lpBuffer
, lpBufferSize
);
1140 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1143 case RESOURCE_CONTEXT
:
1144 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1148 WARN("unexpected scope 0x%08lx\n", enumerator
->dwScope
);
1149 ret
= WN_NO_MORE_ENTRIES
;
1151 TRACE("Returning %ld\n", ret
);
1155 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1156 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1159 return WN_BAD_POINTER
;
1160 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1161 return WN_BAD_VALUE
;
1162 if (!enumerator
->handle
)
1163 return WN_BAD_VALUE
;
1165 return WN_BAD_POINTER
;
1167 return WN_BAD_POINTER
;
1169 return WN_BAD_POINTER
;
1171 return WN_NO_NETWORK
;
1172 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1173 return WN_NO_MORE_ENTRIES
;
1174 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1175 return WN_BAD_VALUE
;
1176 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1177 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1180 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1181 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1184 size_t cchEntireNetworkLen
, bytesNeeded
;
1187 return WN_BAD_POINTER
;
1188 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1189 return WN_BAD_VALUE
;
1191 return WN_BAD_POINTER
;
1193 return WN_BAD_POINTER
;
1195 return WN_BAD_POINTER
;
1197 return WN_NO_NETWORK
;
1199 cchEntireNetworkLen
= lstrlenW(providerTable
->entireNetwork
) + 1;
1200 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1201 if (*lpBufferSize
< bytesNeeded
)
1203 *lpBufferSize
= bytesNeeded
;
1208 LPNETRESOURCEW lpNet
= lpBuffer
;
1210 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1211 lpNet
->dwType
= enumerator
->dwType
;
1212 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1213 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1214 lpNet
->lpLocalName
= NULL
;
1215 lpNet
->lpRemoteName
= NULL
;
1216 lpNet
->lpProvider
= NULL
;
1217 /* odd, but correct: put comment at end of buffer, so it won't get
1218 * overwritten by subsequent calls to a provider's enumResource
1220 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1221 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1222 lstrcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1225 if (ret
== WN_SUCCESS
)
1227 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1229 /* "Entire Network" entry enumerated--morph this into a global
1230 * enumerator. enumerator->lpNet continues to be NULL, since it has
1231 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1233 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1234 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1235 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1236 if (ret
== WN_SUCCESS
)
1238 /* reflect the fact that we already enumerated "Entire Network" */
1240 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1244 /* the provider enumeration failed, but we already succeeded in
1245 * enumerating "Entire Network"--leave type as global to allow a
1246 * retry, but indicate success with a count of one.
1250 *lpBufferSize
= bytesNeeded
;
1253 TRACE("Returning %ld\n", ret
);
1257 static DWORD
_copyStringToEnumW(const WCHAR
*source
, DWORD
* left
, void** end
)
1260 WCHAR
* local
= *end
;
1262 len
= lstrlenW(source
) + 1;
1263 len
*= sizeof(WCHAR
);
1265 return WN_MORE_DATA
;
1267 local
-= (len
/ sizeof(WCHAR
));
1268 memcpy(local
, source
, len
);
1275 static DWORD
_enumerateConnectedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1276 void* user_buffer
, DWORD
* user_size
)
1278 DWORD ret
, index
, count
, total_count
, size
, i
, left
;
1280 NETRESOURCEW
* curr
, * buffer
;
1284 return WN_BAD_POINTER
;
1285 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONNECTED
)
1286 return WN_BAD_VALUE
;
1287 if (!user_count
|| !user_buffer
|| !user_size
)
1288 return WN_BAD_POINTER
;
1290 return WN_NO_NETWORK
;
1292 handles
= enumerator
->specific
.handles
;
1295 buffer
= HeapAlloc(GetProcessHeap(), 0, *user_size
);
1297 return WN_NO_NETWORK
;
1300 end
= (char *)user_buffer
+ size
;
1301 count
= *user_count
;
1304 ret
= WN_NO_MORE_ENTRIES
;
1305 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1307 if (providerTable
->table
[index
].dwEnumScopes
)
1309 if (handles
[index
] == 0)
1311 ret
= providerTable
->table
[index
].openEnum(enumerator
->dwScope
,
1313 enumerator
->dwUsage
,
1314 NULL
, &handles
[index
]);
1315 if (ret
!= WN_SUCCESS
)
1319 ret
= providerTable
->table
[index
].enumResource(handles
[index
],
1322 total_count
+= count
;
1323 if (ret
== WN_MORE_DATA
)
1326 if (ret
== WN_SUCCESS
)
1328 for (i
= 0; i
< count
; ++i
)
1330 if (left
< sizeof(NETRESOURCEW
))
1336 memcpy(curr
, &buffer
[i
], sizeof(NETRESOURCEW
));
1337 left
-= sizeof(NETRESOURCEW
);
1339 ret
= _copyStringToEnumW(buffer
[i
].lpLocalName
, &left
, &end
);
1340 if (ret
== WN_MORE_DATA
)
1342 curr
->lpLocalName
= end
;
1344 ret
= _copyStringToEnumW(buffer
[i
].lpRemoteName
, &left
, &end
);
1345 if (ret
== WN_MORE_DATA
)
1347 curr
->lpRemoteName
= end
;
1349 ret
= _copyStringToEnumW(buffer
[i
].lpProvider
, &left
, &end
);
1350 if (ret
== WN_MORE_DATA
)
1352 curr
->lpProvider
= end
;
1360 if (*user_count
!= -1)
1361 count
= *user_count
- total_count
;
1363 count
= *user_count
;
1367 if (total_count
== 0)
1368 ret
= WN_NO_MORE_ENTRIES
;
1370 *user_count
= total_count
;
1371 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1374 HeapFree(GetProcessHeap(), 0, buffer
);
1376 TRACE("Returning %ld\n", ret
);
1380 static WCHAR
*get_reg_str(HKEY hkey
, const WCHAR
*value
, DWORD
*len
)
1385 if (!RegQueryValueExW(hkey
, value
, NULL
, &type
, NULL
, len
) && type
== REG_SZ
)
1387 if (!(ret
= HeapAlloc(GetProcessHeap(), 0, *len
))) return NULL
;
1388 RegQueryValueExW(hkey
, value
, 0, 0, (BYTE
*)ret
, len
);
1394 static DWORD
_enumeratorRememberedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1395 void* user_buffer
, DWORD
* user_size
)
1397 HKEY registry
, connection
;
1400 DWORD index
, ret
, type
, len
, size
, registry_size
, full_size
= 0, total_count
;
1401 NETRESOURCEW
* net_buffer
= user_buffer
;
1402 WCHAR
* str
, * registry_string
;
1404 /* we will do the work in a single loop, so here is some things:
1405 * we write netresource at the begin of the user buffer
1406 * we write strings at the end of the user buffer
1408 size_left
= *user_size
;
1410 type
= enumerator
->dwType
;
1411 registry
= enumerator
->specific
.remembered
.registry
;
1412 str
= (WCHAR
*)((ULONG_PTR
)user_buffer
+ *user_size
- sizeof(WCHAR
));
1413 for (index
= enumerator
->specific
.remembered
.index
; ; ++index
)
1415 enumerator
->specific
.remembered
.index
= index
;
1417 if (*user_count
!= -1 && total_count
== *user_count
)
1423 len
= ARRAY_SIZE(buffer
);
1424 ret
= RegEnumKeyExW(registry
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
);
1425 if (ret
!= ERROR_SUCCESS
)
1427 if (ret
== ERROR_NO_MORE_ITEMS
) ret
= WN_SUCCESS
;
1431 if (RegOpenKeyExW(registry
, buffer
, 0, KEY_READ
, &connection
) != ERROR_SUCCESS
)
1436 full_size
= sizeof(NETRESOURCEW
);
1437 size_left
-= sizeof(NETRESOURCEW
);
1441 size
= sizeof(DWORD
);
1442 RegQueryValueExW(connection
, L
"ConnectionType", NULL
, NULL
, (BYTE
*)&net_buffer
->dwType
, &size
);
1443 if (type
!= RESOURCETYPE_ANY
&& net_buffer
->dwType
!= type
)
1445 size_left
+= sizeof(NETRESOURCEW
);
1446 RegCloseKey(connection
);
1450 net_buffer
->dwScope
= RESOURCE_REMEMBERED
;
1451 net_buffer
->dwDisplayType
= RESOURCEDISPLAYTYPE_GENERIC
;
1452 net_buffer
->dwUsage
= RESOURCEUSAGE_CONNECTABLE
;
1457 /* FIXME: this only supports drive letters */
1458 full_size
+= 3 * sizeof(WCHAR
);
1459 size_left
-= 3 * sizeof(WCHAR
);
1466 net_buffer
->lpLocalName
= str
;
1470 registry_string
= get_reg_str(connection
, L
"ProviderName", ®istry_size
);
1471 if (registry_string
)
1473 full_size
+= registry_size
;
1474 size_left
-= registry_size
;
1478 str
-= (registry_size
/ sizeof(WCHAR
));
1479 lstrcpyW(str
, registry_string
);
1480 net_buffer
->lpProvider
= str
;
1485 HeapFree(GetProcessHeap(), 0, registry_string
);
1489 registry_string
= get_reg_str(connection
, L
"RemotePath", ®istry_size
);
1490 if (registry_string
)
1492 full_size
+= registry_size
;
1493 size_left
-= registry_size
;
1497 str
-= (registry_size
/ sizeof(WCHAR
));
1498 lstrcpyW(str
, registry_string
);
1499 net_buffer
->lpRemoteName
= str
;
1504 HeapFree(GetProcessHeap(), 0, registry_string
);
1507 RegCloseKey(connection
);
1509 net_buffer
->lpComment
= NULL
;
1518 if (total_count
== 0)
1519 ret
= WN_NO_MORE_ENTRIES
;
1521 *user_count
= total_count
;
1523 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1526 if (ret
== WN_MORE_DATA
)
1527 *user_size
= *user_size
+ full_size
;
1532 /*********************************************************************
1533 * WNetEnumResourceW [MPR.@]
1535 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1536 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1540 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1543 ret
= WN_BAD_POINTER
;
1545 ret
= WN_BAD_POINTER
;
1547 ret
= WN_BAD_POINTER
;
1548 else if (!lpBufferSize
)
1549 ret
= WN_BAD_POINTER
;
1550 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1552 *lpBufferSize
= sizeof(NETRESOURCEW
);
1557 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1559 switch (enumerator
->enumType
)
1561 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1562 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1565 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1566 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1569 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1570 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1573 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1574 ret
= _enumerateConnectedW(enumerator
, lpcCount
, lpBuffer
,
1577 case WNET_ENUMERATOR_TYPE_REMEMBERED
:
1578 ret
= _enumeratorRememberedW(enumerator
, lpcCount
, lpBuffer
,
1582 WARN("bogus enumerator type!\n");
1583 ret
= WN_NO_NETWORK
;
1588 TRACE("Returning %ld\n", ret
);
1592 /*********************************************************************
1593 * WNetCloseEnum [MPR.@]
1595 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1600 TRACE( "(%p)\n", hEnum
);
1604 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1606 switch (enumerator
->enumType
)
1608 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1609 if (enumerator
->specific
.net
)
1610 _freeEnumNetResource(enumerator
->specific
.net
);
1611 if (enumerator
->handle
)
1612 providerTable
->table
[enumerator
->providerIndex
].
1613 closeEnum(enumerator
->handle
);
1616 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1617 if (enumerator
->handle
)
1618 providerTable
->table
[enumerator
->providerIndex
].
1619 closeEnum(enumerator
->handle
);
1622 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1623 handles
= enumerator
->specific
.handles
;
1624 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1626 if (providerTable
->table
[index
].dwEnumScopes
&& handles
[index
])
1627 providerTable
->table
[index
].closeEnum(handles
[index
]);
1629 HeapFree(GetProcessHeap(), 0, handles
);
1632 case WNET_ENUMERATOR_TYPE_REMEMBERED
:
1633 RegCloseKey(enumerator
->specific
.remembered
.registry
);
1637 WARN("bogus enumerator type!\n");
1638 ret
= WN_BAD_HANDLE
;
1640 HeapFree(GetProcessHeap(), 0, hEnum
);
1643 ret
= WN_BAD_HANDLE
;
1646 TRACE("Returning %ld\n", ret
);
1650 /*********************************************************************
1651 * WNetGetResourceInformationA [MPR.@]
1653 * See WNetGetResourceInformationW
1655 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1656 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1661 TRACE( "(%p, %p, %p, %p)\n",
1662 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1664 if (!providerTable
|| providerTable
->numProviders
== 0)
1665 ret
= WN_NO_NETWORK
;
1666 else if (lpNetResource
)
1668 LPNETRESOURCEW lpNetResourceW
= NULL
;
1669 DWORD size
= 1024, count
= 1;
1672 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1673 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1674 if (ret
== WN_MORE_DATA
)
1676 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1677 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1679 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1680 &count
, lpNetResourceW
, &size
);
1682 ret
= WN_OUT_OF_MEMORY
;
1684 if (ret
== WN_SUCCESS
)
1686 LPWSTR lpSystemW
= NULL
;
1689 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1692 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1693 lpBufferW
, &size
, &lpSystemW
);
1694 if (ret
== WN_MORE_DATA
)
1696 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1697 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1699 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1700 lpBufferW
, &size
, &lpSystemW
);
1702 ret
= WN_OUT_OF_MEMORY
;
1704 if (ret
== WN_SUCCESS
)
1706 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1707 &count
, lpBuffer
, cbBuffer
);
1708 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1709 lpNetResourceW
= lpBufferW
;
1710 size
= sizeof(NETRESOURCEA
);
1711 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1712 -1, NULL
, 0, NULL
, NULL
);
1713 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1714 -1, NULL
, 0, NULL
, NULL
);
1716 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1717 -1, NULL
, 0, NULL
, NULL
);
1718 if ((len
) && ( size
+ len
< *cbBuffer
))
1720 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1721 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1722 *lplpSystem
, len
, NULL
, NULL
);
1729 ret
= WN_OUT_OF_MEMORY
;
1730 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1733 ret
= WN_OUT_OF_MEMORY
;
1734 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1736 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1739 ret
= WN_NO_NETWORK
;
1743 TRACE("Returning %ld\n", ret
);
1747 /*********************************************************************
1748 * WNetGetResourceInformationW [MPR.@]
1750 * WNetGetResourceInformationW function identifies the network provider
1751 * that owns the resource and gets information about the type of the resource.
1754 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1755 * defines a network resource.
1756 * lpBuffer [ O] the pointer to buffer, containing result. It
1757 * contains NETRESOURCEW structure and strings to
1758 * which the members of the NETRESOURCEW structure
1760 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1762 * lplpSystem [ O] the pointer to string in the output buffer,
1763 * containing the part of the resource name without
1764 * names of the server and share.
1767 * NO_ERROR if the function succeeds. System error code if the function fails.
1770 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1771 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1772 LPWSTR
*lplpSystem
)
1774 DWORD ret
= WN_NO_NETWORK
;
1777 TRACE( "(%p, %p, %p, %p)\n",
1778 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1781 ret
= WN_OUT_OF_MEMORY
;
1782 else if (providerTable
!= NULL
)
1784 /* FIXME: For function value of a variable is indifferent, it does
1785 * search of all providers in a network.
1787 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1789 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1790 WNNC_DLG_GETRESOURCEINFORMATION
)
1792 if (providerTable
->table
[index
].getResourceInformation
)
1793 ret
= providerTable
->table
[index
].getResourceInformation(
1794 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1796 ret
= WN_NO_NETWORK
;
1797 if (ret
== WN_SUCCESS
)
1807 /*********************************************************************
1808 * WNetGetResourceParentA [MPR.@]
1810 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1811 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1813 FIXME( "(%p, %p, %p): stub\n",
1814 lpNetResource
, lpBuffer
, lpBufferSize
);
1816 SetLastError(WN_NO_NETWORK
);
1817 return WN_NO_NETWORK
;
1820 /*********************************************************************
1821 * WNetGetResourceParentW [MPR.@]
1823 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1824 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1826 FIXME( "(%p, %p, %p): stub\n",
1827 lpNetResource
, lpBuffer
, lpBufferSize
);
1829 SetLastError(WN_NO_NETWORK
);
1830 return WN_NO_NETWORK
;
1836 * Connection Functions
1839 /*********************************************************************
1840 * WNetAddConnectionA [MPR.@]
1842 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1843 LPCSTR lpLocalName
)
1845 NETRESOURCEA resourcesA
;
1847 memset(&resourcesA
, 0, sizeof(resourcesA
));
1848 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
1849 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
1850 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1853 /*********************************************************************
1854 * WNetAddConnectionW [MPR.@]
1856 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1857 LPCWSTR lpLocalName
)
1859 NETRESOURCEW resourcesW
;
1861 memset(&resourcesW
, 0, sizeof(resourcesW
));
1862 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
1863 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
1864 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1867 /*********************************************************************
1868 * WNetAddConnection2A [MPR.@]
1870 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1871 LPCSTR lpPassword
, LPCSTR lpUserID
,
1874 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1878 /*********************************************************************
1879 * WNetAddConnection2W [MPR.@]
1881 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1882 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1885 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1889 /*********************************************************************
1890 * WNetAddConnection3A [MPR.@]
1892 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1893 LPCSTR lpPassword
, LPCSTR lpUserID
,
1896 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1897 dwFlags
, NULL
, 0, NULL
);
1900 /*********************************************************************
1901 * WNetAddConnection3W [MPR.@]
1903 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1904 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1907 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1908 dwFlags
, NULL
, 0, NULL
);
1911 struct use_connection_context
1914 NETRESOURCEW
*resource
;
1915 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
1922 DWORD (*pre_set_accessname
)(struct use_connection_context
*, WCHAR
*);
1923 void (*set_accessname
)(struct use_connection_context
*, WCHAR
*);
1926 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1928 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1933 len
= lstrlenW(local_name
);
1935 len
= lstrlenW(ctxt
->resource
->lpRemoteName
);
1937 if (++len
> *ctxt
->buffer_size
)
1939 *ctxt
->buffer_size
= len
;
1940 return ERROR_MORE_DATA
;
1944 ctxt
->accessname
= NULL
;
1946 return ERROR_SUCCESS
;
1949 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1951 WCHAR
*accessname
= ctxt
->accessname
;
1954 lstrcpyW(accessname
, local_name
);
1956 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1959 lstrcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
1962 static DWORD
wnet_use_provider( struct use_connection_context
*ctxt
, NETRESOURCEW
* netres
, WNetProvider
*provider
, BOOLEAN redirect
)
1966 caps
= provider
->getCaps(WNNC_CONNECTION
);
1967 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
1968 return ERROR_BAD_PROVIDER
;
1970 ret
= WN_ACCESS_DENIED
;
1973 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
1974 ret
= provider
->addConnection3(ctxt
->hwndOwner
, netres
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
1975 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
1976 ret
= provider
->addConnection(netres
, ctxt
->password
, ctxt
->userid
);
1978 if (ret
== WN_ALREADY_CONNECTED
&& redirect
)
1979 netres
->lpLocalName
[0] -= 1;
1980 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& netres
->lpLocalName
[0] >= 'C');
1982 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
1983 ctxt
->set_accessname(ctxt
, netres
->lpLocalName
);
1988 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
1990 WNetProvider
*provider
= NULL
;
1991 DWORD index
, ret
= WN_NO_NETWORK
;
1992 BOOL redirect
= FALSE
;
1993 WCHAR letter
[3] = {'Z', ':', 0};
1994 NETRESOURCEW netres
;
1996 if (!providerTable
|| providerTable
->numProviders
== 0)
1997 return WN_NO_NETWORK
;
1999 if (!ctxt
->resource
)
2000 return ERROR_INVALID_PARAMETER
;
2001 netres
= *ctxt
->resource
;
2003 if (!netres
.lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
2005 if (netres
.dwType
!= RESOURCETYPE_DISK
&& netres
.dwType
!= RESOURCETYPE_PRINT
)
2006 return ERROR_BAD_DEV_TYPE
;
2008 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2010 FIXME("Local device selection is not implemented for printers.\n");
2011 return WN_NO_NETWORK
;
2015 netres
.lpLocalName
= letter
;
2018 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
2019 return ERROR_BAD_NET_NAME
;
2021 if ((ret
= ctxt
->pre_set_accessname(ctxt
, netres
.lpLocalName
)))
2024 if (netres
.lpProvider
)
2026 index
= _findProviderIndexW(netres
.lpProvider
);
2027 if (index
== BAD_PROVIDER_INDEX
)
2028 return ERROR_BAD_PROVIDER
;
2030 provider
= &providerTable
->table
[index
];
2031 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2035 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2037 provider
= &providerTable
->table
[index
];
2038 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2039 if (ret
== WN_SUCCESS
|| ret
== WN_ALREADY_CONNECTED
)
2044 if (ret
== WN_SUCCESS
&& ctxt
->flags
& CONNECT_UPDATE_PROFILE
)
2048 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2050 FIXME("Persistent connection are not supported for printers\n");
2054 if (RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2057 WCHAR subkey
[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres
.lpLocalName
[0], 0};
2059 if (RegCreateKeyExW(user_profile
, subkey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2060 KEY_ALL_ACCESS
, NULL
, &network
, NULL
) == ERROR_SUCCESS
)
2062 DWORD dword_arg
= RESOURCETYPE_DISK
;
2063 DWORD len
= (lstrlenW(provider
->name
) + 1) * sizeof(WCHAR
);
2065 RegSetValueExW(network
, L
"ConnectionType", 0, REG_DWORD
, (const BYTE
*)&dword_arg
,
2067 RegSetValueExW(network
, L
"ProviderName", 0, REG_SZ
, (const BYTE
*)provider
->name
, len
);
2068 RegSetValueExW(network
, L
"ProviderType", 0, REG_DWORD
,
2069 (const BYTE
*)&provider
->dwNetType
, sizeof(DWORD
));
2070 len
= (lstrlenW(netres
.lpRemoteName
) + 1) * sizeof(WCHAR
);
2071 RegSetValueExW(network
, L
"RemotePath", 0, REG_SZ
, (const BYTE
*)netres
.lpRemoteName
, len
);
2073 RegSetValueExW(network
, L
"UserName", 0, REG_SZ
, (const BYTE
*) L
"", len
);
2074 RegCloseKey(network
);
2077 RegCloseKey(user_profile
);
2084 /*****************************************************************
2085 * WNetUseConnectionW [MPR.@]
2087 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
2088 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
2090 struct use_connection_context ctxt
;
2092 TRACE( "(%p, %p, %p, %s, 0x%08lX, %p, %p, %p)\n",
2093 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
2094 accessname
, buffer_size
, result
);
2096 ctxt
.hwndOwner
= hwndOwner
;
2097 ctxt
.resource
= resource
;
2098 ctxt
.resourceA
= NULL
;
2099 ctxt
.password
= (WCHAR
*)password
;
2100 ctxt
.userid
= (WCHAR
*)userid
;
2102 ctxt
.accessname
= accessname
;
2103 ctxt
.buffer_size
= buffer_size
;
2104 ctxt
.result
= result
;
2105 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
2106 ctxt
.set_accessname
= use_connection_set_accessnameW
;
2108 return wnet_use_connection(&ctxt
);
2111 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2113 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
2118 len
= WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, NULL
, 0, NULL
, NULL
) - 1;
2120 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
2122 if (++len
> *ctxt
->buffer_size
)
2124 *ctxt
->buffer_size
= len
;
2125 return ERROR_MORE_DATA
;
2129 ctxt
->accessname
= NULL
;
2131 return ERROR_SUCCESS
;
2134 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2136 char *accessname
= ctxt
->accessname
;
2139 WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, accessname
, *ctxt
->buffer_size
, NULL
, NULL
);
2141 *ctxt
->result
= CONNECT_LOCALDRIVE
;
2144 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
2147 static LPWSTR
strdupAtoW( LPCSTR str
)
2152 if (!str
) return NULL
;
2153 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
2154 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2155 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
2159 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
2161 resourceW
->dwScope
= resourceA
->dwScope
;
2162 resourceW
->dwType
= resourceA
->dwType
;
2163 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
2164 resourceW
->dwUsage
= resourceA
->dwUsage
;
2165 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
2166 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
2167 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
2168 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
2171 static void free_netresourceW( NETRESOURCEW
*resource
)
2173 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
2174 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
2175 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
2176 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
2179 /*****************************************************************
2180 * WNetUseConnectionA [MPR.@]
2182 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
2183 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
2184 DWORD
*buffer_size
, DWORD
*result
)
2186 struct use_connection_context ctxt
;
2187 NETRESOURCEW resourceW
;
2190 TRACE( "(%p, %p, %p, %s, 0x%08lX, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
2191 accessname
, buffer_size
, result
);
2193 netresource_a_to_w(resource
, &resourceW
);
2195 ctxt
.hwndOwner
= hwndOwner
;
2196 ctxt
.resource
= &resourceW
;
2197 ctxt
.resourceA
= resource
;
2198 ctxt
.password
= strdupAtoW(password
);
2199 ctxt
.userid
= strdupAtoW(userid
);
2201 ctxt
.accessname
= accessname
;
2202 ctxt
.buffer_size
= buffer_size
;
2203 ctxt
.result
= result
;
2204 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
2205 ctxt
.set_accessname
= use_connection_set_accessnameA
;
2207 ret
= wnet_use_connection(&ctxt
);
2209 free_netresourceW(&resourceW
);
2210 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
2211 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
2216 /*********************************************************************
2217 * WNetCancelConnectionA [MPR.@]
2219 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
2221 return WNetCancelConnection2A(lpName
, 0, fForce
);
2224 /*********************************************************************
2225 * WNetCancelConnectionW [MPR.@]
2227 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
2229 return WNetCancelConnection2W(lpName
, 0, fForce
);
2232 /*********************************************************************
2233 * WNetCancelConnection2A [MPR.@]
2235 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2238 WCHAR
* name
= strdupAtoW(lpName
);
2240 return ERROR_NOT_CONNECTED
;
2242 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
2243 HeapFree(GetProcessHeap(), 0, name
);
2248 /*********************************************************************
2249 * WNetCancelConnection2W [MPR.@]
2251 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2253 DWORD ret
= WN_NO_NETWORK
;
2256 if (providerTable
!= NULL
)
2258 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2260 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2261 WNNC_CON_CANCELCONNECTION
)
2263 if (providerTable
->table
[index
].cancelConnection
)
2264 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
2266 ret
= WN_NO_NETWORK
;
2267 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
2273 if (ret
== WN_SUCCESS
&& dwFlags
& CONNECT_UPDATE_PROFILE
)
2277 /* FIXME: Only remove it if that's a drive letter */
2278 if (iswalpha(lpName
[0]) && lpName
[1] == ':' &&
2279 RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2281 WCHAR subkey
[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', lpName
[0], 0};
2283 RegDeleteKeyW(user_profile
, subkey
);
2285 RegCloseKey(user_profile
);
2292 /*****************************************************************
2293 * WNetRestoreConnectionA [MPR.@]
2295 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
2297 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
2299 SetLastError(WN_NO_NETWORK
);
2300 return WN_NO_NETWORK
;
2303 /*****************************************************************
2304 * WNetRestoreConnectionW [MPR.@]
2306 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
2308 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
2310 SetLastError(WN_NO_NETWORK
);
2311 return WN_NO_NETWORK
;
2314 /**************************************************************************
2315 * WNetGetConnectionA [MPR.@]
2318 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2319 * - WN_NOT_CONNECTED drive is a local drive
2320 * - WN_MORE_DATA buffer isn't big enough
2321 * - WN_SUCCESS success (net path in buffer)
2323 * FIXME: need to test return values under different errors
2325 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
2326 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
2331 ret
= WN_BAD_POINTER
;
2332 else if (!lpBufferSize
)
2333 ret
= WN_BAD_POINTER
;
2334 else if (!lpRemoteName
&& *lpBufferSize
)
2335 ret
= WN_BAD_POINTER
;
2338 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
2342 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2346 WCHAR wideRemoteStatic
[MAX_PATH
];
2347 DWORD wideRemoteSize
= ARRAY_SIZE(wideRemoteStatic
);
2349 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
2351 /* try once without memory allocation */
2352 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
2354 if (ret
== WN_SUCCESS
)
2356 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2357 -1, NULL
, 0, NULL
, NULL
);
2359 if (len
<= *lpBufferSize
)
2361 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
2362 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2367 *lpBufferSize
= len
;
2371 else if (ret
== WN_MORE_DATA
)
2373 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2374 wideRemoteSize
* sizeof(WCHAR
));
2378 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2380 if (ret
== WN_SUCCESS
)
2382 if (len
<= *lpBufferSize
)
2384 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2385 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2390 *lpBufferSize
= len
;
2394 HeapFree(GetProcessHeap(), 0, wideRemote
);
2397 ret
= WN_OUT_OF_MEMORY
;
2399 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2402 ret
= WN_OUT_OF_MEMORY
;
2405 ret
= WN_BAD_LOCALNAME
;
2409 TRACE("Returning %ld\n", ret
);
2413 /* find the network connection for a given drive; helper for WNetGetConnection */
2414 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2417 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2419 DWORD ret
= WN_NOT_CONNECTED
;
2420 DWORD bytes_returned
;
2422 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2423 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2424 0, 0 )) == INVALID_HANDLE_VALUE
)
2426 ERR( "failed to open mount manager err %lu\n", GetLastError() );
2429 memset( data
, 0, sizeof(*data
) );
2430 data
->letter
= letter
;
2431 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2432 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2434 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2437 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2440 mount_point
[0] = '\\';
2441 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2443 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2451 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2460 /**************************************************************************
2461 * WNetGetConnectionW [MPR.@]
2463 * FIXME: need to test return values under different errors
2465 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2466 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2470 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2474 ret
= WN_BAD_POINTER
;
2475 else if (!lpBufferSize
)
2476 ret
= WN_BAD_POINTER
;
2477 else if (!lpRemoteName
&& *lpBufferSize
)
2478 ret
= WN_BAD_POINTER
;
2479 else if (!lpLocalName
[0])
2480 ret
= WN_BAD_LOCALNAME
;
2483 if (lpLocalName
[1] == ':')
2485 switch(GetDriveTypeW(lpLocalName
))
2488 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2490 case DRIVE_REMOVABLE
:
2493 TRACE("file is local\n");
2494 ret
= WN_NOT_CONNECTED
;
2497 ret
= WN_BAD_LOCALNAME
;
2501 ret
= WN_BAD_LOCALNAME
;
2505 TRACE("Returning %ld\n", ret
);
2509 /**************************************************************************
2510 * WNetSetConnectionA [MPR.@]
2512 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2515 FIXME( "(%s, %08lX, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2517 SetLastError(WN_NO_NETWORK
);
2518 return WN_NO_NETWORK
;
2521 /**************************************************************************
2522 * WNetSetConnectionW [MPR.@]
2524 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2527 FIXME( "(%s, %08lX, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2529 SetLastError(WN_NO_NETWORK
);
2530 return WN_NO_NETWORK
;
2533 /*****************************************************************
2534 * WNetGetUniversalNameA [MPR.@]
2536 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2537 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2541 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
2542 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2544 switch (dwInfoLevel
)
2546 case UNIVERSAL_NAME_INFO_LEVEL
:
2548 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2550 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2552 err
= ERROR_NOT_CONNECTED
;
2556 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2557 if (*lpBufferSize
< size
)
2562 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2563 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2567 case REMOTE_NAME_INFO_LEVEL
:
2568 err
= WN_NOT_CONNECTED
;
2580 /*****************************************************************
2581 * WNetGetUniversalNameW [MPR.@]
2583 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2584 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2588 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
2589 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2591 switch (dwInfoLevel
)
2593 case UNIVERSAL_NAME_INFO_LEVEL
:
2595 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2597 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2599 err
= ERROR_NOT_CONNECTED
;
2603 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2604 if (*lpBufferSize
< size
)
2606 *lpBufferSize
= size
;
2610 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2611 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2615 case REMOTE_NAME_INFO_LEVEL
:
2616 err
= WN_NO_NETWORK
;
2624 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2628 /*****************************************************************
2629 * WNetClearConnections [MPR.@]
2631 DWORD WINAPI
WNetClearConnections ( HWND owner
)
2635 DWORD ret
, size
, count
;
2636 NETRESOURCEW
* resources
, * iter
;
2638 ret
= WNetOpenEnumW(RESOURCE_CONNECTED
, RESOURCETYPE_ANY
, 0, NULL
, &connected
);
2639 if (ret
!= WN_SUCCESS
)
2641 if (ret
!= WN_NO_NETWORK
)
2646 /* Means no provider, then, clearing is OK */
2651 resources
= HeapAlloc(GetProcessHeap(), 0, size
);
2654 WNetCloseEnum(connected
);
2655 return WN_OUT_OF_MEMORY
;
2663 memset(resources
, 0, size
);
2664 ret
= WNetEnumResourceW(connected
, &count
, resources
, &size
);
2665 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2667 for (iter
= resources
; count
; count
--, iter
++)
2669 if (iter
->lpLocalName
&& iter
->lpLocalName
[0])
2670 connection
= iter
->lpLocalName
;
2672 connection
= iter
->lpRemoteName
;
2674 WNetCancelConnection2W(connection
, 0, TRUE
);
2681 HeapFree(GetProcessHeap(), 0, resources
);
2682 WNetCloseEnum(connected
);
2692 /**************************************************************************
2693 * WNetGetUserA [MPR.@]
2695 * FIXME: we should not return ourselves, but the owner of the drive lpName
2697 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2699 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2700 return GetLastError();
2703 /*****************************************************************
2704 * WNetGetUserW [MPR.@]
2706 * FIXME: we should not return ourselves, but the owner of the drive lpName
2708 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2710 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2711 return GetLastError();
2714 /*********************************************************************
2715 * WNetConnectionDialog [MPR.@]
2717 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2719 CONNECTDLGSTRUCTW conn_dlg
;
2720 NETRESOURCEW net_res
;
2722 ZeroMemory(&conn_dlg
, sizeof(conn_dlg
));
2723 ZeroMemory(&net_res
, sizeof(net_res
));
2725 conn_dlg
.cbStructure
= sizeof(conn_dlg
);
2726 conn_dlg
.lpConnRes
= &net_res
;
2727 conn_dlg
.hwndOwner
= hwnd
;
2728 net_res
.dwType
= dwType
;
2730 return WNetConnectionDialog1W(&conn_dlg
);
2733 /*********************************************************************
2734 * WNetConnectionDialog1A [MPR.@]
2736 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2738 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2740 SetLastError(WN_NO_NETWORK
);
2741 return WN_NO_NETWORK
;
2744 /*********************************************************************
2745 * WNetConnectionDialog1W [MPR.@]
2747 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2749 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2751 SetLastError(WN_NO_NETWORK
);
2752 return WN_NO_NETWORK
;
2755 /*********************************************************************
2756 * WNetDisconnectDialog [MPR.@]
2758 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2760 FIXME( "(%p, %08lX): stub\n", hwnd
, dwType
);
2762 SetLastError(WN_NO_NETWORK
);
2763 return WN_NO_NETWORK
;
2766 /*********************************************************************
2767 * WNetDisconnectDialog1A [MPR.@]
2769 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2771 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2773 SetLastError(WN_NO_NETWORK
);
2774 return WN_NO_NETWORK
;
2777 /*********************************************************************
2778 * WNetDisconnectDialog1W [MPR.@]
2780 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2782 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2784 SetLastError(WN_NO_NETWORK
);
2785 return WN_NO_NETWORK
;
2788 /*********************************************************************
2789 * WNetGetLastErrorA [MPR.@]
2791 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2792 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2793 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2795 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
2796 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2798 SetLastError(WN_NO_NETWORK
);
2799 return WN_NO_NETWORK
;
2802 /*********************************************************************
2803 * WNetGetLastErrorW [MPR.@]
2805 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2806 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2807 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2809 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
2810 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2812 SetLastError(WN_NO_NETWORK
);
2813 return WN_NO_NETWORK
;
2816 /*********************************************************************
2817 * WNetGetNetworkInformationA [MPR.@]
2819 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2820 LPNETINFOSTRUCT lpNetInfoStruct
)
2824 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2827 ret
= WN_BAD_POINTER
;
2832 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2835 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2839 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2841 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2842 HeapFree(GetProcessHeap(), 0, wideProvider
);
2845 ret
= WN_OUT_OF_MEMORY
;
2848 ret
= GetLastError();
2852 TRACE("Returning %ld\n", ret
);
2856 /*********************************************************************
2857 * WNetGetNetworkInformationW [MPR.@]
2859 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2860 LPNETINFOSTRUCT lpNetInfoStruct
)
2864 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2867 ret
= WN_BAD_POINTER
;
2868 else if (!lpNetInfoStruct
)
2869 ret
= WN_BAD_POINTER
;
2870 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2874 if (providerTable
&& providerTable
->numProviders
)
2876 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2878 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2880 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2881 lpNetInfoStruct
->dwProviderVersion
=
2882 providerTable
->table
[providerIndex
].dwSpecVersion
;
2883 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2884 lpNetInfoStruct
->dwCharacteristics
= 0;
2885 lpNetInfoStruct
->dwHandle
= 0;
2886 lpNetInfoStruct
->wNetType
=
2887 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2888 lpNetInfoStruct
->dwPrinters
= -1;
2889 lpNetInfoStruct
->dwDrives
= -1;
2893 ret
= WN_BAD_PROVIDER
;
2896 ret
= WN_NO_NETWORK
;
2900 TRACE("Returning %ld\n", ret
);
2904 /*****************************************************************
2905 * WNetGetProviderNameA [MPR.@]
2907 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2908 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2912 TRACE("(0x%08lx, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2916 ret
= WN_BAD_POINTER
;
2917 else if (!lpBufferSize
)
2918 ret
= WN_BAD_POINTER
;
2925 ret
= WN_NO_NETWORK
;
2926 for (i
= 0; i
< providerTable
->numProviders
&&
2927 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2930 if (i
< providerTable
->numProviders
)
2932 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2933 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2935 if (*lpBufferSize
< sizeNeeded
)
2937 *lpBufferSize
= sizeNeeded
;
2942 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2943 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2945 /* FIXME: is *lpBufferSize set to the number of characters
2951 ret
= WN_NO_NETWORK
;
2955 TRACE("Returning %ld\n", ret
);
2959 /*****************************************************************
2960 * WNetGetProviderNameW [MPR.@]
2962 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2963 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2967 TRACE("(0x%08lx, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2971 ret
= WN_BAD_POINTER
;
2972 else if (!lpBufferSize
)
2973 ret
= WN_BAD_POINTER
;
2980 ret
= WN_NO_NETWORK
;
2981 for (i
= 0; i
< providerTable
->numProviders
&&
2982 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2985 if (i
< providerTable
->numProviders
)
2987 DWORD sizeNeeded
= lstrlenW(providerTable
->table
[i
].name
) + 1;
2989 if (*lpBufferSize
< sizeNeeded
)
2991 *lpBufferSize
= sizeNeeded
;
2996 lstrcpyW(lpProvider
, providerTable
->table
[i
].name
);
2998 /* FIXME: is *lpBufferSize set to the number of characters
3004 ret
= WN_NO_NETWORK
;
3008 TRACE("Returning %ld\n", ret
);