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 #include <wine/unicode.h>
42 WINE_DEFAULT_DEBUG_CHANNEL(mpr
);
44 /* Data structures representing network service providers. Assumes only one
45 * thread creates them, and that they are constant for the life of the process
46 * (and therefore doesn't synchronize access).
47 * FIXME: only basic provider data and enumeration-related data are implemented
48 * so far, need to implement the rest too.
50 typedef struct _WNetProvider
58 PF_NPOpenEnum openEnum
;
59 PF_NPEnumResource enumResource
;
60 PF_NPCloseEnum closeEnum
;
61 PF_NPGetResourceInformation getResourceInformation
;
62 PF_NPAddConnection addConnection
;
63 PF_NPAddConnection3 addConnection3
;
64 PF_NPCancelConnection cancelConnection
;
66 PF_NPGetConnection getConnection
;
68 } WNetProvider
, *PWNetProvider
;
70 typedef struct _WNetProviderTable
75 WNetProvider table
[1];
76 } WNetProviderTable
, *PWNetProviderTable
;
78 #define WNET_ENUMERATOR_TYPE_GLOBAL 0
79 #define WNET_ENUMERATOR_TYPE_PROVIDER 1
80 #define WNET_ENUMERATOR_TYPE_CONTEXT 2
81 #define WNET_ENUMERATOR_TYPE_CONNECTED 3
82 #define WNET_ENUMERATOR_TYPE_REMEMBERED 4
84 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
85 * the enumeration; it represents one of the following types:
86 * - a global enumeration, one that's executed across all providers
87 * - a provider-specific enumeration, one that's only executed by a single
89 * - a context enumeration. I know this contradicts what I just said about
90 * there being no correspondence between the scope and the type, but it's
91 * necessary for the special case that a "Entire Network" entry needs to
92 * be enumerated in an enumeration of the context scope. Thus an enumeration
93 * of the context scope results in a context type enumerator, which morphs
94 * into a global enumeration (so the enumeration continues across all
96 * - a remembered enumeration, not related to providers themselves, but it
97 * is a registry enumeration for saved connections
99 typedef struct _WNetEnumerator
118 } WNetEnumerator
, *PWNetEnumerator
;
120 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
122 /* Returns an index (into the global WNetProviderTable) of the provider with
123 * the given name, or BAD_PROVIDER_INDEX if not found.
125 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
127 static PWNetProviderTable providerTable
;
130 * Global provider table functions
133 static void _tryLoadProvider(PCWSTR provider
)
135 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
136 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'S','e','r','v','i','c','e','s','\\',0 };
138 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
139 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
140 WCHAR serviceName
[MAX_PATH
];
143 TRACE("%s\n", debugstr_w(provider
));
144 swprintf(serviceName
, serviceFmt
, servicePrefix
, provider
);
145 serviceName
[ARRAY_SIZE(serviceName
) - 1] = '\0';
146 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
149 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
151 WCHAR providerPath
[MAX_PATH
];
152 DWORD type
, size
= sizeof(providerPath
);
154 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
155 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
157 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
160 if (type
== REG_EXPAND_SZ
)
162 WCHAR path
[MAX_PATH
];
163 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
167 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
170 name
= HeapAlloc(GetProcessHeap(), 0, size
);
171 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
172 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
174 HeapFree(GetProcessHeap(), 0, name
);
180 HMODULE hLib
= LoadLibraryW(providerPath
);
184 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
186 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
188 TRACE("loaded lib %p\n", hLib
);
192 PWNetProvider provider
=
193 &providerTable
->table
[providerTable
->numProviders
];
195 provider
->hLib
= hLib
;
196 provider
->name
= name
;
197 TRACE("name is %s\n", debugstr_w(name
));
198 provider
->getCaps
= getCaps
;
199 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
200 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
201 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
202 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
203 if (provider
->dwEnumScopes
)
205 TRACE("supports enumeration\n");
206 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
207 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
208 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
209 TRACE("NPEnumResource %p\n", provider
->enumResource
);
210 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
211 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
212 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
213 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
214 if (!provider
->openEnum
||
215 !provider
->enumResource
||
216 !provider
->closeEnum
)
218 provider
->openEnum
= NULL
;
219 provider
->enumResource
= NULL
;
220 provider
->closeEnum
= NULL
;
221 provider
->dwEnumScopes
= 0;
222 WARN("Couldn't load enumeration functions\n");
225 connectCap
= getCaps(WNNC_CONNECTION
);
226 if (connectCap
& WNNC_CON_ADDCONNECTION
)
227 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
228 if (connectCap
& WNNC_CON_ADDCONNECTION3
)
229 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
230 if (connectCap
& WNNC_CON_CANCELCONNECTION
)
231 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
233 if (connectCap
& WNNC_CON_GETCONNECTIONS
)
234 provider
->getConnection
= MPR_GETPROC(NPGetConnection
);
236 TRACE("NPAddConnection %p\n", provider
->addConnection
);
237 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
238 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
239 providerTable
->numProviders
++;
243 WARN("Provider %s didn't export NPGetCaps\n",
244 debugstr_w(provider
));
245 HeapFree(GetProcessHeap(), 0, name
);
253 WARN("Couldn't load library %s for provider %s\n",
254 debugstr_w(providerPath
), debugstr_w(provider
));
255 HeapFree(GetProcessHeap(), 0, name
);
260 WARN("Couldn't get provider name for provider %s\n",
261 debugstr_w(provider
));
265 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
269 WARN("Couldn't open service key for provider %s\n",
270 debugstr_w(provider
));
274 static void _restoreSavedConnection(HKEY connection
, WCHAR
* local
)
277 DWORD type
, prov
, index
, size
;
279 net
.lpProvider
= NULL
;
280 net
.lpRemoteName
= NULL
;
281 net
.lpLocalName
= NULL
;
283 TRACE("Restoring: %S\n", local
);
285 size
= sizeof(DWORD
);
286 if (RegQueryValueExW(connection
, L
"ConnectionType", NULL
, &type
, (BYTE
*)&net
.dwType
, &size
) != ERROR_SUCCESS
)
289 if (type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
292 if (RegQueryValueExW(connection
, L
"ProviderName", NULL
, &type
, NULL
, &size
) != ERROR_SUCCESS
)
298 net
.lpProvider
= HeapAlloc(GetProcessHeap(), 0, size
);
302 if (RegQueryValueExW(connection
, L
"ProviderName", NULL
, NULL
, (BYTE
*)net
.lpProvider
, &size
) != ERROR_SUCCESS
)
305 size
= sizeof(DWORD
);
306 if (RegQueryValueExW(connection
, L
"ProviderType", NULL
, &type
, (BYTE
*)&prov
, &size
) != ERROR_SUCCESS
)
309 if (type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
312 index
= _findProviderIndexW(net
.lpProvider
);
313 if (index
== BAD_PROVIDER_INDEX
)
316 if (providerTable
->table
[index
].dwNetType
!= prov
)
319 if (RegQueryValueExW(connection
, L
"RemotePath", NULL
, &type
, NULL
, &size
) != ERROR_SUCCESS
)
325 net
.lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, size
);
326 if (!net
.lpRemoteName
)
329 if (RegQueryValueExW(connection
, L
"RemotePath", NULL
, NULL
, (BYTE
*)net
.lpRemoteName
, &size
) != ERROR_SUCCESS
)
332 size
= strlenW(local
);
333 net
.lpLocalName
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
) + 2 * sizeof(WCHAR
));
334 if (!net
.lpLocalName
)
337 strcpyW(net
.lpLocalName
, local
);
338 net
.lpLocalName
[size
] = ':';
339 net
.lpLocalName
[size
+ 1] = 0;
341 TRACE("Attempting connection\n");
343 WNetAddConnection2W(&net
, NULL
, NULL
, 0);
346 HeapFree(GetProcessHeap(), 0, net
.lpProvider
);
347 HeapFree(GetProcessHeap(), 0, net
.lpRemoteName
);
348 HeapFree(GetProcessHeap(), 0, net
.lpLocalName
);
352 void wnetInit(HINSTANCE hInstDll
)
354 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
355 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
356 'C','o','n','t','r','o','l','\\',
357 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
358 'O','r','d','e','r',0 };
359 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
360 'O','r','d','e','r',0 };
363 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
368 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
371 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
377 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
378 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
383 TRACE("provider order is %s\n", debugstr_w(providers
));
384 /* first count commas as a heuristic for how many to
385 * allocate space for */
386 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
388 ptr
= wcschr(ptr
, ',');
395 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
396 sizeof(WNetProviderTable
)
397 + (numToAllocate
- 1) * sizeof(WNetProvider
));
401 int entireNetworkLen
;
402 LPCWSTR stringresource
;
404 entireNetworkLen
= LoadStringW(hInstDll
,
405 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
406 providerTable
->entireNetwork
= HeapAlloc(
407 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
409 if (providerTable
->entireNetwork
)
411 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
412 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
414 providerTable
->numAllocated
= numToAllocate
;
415 for (ptr
= providers
; ptr
; )
418 ptr
= wcschr(ptr
, ',');
421 _tryLoadProvider(ptrPrev
);
425 HeapFree(GetProcessHeap(), 0, providers
);
436 if (RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
439 WCHAR subkey
[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
441 if (RegOpenKeyExW(user_profile
, subkey
, 0, KEY_READ
, &network
) == ERROR_SUCCESS
)
445 TRACE("Enumerating remembered connections\n");
447 if (RegQueryInfoKey(network
, NULL
, NULL
, NULL
, &max
, &size
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
451 TRACE("There are %lu connections\n", max
);
453 local
= HeapAlloc(GetProcessHeap(), 0, (size
+ 1) * sizeof(WCHAR
));
458 for (index
= 0; index
< max
; ++index
)
460 DWORD len
= size
+ 1;
463 TRACE("Trying connection %lu\n", index
);
465 if (RegEnumKeyExW(network
, index
, local
, &len
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
468 TRACE("It is %S\n", local
);
470 if (RegOpenKeyExW(network
, local
, 0, KEY_READ
, &connection
) != ERROR_SUCCESS
)
473 _restoreSavedConnection(connection
, local
);
474 RegCloseKey(connection
);
477 HeapFree(GetProcessHeap(), 0, local
);
481 RegCloseKey(network
);
484 RegCloseKey(user_profile
);
496 for (i
= 0; i
< providerTable
->numProviders
; i
++)
498 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
499 FreeModule(providerTable
->table
[i
].hLib
);
501 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
502 HeapFree(GetProcessHeap(), 0, providerTable
);
503 providerTable
= NULL
;
507 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
509 DWORD ret
= BAD_PROVIDER_INDEX
;
511 if (providerTable
&& providerTable
->numProviders
)
515 for (i
= 0; i
< providerTable
->numProviders
&&
516 ret
== BAD_PROVIDER_INDEX
; i
++)
517 if (!lstrcmpW(lpProvider
, providerTable
->table
[i
].name
))
527 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
533 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
539 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
540 if (lpNet
->lpRemoteName
)
542 len
= lstrlenW(lpNet
->lpRemoteName
) + 1;
543 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
544 if (ret
->lpRemoteName
)
545 lstrcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
554 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
558 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
559 HeapFree(GetProcessHeap(), 0, lpNet
);
563 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
564 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
566 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
567 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
571 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
572 ret
->dwScope
= dwScope
;
573 ret
->dwType
= dwType
;
574 ret
->dwUsage
= dwUsage
;
575 ret
->specific
.net
= _copyNetResourceForEnumW(lpNet
);
580 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
581 DWORD dwUsage
, DWORD index
, HANDLE handle
)
585 if (!providerTable
|| index
>= providerTable
->numProviders
)
589 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
592 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
593 ret
->providerIndex
= index
;
594 ret
->dwScope
= dwScope
;
595 ret
->dwType
= dwType
;
596 ret
->dwUsage
= dwUsage
;
597 ret
->handle
= handle
;
603 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
606 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
607 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
611 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
612 ret
->dwScope
= dwScope
;
613 ret
->dwType
= dwType
;
614 ret
->dwUsage
= dwUsage
;
619 static PWNetEnumerator
_createConnectedEnumerator(DWORD dwScope
, DWORD dwType
,
622 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
625 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONNECTED
;
626 ret
->dwScope
= dwScope
;
627 ret
->dwType
= dwType
;
628 ret
->dwUsage
= dwUsage
;
629 ret
->specific
.handles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HANDLE
) * providerTable
->numProviders
);
630 if (!ret
->specific
.handles
)
632 HeapFree(GetProcessHeap(), 0, ret
);
639 static PWNetEnumerator
_createRememberedEnumerator(DWORD dwScope
, DWORD dwType
,
642 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
645 ret
->enumType
= WNET_ENUMERATOR_TYPE_REMEMBERED
;
646 ret
->dwScope
= dwScope
;
647 ret
->dwType
= dwType
;
648 ret
->specific
.remembered
.registry
= remembered
;
653 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
654 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
655 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
656 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
657 * if not all members of the array could be thunked, and something else on
660 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
661 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
663 DWORD i
, numToThunk
, totalBytes
, ret
;
667 return WN_BAD_POINTER
;
669 return WN_BAD_POINTER
;
673 return WN_BAD_POINTER
;
675 return WN_BAD_POINTER
;
677 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
679 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
681 totalBytes
+= sizeof(NETRESOURCEA
);
682 if (lpNet
->lpLocalName
)
683 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
684 -1, NULL
, 0, NULL
, NULL
);
685 if (lpNet
->lpRemoteName
)
686 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
687 -1, NULL
, 0, NULL
, NULL
);
688 if (lpNet
->lpComment
)
689 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
690 -1, NULL
, 0, NULL
, NULL
);
691 if (lpNet
->lpProvider
)
692 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
693 -1, NULL
, 0, NULL
, NULL
);
694 if (totalBytes
< *lpBufferSize
)
697 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
698 for (i
= 0; i
< numToThunk
; i
++)
700 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
701 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
703 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
704 /* lie about string lengths, we already verified how many
705 * we have space for above
707 if (lpNetIn
->lpLocalName
)
709 lpNetOut
->lpLocalName
= strNext
;
710 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
711 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
713 if (lpNetIn
->lpRemoteName
)
715 lpNetOut
->lpRemoteName
= strNext
;
716 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
717 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
719 if (lpNetIn
->lpComment
)
721 lpNetOut
->lpComment
= strNext
;
722 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
723 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
725 if (lpNetIn
->lpProvider
)
727 lpNetOut
->lpProvider
= strNext
;
728 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
729 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
732 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
733 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
738 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
739 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
740 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
741 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
742 * if not all members of the array could be thunked, and something else on
745 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
746 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
748 DWORD i
, numToThunk
, totalBytes
, ret
;
752 return WN_BAD_POINTER
;
754 return WN_BAD_POINTER
;
758 return WN_BAD_POINTER
;
760 return WN_BAD_POINTER
;
762 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
764 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
766 totalBytes
+= sizeof(NETRESOURCEW
);
767 if (lpNet
->lpLocalName
)
768 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
769 -1, NULL
, 0) * sizeof(WCHAR
);
770 if (lpNet
->lpRemoteName
)
771 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
772 -1, NULL
, 0) * sizeof(WCHAR
);
773 if (lpNet
->lpComment
)
774 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
775 -1, NULL
, 0) * sizeof(WCHAR
);
776 if (lpNet
->lpProvider
)
777 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
778 -1, NULL
, 0) * sizeof(WCHAR
);
779 if (totalBytes
< *lpBufferSize
)
782 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
783 for (i
= 0; i
< numToThunk
; i
++)
785 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
786 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
788 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
789 /* lie about string lengths, we already verified how many
790 * we have space for above
792 if (lpNetIn
->lpLocalName
)
794 lpNetOut
->lpLocalName
= strNext
;
795 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
796 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
798 if (lpNetIn
->lpRemoteName
)
800 lpNetOut
->lpRemoteName
= strNext
;
801 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
802 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
804 if (lpNetIn
->lpComment
)
806 lpNetOut
->lpComment
= strNext
;
807 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
808 -1, lpNetOut
->lpComment
, *lpBufferSize
);
810 if (lpNetIn
->lpProvider
)
812 lpNetOut
->lpProvider
= strNext
;
813 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
814 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
817 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
818 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
823 /*********************************************************************
824 * WNetOpenEnumA [MPR.@]
826 * See comments for WNetOpenEnumW.
828 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
829 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
833 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
834 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
837 ret
= WN_BAD_POINTER
;
838 else if (!providerTable
|| providerTable
->numProviders
== 0)
847 LPNETRESOURCEW lpNetWide
= NULL
;
849 DWORD size
= sizeof(buf
), count
= 1;
850 BOOL allocated
= FALSE
;
852 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
853 if (ret
== WN_MORE_DATA
)
855 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
859 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
864 ret
= WN_OUT_OF_MEMORY
;
866 else if (ret
== WN_SUCCESS
)
867 lpNetWide
= (LPNETRESOURCEW
)buf
;
868 if (ret
== WN_SUCCESS
)
869 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
872 HeapFree(GetProcessHeap(), 0, lpNetWide
);
875 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
879 TRACE("Returning %d\n", ret
);
883 /*********************************************************************
884 * WNetOpenEnumW [MPR.@]
886 * Network enumeration has way too many parameters, so I'm not positive I got
887 * them right. What I've got so far:
889 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
890 * all the network providers should be enumerated.
892 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
893 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
894 * lpProvider is set, all the network providers should be enumerated.
895 * (This means the enumeration is a list of network providers, not that the
896 * enumeration is passed on to the providers.)
898 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
899 * resource matches the "Entire Network" resource (no remote name, no
900 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
901 * enumeration is done on every network provider.
903 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
904 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
905 * only to the given network provider.
907 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
908 * no lpProvider is set, enumeration will be tried on every network provider,
909 * in the order in which they're loaded.
911 * - The LPNETRESOURCE should be disregarded for scopes besides
912 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
913 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
915 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
916 * resource in the enumerated list, as well as any machines in your
917 * workgroup. The machines in your workgroup come from doing a
918 * RESOURCE_CONTEXT enumeration of every Network Provider.
920 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
921 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
925 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
926 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
929 ret
= WN_BAD_POINTER
;
930 else if (!providerTable
|| providerTable
->numProviders
== 0)
939 case RESOURCE_GLOBALNET
:
942 if (lpNet
->lpProvider
)
944 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
946 if (index
!= BAD_PROVIDER_INDEX
)
948 if (providerTable
->table
[index
].openEnum
&&
949 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
952 PWSTR RemoteName
= lpNet
->lpRemoteName
;
954 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
955 RemoteName
&& !lstrcmpW(RemoteName
, lpNet
->lpProvider
))
956 lpNet
->lpRemoteName
= NULL
;
958 ret
= providerTable
->table
[index
].openEnum(
959 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
960 if (ret
== WN_SUCCESS
)
962 *lphEnum
= _createProviderEnumerator(
963 dwScope
, dwType
, dwUsage
, index
, handle
);
964 ret
= *lphEnum
? WN_SUCCESS
:
968 lpNet
->lpRemoteName
= RemoteName
;
971 ret
= WN_NOT_SUPPORTED
;
974 ret
= WN_BAD_PROVIDER
;
976 else if (lpNet
->lpRemoteName
)
978 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
979 dwType
, dwUsage
, lpNet
);
980 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
984 if (lpNet
->lpComment
&& !lstrcmpW(lpNet
->lpComment
,
985 providerTable
->entireNetwork
))
987 /* comment matches the "Entire Network", enumerate
988 * global scope of every provider
990 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
991 dwType
, dwUsage
, lpNet
);
995 /* this is the same as not having passed lpNet */
996 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
997 dwType
, dwUsage
, NULL
);
999 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1004 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
1006 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1009 case RESOURCE_CONTEXT
:
1010 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
1011 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1013 case RESOURCE_CONNECTED
:
1014 *lphEnum
= _createConnectedEnumerator(dwScope
, dwType
, dwUsage
);
1015 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1017 case RESOURCE_REMEMBERED
:
1019 HKEY remembered
, user_profile
;
1021 ret
= WN_OUT_OF_MEMORY
;
1022 if (RegOpenCurrentUser(KEY_READ
, &user_profile
) == ERROR_SUCCESS
)
1024 WCHAR subkey
[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
1026 if (RegOpenKeyExW(user_profile
, subkey
, 0, KEY_READ
, &remembered
) == ERROR_SUCCESS
)
1028 *lphEnum
= _createRememberedEnumerator(dwScope
, dwType
, remembered
);
1029 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1032 RegCloseKey(user_profile
);
1037 WARN("unknown scope 0x%08x\n", dwScope
);
1043 TRACE("Returning %d\n", ret
);
1047 /*********************************************************************
1048 * WNetEnumResourceA [MPR.@]
1050 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
1051 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1055 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1058 ret
= WN_BAD_POINTER
;
1060 ret
= WN_BAD_POINTER
;
1062 ret
= WN_BAD_POINTER
;
1063 else if (!lpBufferSize
)
1064 ret
= WN_BAD_POINTER
;
1065 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
1067 *lpBufferSize
= sizeof(NETRESOURCEA
);
1072 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
1073 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
1077 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
1079 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
1081 /* FIXME: this isn't necessarily going to work in the case of
1082 * WN_MORE_DATA, because our enumerator may have moved on to
1083 * the next provider. MSDN states that a large (16KB) buffer
1084 * size is the appropriate usage of this function, so
1085 * hopefully it won't be an issue.
1087 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
1088 lpBuffer
, lpBufferSize
);
1089 *lpcCount
= localCount
;
1091 HeapFree(GetProcessHeap(), 0, localBuffer
);
1094 ret
= WN_OUT_OF_MEMORY
;
1098 TRACE("Returning %d\n", ret
);
1102 static DWORD
_countProviderBytesW(PWNetProvider provider
)
1108 ret
= sizeof(NETRESOURCEW
);
1109 ret
+= 2 * (lstrlenW(provider
->name
) + 1) * sizeof(WCHAR
);
1116 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1117 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
1122 return WN_BAD_POINTER
;
1123 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1124 return WN_BAD_VALUE
;
1126 return WN_BAD_POINTER
;
1128 return WN_BAD_POINTER
;
1130 return WN_BAD_POINTER
;
1131 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
1132 return WN_MORE_DATA
;
1134 if (!providerTable
|| enumerator
->providerIndex
>=
1135 providerTable
->numProviders
)
1136 ret
= WN_NO_MORE_ENTRIES
;
1139 DWORD bytes
= 0, count
= 0, countLimit
, i
;
1140 LPNETRESOURCEW resource
;
1143 countLimit
= *lpcCount
== -1 ?
1144 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
1145 while (count
< countLimit
&& bytes
< *lpBufferSize
)
1147 DWORD bytesNext
= _countProviderBytesW(
1148 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
1150 if (bytes
+ bytesNext
< *lpBufferSize
)
1156 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
1157 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
1159 resource
->dwScope
= RESOURCE_GLOBALNET
;
1160 resource
->dwType
= RESOURCETYPE_ANY
;
1161 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
1162 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
1163 RESOURCEUSAGE_RESERVED
;
1164 resource
->lpLocalName
= NULL
;
1165 resource
->lpRemoteName
= strNext
;
1166 lstrcpyW(resource
->lpRemoteName
,
1167 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1168 strNext
+= lstrlenW(resource
->lpRemoteName
) + 1;
1169 resource
->lpComment
= NULL
;
1170 resource
->lpProvider
= strNext
;
1171 lstrcpyW(resource
->lpProvider
,
1172 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1173 strNext
+= lstrlenW(resource
->lpProvider
) + 1;
1175 enumerator
->providerIndex
+= count
;
1177 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
1179 TRACE("Returning %d\n", ret
);
1183 /* Advances the enumerator (assumed to be a global enumerator) to the next
1184 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1185 * not open a handle with the next provider.
1186 * If the existing handle is NULL, may leave the enumerator unchanged, since
1187 * the current provider may support the desired scope.
1188 * If the existing handle is not NULL, closes it before moving on.
1189 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1190 * provider, and another error on failure.
1192 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
1195 return WN_BAD_POINTER
;
1196 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1197 return WN_BAD_VALUE
;
1198 if (!providerTable
|| enumerator
->providerIndex
>=
1199 providerTable
->numProviders
)
1200 return WN_NO_MORE_ENTRIES
;
1202 if (enumerator
->providerDone
)
1205 enumerator
->providerDone
= FALSE
;
1206 if (enumerator
->handle
)
1208 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1209 enumerator
->handle
);
1210 enumerator
->handle
= NULL
;
1211 enumerator
->providerIndex
++;
1213 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1214 dwEnum
= WNNC_ENUM_LOCAL
;
1215 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1216 dwEnum
= WNNC_ENUM_GLOBAL
;
1217 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1218 dwEnum
= WNNC_ENUM_CONTEXT
;
1219 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1220 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1221 & dwEnum
); enumerator
->providerIndex
++)
1224 return enumerator
->providerIndex
< providerTable
->numProviders
?
1225 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1228 /* "Passes through" call to the next provider that supports the enumeration
1230 * FIXME: if one call to a provider's enumerator succeeds while there's still
1231 * space in lpBuffer, I don't call to the next provider. The caller may not
1232 * expect that it should call EnumResourceW again with a return value of
1233 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1234 * may have to be moved around a bit, ick.
1236 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1237 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1242 return WN_BAD_POINTER
;
1243 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1244 return WN_BAD_VALUE
;
1246 return WN_BAD_POINTER
;
1248 return WN_BAD_POINTER
;
1250 return WN_BAD_POINTER
;
1251 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1252 return WN_MORE_DATA
;
1254 ret
= _globalEnumeratorAdvance(enumerator
);
1255 if (ret
== WN_SUCCESS
)
1257 ret
= providerTable
->table
[enumerator
->providerIndex
].
1258 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1259 enumerator
->dwUsage
, enumerator
->specific
.net
,
1260 &enumerator
->handle
);
1261 if (ret
== WN_SUCCESS
)
1263 ret
= providerTable
->table
[enumerator
->providerIndex
].
1264 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1266 if (ret
!= WN_MORE_DATA
)
1267 enumerator
->providerDone
= TRUE
;
1270 TRACE("Returning %d\n", ret
);
1274 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1275 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1280 return WN_BAD_POINTER
;
1281 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1282 return WN_BAD_VALUE
;
1284 return WN_BAD_POINTER
;
1286 return WN_BAD_POINTER
;
1288 return WN_BAD_POINTER
;
1289 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1290 return WN_MORE_DATA
;
1292 return WN_NO_NETWORK
;
1294 switch (enumerator
->dwScope
)
1296 case RESOURCE_GLOBALNET
:
1297 if (enumerator
->specific
.net
)
1298 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1299 lpBuffer
, lpBufferSize
);
1301 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1304 case RESOURCE_CONTEXT
:
1305 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1309 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1310 ret
= WN_NO_MORE_ENTRIES
;
1312 TRACE("Returning %d\n", ret
);
1316 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1317 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1320 return WN_BAD_POINTER
;
1321 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1322 return WN_BAD_VALUE
;
1323 if (!enumerator
->handle
)
1324 return WN_BAD_VALUE
;
1326 return WN_BAD_POINTER
;
1328 return WN_BAD_POINTER
;
1330 return WN_BAD_POINTER
;
1332 return WN_NO_NETWORK
;
1333 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1334 return WN_NO_MORE_ENTRIES
;
1335 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1336 return WN_BAD_VALUE
;
1337 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1338 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1341 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1342 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1345 size_t cchEntireNetworkLen
, bytesNeeded
;
1348 return WN_BAD_POINTER
;
1349 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1350 return WN_BAD_VALUE
;
1352 return WN_BAD_POINTER
;
1354 return WN_BAD_POINTER
;
1356 return WN_BAD_POINTER
;
1358 return WN_NO_NETWORK
;
1360 cchEntireNetworkLen
= lstrlenW(providerTable
->entireNetwork
) + 1;
1361 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1362 if (*lpBufferSize
< bytesNeeded
)
1364 *lpBufferSize
= bytesNeeded
;
1369 LPNETRESOURCEW lpNet
= lpBuffer
;
1371 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1372 lpNet
->dwType
= enumerator
->dwType
;
1373 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1374 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1375 lpNet
->lpLocalName
= NULL
;
1376 lpNet
->lpRemoteName
= NULL
;
1377 lpNet
->lpProvider
= NULL
;
1378 /* odd, but correct: put comment at end of buffer, so it won't get
1379 * overwritten by subsequent calls to a provider's enumResource
1381 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1382 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1383 lstrcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1386 if (ret
== WN_SUCCESS
)
1388 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1390 /* "Entire Network" entry enumerated--morph this into a global
1391 * enumerator. enumerator->lpNet continues to be NULL, since it has
1392 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1394 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1395 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1396 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1397 if (ret
== WN_SUCCESS
)
1399 /* reflect the fact that we already enumerated "Entire Network" */
1401 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1405 /* the provider enumeration failed, but we already succeeded in
1406 * enumerating "Entire Network"--leave type as global to allow a
1407 * retry, but indicate success with a count of one.
1411 *lpBufferSize
= bytesNeeded
;
1414 TRACE("Returning %d\n", ret
);
1418 static DWORD
_copyStringToEnumW(const WCHAR
*source
, DWORD
* left
, void** end
)
1421 WCHAR
* local
= *end
;
1423 len
= lstrlenW(source
) + 1;
1424 len
*= sizeof(WCHAR
);
1426 return WN_MORE_DATA
;
1428 local
-= (len
/ sizeof(WCHAR
));
1429 memcpy(local
, source
, len
);
1436 static DWORD
_enumerateConnectedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1437 void* user_buffer
, DWORD
* user_size
)
1439 DWORD ret
, index
, count
, total_count
, size
, i
, left
;
1441 NETRESOURCEW
* curr
, * buffer
;
1445 return WN_BAD_POINTER
;
1446 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONNECTED
)
1447 return WN_BAD_VALUE
;
1448 if (!user_count
|| !user_buffer
|| !user_size
)
1449 return WN_BAD_POINTER
;
1451 return WN_NO_NETWORK
;
1453 handles
= enumerator
->specific
.handles
;
1456 buffer
= HeapAlloc(GetProcessHeap(), 0, *user_size
);
1458 return WN_NO_NETWORK
;
1461 end
= (char *)user_buffer
+ size
;
1462 count
= *user_count
;
1465 ret
= WN_NO_MORE_ENTRIES
;
1466 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1468 if (providerTable
->table
[index
].dwEnumScopes
)
1470 if (handles
[index
] == 0)
1472 ret
= providerTable
->table
[index
].openEnum(enumerator
->dwScope
,
1474 enumerator
->dwUsage
,
1475 NULL
, &handles
[index
]);
1476 if (ret
!= WN_SUCCESS
)
1480 ret
= providerTable
->table
[index
].enumResource(handles
[index
],
1483 total_count
+= count
;
1484 if (ret
== WN_MORE_DATA
)
1487 if (ret
== WN_SUCCESS
)
1489 for (i
= 0; i
< count
; ++i
)
1491 if (left
< sizeof(NETRESOURCEW
))
1497 memcpy(curr
, &buffer
[i
], sizeof(NETRESOURCEW
));
1498 left
-= sizeof(NETRESOURCEW
);
1500 ret
= _copyStringToEnumW(buffer
[i
].lpLocalName
, &left
, &end
);
1501 if (ret
== WN_MORE_DATA
)
1503 curr
->lpLocalName
= end
;
1505 ret
= _copyStringToEnumW(buffer
[i
].lpRemoteName
, &left
, &end
);
1506 if (ret
== WN_MORE_DATA
)
1508 curr
->lpRemoteName
= end
;
1510 ret
= _copyStringToEnumW(buffer
[i
].lpProvider
, &left
, &end
);
1511 if (ret
== WN_MORE_DATA
)
1513 curr
->lpProvider
= end
;
1521 if (*user_count
!= -1)
1522 count
= *user_count
- total_count
;
1524 count
= *user_count
;
1528 if (total_count
== 0)
1529 ret
= WN_NO_MORE_ENTRIES
;
1531 *user_count
= total_count
;
1532 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1535 HeapFree(GetProcessHeap(), 0, buffer
);
1537 TRACE("Returning %d\n", ret
);
1541 static const WCHAR connectionType
[] = { 'C','o','n','n','e','c','t','i','o','n','T','y','p','e',0 };
1542 static const WCHAR providerName
[] = { 'P','r','o','v','i','d','e','r','N','a','m','e',0 };
1543 static const WCHAR remotePath
[] = { 'R','e','m','o','t','e','P','a','t','h',0 };
1545 static WCHAR
*get_reg_str(HKEY hkey
, const WCHAR
*value
, DWORD
*len
)
1550 if (!RegQueryValueExW(hkey
, value
, NULL
, &type
, NULL
, len
) && type
== REG_SZ
)
1552 if (!(ret
= HeapAlloc(GetProcessHeap(), 0, *len
))) return NULL
;
1553 RegQueryValueExW(hkey
, value
, 0, 0, (BYTE
*)ret
, len
);
1559 static DWORD
_enumeratorRememberedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1560 void* user_buffer
, DWORD
* user_size
)
1562 HKEY registry
, connection
;
1565 DWORD index
, ret
, type
, len
, size
, registry_size
, full_size
= 0, total_count
;
1566 NETRESOURCEW
* net_buffer
= user_buffer
;
1567 WCHAR
* str
, * registry_string
;
1569 /* we will do the work in a single loop, so here is some things:
1570 * we write netresource at the begin of the user buffer
1571 * we write strings at the end of the user buffer
1573 size_left
= *user_size
;
1575 type
= enumerator
->dwType
;
1576 registry
= enumerator
->specific
.remembered
.registry
;
1577 str
= (WCHAR
*)((ULONG_PTR
)user_buffer
+ *user_size
- sizeof(WCHAR
));
1578 for (index
= enumerator
->specific
.remembered
.index
; ; ++index
)
1580 enumerator
->specific
.remembered
.index
= index
;
1582 if (*user_count
!= -1 && total_count
== *user_count
)
1588 len
= ARRAY_SIZE(buffer
);
1589 ret
= RegEnumKeyExW(registry
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
);
1590 if (ret
!= ERROR_SUCCESS
)
1592 if (ret
== ERROR_NO_MORE_ITEMS
) ret
= WN_SUCCESS
;
1596 if (RegOpenKeyExW(registry
, buffer
, 0, KEY_READ
, &connection
) != ERROR_SUCCESS
)
1601 full_size
= sizeof(NETRESOURCEW
);
1602 size_left
-= sizeof(NETRESOURCEW
);
1606 size
= sizeof(DWORD
);
1607 RegQueryValueExW(connection
, connectionType
, NULL
, NULL
, (BYTE
*)&net_buffer
->dwType
, &size
);
1608 if (type
!= RESOURCETYPE_ANY
&& net_buffer
->dwType
!= type
)
1610 size_left
+= sizeof(NETRESOURCEW
);
1611 RegCloseKey(connection
);
1615 net_buffer
->dwScope
= RESOURCE_REMEMBERED
;
1616 net_buffer
->dwDisplayType
= RESOURCEDISPLAYTYPE_GENERIC
;
1617 net_buffer
->dwUsage
= RESOURCEUSAGE_CONNECTABLE
;
1622 /* FIXME: this only supports drive letters */
1623 full_size
+= 3 * sizeof(WCHAR
);
1624 size_left
-= 3 * sizeof(WCHAR
);
1631 net_buffer
->lpLocalName
= str
;
1635 registry_string
= get_reg_str(connection
, providerName
, ®istry_size
);
1636 if (registry_string
)
1638 full_size
+= registry_size
;
1639 size_left
-= registry_size
;
1643 str
-= (registry_size
/ sizeof(WCHAR
));
1644 lstrcpyW(str
, registry_string
);
1645 net_buffer
->lpProvider
= str
;
1650 HeapFree(GetProcessHeap(), 0, registry_string
);
1654 registry_string
= get_reg_str(connection
, remotePath
, ®istry_size
);
1655 if (registry_string
)
1657 full_size
+= registry_size
;
1658 size_left
-= registry_size
;
1662 str
-= (registry_size
/ sizeof(WCHAR
));
1663 lstrcpyW(str
, registry_string
);
1664 net_buffer
->lpRemoteName
= str
;
1669 HeapFree(GetProcessHeap(), 0, registry_string
);
1672 RegCloseKey(connection
);
1674 net_buffer
->lpComment
= NULL
;
1683 if (total_count
== 0)
1684 ret
= WN_NO_MORE_ENTRIES
;
1686 *user_count
= total_count
;
1688 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1691 if (ret
== WN_MORE_DATA
)
1692 *user_size
= *user_size
+ full_size
;
1697 /*********************************************************************
1698 * WNetEnumResourceW [MPR.@]
1700 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1701 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1705 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1708 ret
= WN_BAD_POINTER
;
1710 ret
= WN_BAD_POINTER
;
1712 ret
= WN_BAD_POINTER
;
1713 else if (!lpBufferSize
)
1714 ret
= WN_BAD_POINTER
;
1715 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1717 *lpBufferSize
= sizeof(NETRESOURCEW
);
1722 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1724 switch (enumerator
->enumType
)
1726 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1727 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1730 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1731 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1734 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1735 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1738 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1739 ret
= _enumerateConnectedW(enumerator
, lpcCount
, lpBuffer
,
1742 case WNET_ENUMERATOR_TYPE_REMEMBERED
:
1743 ret
= _enumeratorRememberedW(enumerator
, lpcCount
, lpBuffer
,
1747 WARN("bogus enumerator type!\n");
1748 ret
= WN_NO_NETWORK
;
1753 TRACE("Returning %d\n", ret
);
1757 /*********************************************************************
1758 * WNetCloseEnum [MPR.@]
1760 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1765 TRACE( "(%p)\n", hEnum
);
1769 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1771 switch (enumerator
->enumType
)
1773 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1774 if (enumerator
->specific
.net
)
1775 _freeEnumNetResource(enumerator
->specific
.net
);
1776 if (enumerator
->handle
)
1777 providerTable
->table
[enumerator
->providerIndex
].
1778 closeEnum(enumerator
->handle
);
1781 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1782 if (enumerator
->handle
)
1783 providerTable
->table
[enumerator
->providerIndex
].
1784 closeEnum(enumerator
->handle
);
1787 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1788 handles
= enumerator
->specific
.handles
;
1789 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1791 if (providerTable
->table
[index
].dwEnumScopes
&& handles
[index
])
1792 providerTable
->table
[index
].closeEnum(handles
[index
]);
1794 HeapFree(GetProcessHeap(), 0, handles
);
1797 case WNET_ENUMERATOR_TYPE_REMEMBERED
:
1798 RegCloseKey(enumerator
->specific
.remembered
.registry
);
1802 WARN("bogus enumerator type!\n");
1803 ret
= WN_BAD_HANDLE
;
1805 HeapFree(GetProcessHeap(), 0, hEnum
);
1808 ret
= WN_BAD_HANDLE
;
1811 TRACE("Returning %d\n", ret
);
1815 /*********************************************************************
1816 * WNetGetResourceInformationA [MPR.@]
1818 * See WNetGetResourceInformationW
1820 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1821 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1826 TRACE( "(%p, %p, %p, %p)\n",
1827 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1829 if (!providerTable
|| providerTable
->numProviders
== 0)
1830 ret
= WN_NO_NETWORK
;
1831 else if (lpNetResource
)
1833 LPNETRESOURCEW lpNetResourceW
= NULL
;
1834 DWORD size
= 1024, count
= 1;
1837 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1838 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1839 if (ret
== WN_MORE_DATA
)
1841 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1842 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1844 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1845 &count
, lpNetResourceW
, &size
);
1847 ret
= WN_OUT_OF_MEMORY
;
1849 if (ret
== WN_SUCCESS
)
1851 LPWSTR lpSystemW
= NULL
;
1854 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1857 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1858 lpBufferW
, &size
, &lpSystemW
);
1859 if (ret
== WN_MORE_DATA
)
1861 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1862 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1864 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1865 lpBufferW
, &size
, &lpSystemW
);
1867 ret
= WN_OUT_OF_MEMORY
;
1869 if (ret
== WN_SUCCESS
)
1871 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1872 &count
, lpBuffer
, cbBuffer
);
1873 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1874 lpNetResourceW
= lpBufferW
;
1875 size
= sizeof(NETRESOURCEA
);
1876 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1877 -1, NULL
, 0, NULL
, NULL
);
1878 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1879 -1, NULL
, 0, NULL
, NULL
);
1881 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1882 -1, NULL
, 0, NULL
, NULL
);
1883 if ((len
) && ( size
+ len
< *cbBuffer
))
1885 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1886 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1887 *lplpSystem
, len
, NULL
, NULL
);
1894 ret
= WN_OUT_OF_MEMORY
;
1895 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1898 ret
= WN_OUT_OF_MEMORY
;
1899 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1901 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1904 ret
= WN_NO_NETWORK
;
1908 TRACE("Returning %d\n", ret
);
1912 /*********************************************************************
1913 * WNetGetResourceInformationW [MPR.@]
1915 * WNetGetResourceInformationW function identifies the network provider
1916 * that owns the resource and gets information about the type of the resource.
1919 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1920 * defines a network resource.
1921 * lpBuffer [ O] the pointer to buffer, containing result. It
1922 * contains NETRESOURCEW structure and strings to
1923 * which the members of the NETRESOURCEW structure
1925 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1927 * lplpSystem [ O] the pointer to string in the output buffer,
1928 * containing the part of the resource name without
1929 * names of the server and share.
1932 * NO_ERROR if the function succeeds. System error code if the function fails.
1935 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1936 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1937 LPWSTR
*lplpSystem
)
1939 DWORD ret
= WN_NO_NETWORK
;
1942 TRACE( "(%p, %p, %p, %p)\n",
1943 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1946 ret
= WN_OUT_OF_MEMORY
;
1947 else if (providerTable
!= NULL
)
1949 /* FIXME: For function value of a variable is indifferent, it does
1950 * search of all providers in a network.
1952 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1954 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1955 WNNC_DLG_GETRESOURCEINFORMATION
)
1957 if (providerTable
->table
[index
].getResourceInformation
)
1958 ret
= providerTable
->table
[index
].getResourceInformation(
1959 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1961 ret
= WN_NO_NETWORK
;
1962 if (ret
== WN_SUCCESS
)
1972 /*********************************************************************
1973 * WNetGetResourceParentA [MPR.@]
1975 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1976 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1978 FIXME( "(%p, %p, %p): stub\n",
1979 lpNetResource
, lpBuffer
, lpBufferSize
);
1981 SetLastError(WN_NO_NETWORK
);
1982 return WN_NO_NETWORK
;
1985 /*********************************************************************
1986 * WNetGetResourceParentW [MPR.@]
1988 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1989 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1991 FIXME( "(%p, %p, %p): stub\n",
1992 lpNetResource
, lpBuffer
, lpBufferSize
);
1994 SetLastError(WN_NO_NETWORK
);
1995 return WN_NO_NETWORK
;
2001 * Connection Functions
2004 /*********************************************************************
2005 * WNetAddConnectionA [MPR.@]
2007 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
2008 LPCSTR lpLocalName
)
2010 NETRESOURCEA resourcesA
;
2012 memset(&resourcesA
, 0, sizeof(resourcesA
));
2013 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
2014 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
2015 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
2018 /*********************************************************************
2019 * WNetAddConnectionW [MPR.@]
2021 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
2022 LPCWSTR lpLocalName
)
2024 NETRESOURCEW resourcesW
;
2026 memset(&resourcesW
, 0, sizeof(resourcesW
));
2027 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
2028 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
2029 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
2032 /*********************************************************************
2033 * WNetAddConnection2A [MPR.@]
2035 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
2036 LPCSTR lpPassword
, LPCSTR lpUserID
,
2039 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
2043 /*********************************************************************
2044 * WNetAddConnection2W [MPR.@]
2046 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
2047 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
2050 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
2054 /*********************************************************************
2055 * WNetAddConnection3A [MPR.@]
2057 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
2058 LPCSTR lpPassword
, LPCSTR lpUserID
,
2061 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
2062 dwFlags
, NULL
, 0, NULL
);
2065 /*********************************************************************
2066 * WNetAddConnection3W [MPR.@]
2068 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
2069 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
2072 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
2073 dwFlags
, NULL
, 0, NULL
);
2076 struct use_connection_context
2079 NETRESOURCEW
*resource
;
2080 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
2087 DWORD (*pre_set_accessname
)(struct use_connection_context
*, WCHAR
*);
2088 void (*set_accessname
)(struct use_connection_context
*, WCHAR
*);
2091 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2093 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
2098 len
= lstrlenW(local_name
);
2100 len
= lstrlenW(ctxt
->resource
->lpRemoteName
);
2102 if (++len
> *ctxt
->buffer_size
)
2104 *ctxt
->buffer_size
= len
;
2105 return ERROR_MORE_DATA
;
2109 ctxt
->accessname
= NULL
;
2111 return ERROR_SUCCESS
;
2114 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2116 WCHAR
*accessname
= ctxt
->accessname
;
2119 lstrcpyW(accessname
, local_name
);
2121 *ctxt
->result
= CONNECT_LOCALDRIVE
;
2124 lstrcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
2127 static DWORD
wnet_use_provider( struct use_connection_context
*ctxt
, NETRESOURCEW
* netres
, WNetProvider
*provider
, BOOLEAN redirect
)
2131 caps
= provider
->getCaps(WNNC_CONNECTION
);
2132 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
2133 return ERROR_BAD_PROVIDER
;
2135 ret
= WN_ACCESS_DENIED
;
2138 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
2139 ret
= provider
->addConnection3(ctxt
->hwndOwner
, netres
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
2140 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
2141 ret
= provider
->addConnection(netres
, ctxt
->password
, ctxt
->userid
);
2143 if (ret
== WN_ALREADY_CONNECTED
&& redirect
)
2144 netres
->lpLocalName
[0] -= 1;
2145 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& netres
->lpLocalName
[0] >= 'C');
2147 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
2148 ctxt
->set_accessname(ctxt
, netres
->lpLocalName
);
2153 static const WCHAR providerType
[] = { 'P','r','o','v','i','d','e','r','T','y','p','e',0 };
2154 static const WCHAR userName
[] = { 'U','s','e','r','N','a','m','e',0 };
2156 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
2158 WNetProvider
*provider
= NULL
;
2159 DWORD index
, ret
= WN_NO_NETWORK
;
2160 BOOL redirect
= FALSE
;
2161 WCHAR letter
[3] = {'Z', ':', 0};
2162 NETRESOURCEW netres
;
2164 if (!providerTable
|| providerTable
->numProviders
== 0)
2165 return WN_NO_NETWORK
;
2167 if (!ctxt
->resource
)
2168 return ERROR_INVALID_PARAMETER
;
2169 netres
= *ctxt
->resource
;
2171 if (!netres
.lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
2173 if (netres
.dwType
!= RESOURCETYPE_DISK
&& netres
.dwType
!= RESOURCETYPE_PRINT
)
2174 return ERROR_BAD_DEV_TYPE
;
2176 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2178 FIXME("Local device selection is not implemented for printers.\n");
2179 return WN_NO_NETWORK
;
2183 netres
.lpLocalName
= letter
;
2186 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
2187 return ERROR_BAD_NET_NAME
;
2189 if ((ret
= ctxt
->pre_set_accessname(ctxt
, netres
.lpLocalName
)))
2192 if (netres
.lpProvider
)
2194 index
= _findProviderIndexW(netres
.lpProvider
);
2195 if (index
== BAD_PROVIDER_INDEX
)
2196 return ERROR_BAD_PROVIDER
;
2198 provider
= &providerTable
->table
[index
];
2199 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2203 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2205 provider
= &providerTable
->table
[index
];
2206 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2207 if (ret
== WN_SUCCESS
|| ret
== WN_ALREADY_CONNECTED
)
2212 if (ret
== WN_SUCCESS
&& ctxt
->flags
& CONNECT_UPDATE_PROFILE
)
2216 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2218 FIXME("Persistent connection are not supported for printers\n");
2222 if (RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2225 WCHAR subkey
[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres
.lpLocalName
[0], 0};
2227 if (RegCreateKeyExW(user_profile
, subkey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2228 KEY_ALL_ACCESS
, NULL
, &network
, NULL
) == ERROR_SUCCESS
)
2230 DWORD dword_arg
= RESOURCETYPE_DISK
;
2231 DWORD len
= (lstrlenW(provider
->name
) + 1) * sizeof(WCHAR
);
2232 static const WCHAR empty
[1] = {0};
2234 RegSetValueExW(network
, connectionType
, 0, REG_DWORD
, (const BYTE
*)&dword_arg
, sizeof(DWORD
));
2235 RegSetValueExW(network
, providerName
, 0, REG_SZ
, (const BYTE
*)provider
->name
, len
);
2236 RegSetValueExW(network
, providerType
, 0, REG_DWORD
, (const BYTE
*)&provider
->dwNetType
, sizeof(DWORD
));
2237 len
= (lstrlenW(netres
.lpRemoteName
) + 1) * sizeof(WCHAR
);
2238 RegSetValueExW(network
, remotePath
, 0, REG_SZ
, (const BYTE
*)netres
.lpRemoteName
, len
);
2239 len
= sizeof(empty
);
2240 RegSetValueExW(network
, userName
, 0, REG_SZ
, (const BYTE
*)empty
, len
);
2241 RegCloseKey(network
);
2244 RegCloseKey(user_profile
);
2251 /*****************************************************************
2252 * WNetUseConnectionW [MPR.@]
2254 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
2255 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
2257 struct use_connection_context ctxt
;
2259 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
2260 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
2261 accessname
, buffer_size
, result
);
2263 ctxt
.hwndOwner
= hwndOwner
;
2264 ctxt
.resource
= resource
;
2265 ctxt
.resourceA
= NULL
;
2266 ctxt
.password
= (WCHAR
*)password
;
2267 ctxt
.userid
= (WCHAR
*)userid
;
2269 ctxt
.accessname
= accessname
;
2270 ctxt
.buffer_size
= buffer_size
;
2271 ctxt
.result
= result
;
2272 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
2273 ctxt
.set_accessname
= use_connection_set_accessnameW
;
2275 return wnet_use_connection(&ctxt
);
2278 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2280 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
2285 len
= WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, NULL
, 0, NULL
, NULL
) - 1;
2287 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
2289 if (++len
> *ctxt
->buffer_size
)
2291 *ctxt
->buffer_size
= len
;
2292 return ERROR_MORE_DATA
;
2296 ctxt
->accessname
= NULL
;
2298 return ERROR_SUCCESS
;
2301 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2303 char *accessname
= ctxt
->accessname
;
2306 WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, accessname
, *ctxt
->buffer_size
, NULL
, NULL
);
2308 *ctxt
->result
= CONNECT_LOCALDRIVE
;
2311 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
2314 static LPWSTR
strdupAtoW( LPCSTR str
)
2319 if (!str
) return NULL
;
2320 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
2321 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2322 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
2326 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
2328 resourceW
->dwScope
= resourceA
->dwScope
;
2329 resourceW
->dwType
= resourceA
->dwType
;
2330 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
2331 resourceW
->dwUsage
= resourceA
->dwUsage
;
2332 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
2333 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
2334 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
2335 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
2338 static void free_netresourceW( NETRESOURCEW
*resource
)
2340 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
2341 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
2342 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
2343 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
2346 /*****************************************************************
2347 * WNetUseConnectionA [MPR.@]
2349 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
2350 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
2351 DWORD
*buffer_size
, DWORD
*result
)
2353 struct use_connection_context ctxt
;
2354 NETRESOURCEW resourceW
;
2357 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
2358 accessname
, buffer_size
, result
);
2360 netresource_a_to_w(resource
, &resourceW
);
2362 ctxt
.hwndOwner
= hwndOwner
;
2363 ctxt
.resource
= &resourceW
;
2364 ctxt
.resourceA
= resource
;
2365 ctxt
.password
= strdupAtoW(password
);
2366 ctxt
.userid
= strdupAtoW(userid
);
2368 ctxt
.accessname
= accessname
;
2369 ctxt
.buffer_size
= buffer_size
;
2370 ctxt
.result
= result
;
2371 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
2372 ctxt
.set_accessname
= use_connection_set_accessnameA
;
2374 ret
= wnet_use_connection(&ctxt
);
2376 free_netresourceW(&resourceW
);
2377 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
2378 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
2383 /*********************************************************************
2384 * WNetCancelConnectionA [MPR.@]
2386 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
2388 return WNetCancelConnection2A(lpName
, 0, fForce
);
2391 /*********************************************************************
2392 * WNetCancelConnectionW [MPR.@]
2394 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
2396 return WNetCancelConnection2W(lpName
, 0, fForce
);
2399 /*********************************************************************
2400 * WNetCancelConnection2A [MPR.@]
2402 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2405 WCHAR
* name
= strdupAtoW(lpName
);
2407 return ERROR_NOT_CONNECTED
;
2409 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
2410 HeapFree(GetProcessHeap(), 0, name
);
2415 /*********************************************************************
2416 * WNetCancelConnection2W [MPR.@]
2418 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2420 DWORD ret
= WN_NO_NETWORK
;
2423 if (providerTable
!= NULL
)
2425 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2427 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2428 WNNC_CON_CANCELCONNECTION
)
2430 if (providerTable
->table
[index
].cancelConnection
)
2431 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
2433 ret
= WN_NO_NETWORK
;
2434 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
2440 if (ret
== WN_SUCCESS
&& dwFlags
& CONNECT_UPDATE_PROFILE
)
2444 /* FIXME: Only remove it if that's a drive letter */
2445 if (iswalpha(lpName
[0]) && lpName
[1] == ':' &&
2446 RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2448 WCHAR subkey
[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', lpName
[0], 0};
2450 RegDeleteKeyW(user_profile
, subkey
);
2452 RegCloseKey(user_profile
);
2459 /*****************************************************************
2460 * WNetRestoreConnectionA [MPR.@]
2462 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
2464 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
2466 SetLastError(WN_NO_NETWORK
);
2467 return WN_NO_NETWORK
;
2470 /*****************************************************************
2471 * WNetRestoreConnectionW [MPR.@]
2473 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
2475 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
2477 SetLastError(WN_NO_NETWORK
);
2478 return WN_NO_NETWORK
;
2481 /**************************************************************************
2482 * WNetGetConnectionA [MPR.@]
2485 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2486 * - WN_NOT_CONNECTED drive is a local drive
2487 * - WN_MORE_DATA buffer isn't big enough
2488 * - WN_SUCCESS success (net path in buffer)
2490 * FIXME: need to test return values under different errors
2492 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
2493 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
2498 ret
= WN_BAD_POINTER
;
2499 else if (!lpBufferSize
)
2500 ret
= WN_BAD_POINTER
;
2501 else if (!lpRemoteName
&& *lpBufferSize
)
2502 ret
= WN_BAD_POINTER
;
2505 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
2509 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2513 WCHAR wideRemoteStatic
[MAX_PATH
];
2514 DWORD wideRemoteSize
= ARRAY_SIZE(wideRemoteStatic
);
2516 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
2518 /* try once without memory allocation */
2519 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
2521 if (ret
== WN_SUCCESS
)
2523 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2524 -1, NULL
, 0, NULL
, NULL
);
2526 if (len
<= *lpBufferSize
)
2528 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
2529 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2534 *lpBufferSize
= len
;
2538 else if (ret
== WN_MORE_DATA
)
2540 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2541 wideRemoteSize
* sizeof(WCHAR
));
2545 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2547 if (ret
== WN_SUCCESS
)
2549 if (len
<= *lpBufferSize
)
2551 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2552 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2557 *lpBufferSize
= len
;
2561 HeapFree(GetProcessHeap(), 0, wideRemote
);
2564 ret
= WN_OUT_OF_MEMORY
;
2566 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2569 ret
= WN_OUT_OF_MEMORY
;
2572 ret
= WN_BAD_LOCALNAME
;
2576 TRACE("Returning %d\n", ret
);
2580 /* find the network connection for a given drive; helper for WNetGetConnection */
2581 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2585 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2587 DWORD ret
= WN_NOT_CONNECTED
;
2588 DWORD bytes_returned
;
2590 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2591 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2592 0, 0 )) == INVALID_HANDLE_VALUE
)
2594 ERR( "failed to open mount manager err %u\n", GetLastError() );
2597 memset( data
, 0, sizeof(*data
) );
2598 data
->letter
= letter
;
2599 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2600 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2602 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2605 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2608 mount_point
[0] = '\\';
2609 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2611 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2619 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2627 DWORD ret
= WN_NO_NETWORK
;
2629 WCHAR local
[3] = {letter
, ':', 0};
2631 if (providerTable
!= NULL
)
2633 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2635 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2636 WNNC_CON_GETCONNECTIONS
)
2638 if (providerTable
->table
[index
].getConnection
)
2639 ret
= providerTable
->table
[index
].getConnection(
2640 local
, remote
, size
);
2642 ret
= WN_NO_NETWORK
;
2643 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2654 /**************************************************************************
2655 * WNetGetConnectionW [MPR.@]
2657 * FIXME: need to test return values under different errors
2659 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2660 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2664 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2668 ret
= WN_BAD_POINTER
;
2669 else if (!lpBufferSize
)
2670 ret
= WN_BAD_POINTER
;
2671 else if (!lpRemoteName
&& *lpBufferSize
)
2672 ret
= WN_BAD_POINTER
;
2673 else if (!lpLocalName
[0])
2674 ret
= WN_BAD_LOCALNAME
;
2677 if (lpLocalName
[1] == ':')
2679 switch(GetDriveTypeW(lpLocalName
))
2682 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2684 case DRIVE_REMOVABLE
:
2687 TRACE("file is local\n");
2688 ret
= WN_NOT_CONNECTED
;
2691 ret
= WN_BAD_LOCALNAME
;
2695 ret
= WN_BAD_LOCALNAME
;
2699 TRACE("Returning %d\n", ret
);
2703 /**************************************************************************
2704 * WNetSetConnectionA [MPR.@]
2706 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2709 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2711 SetLastError(WN_NO_NETWORK
);
2712 return WN_NO_NETWORK
;
2715 /**************************************************************************
2716 * WNetSetConnectionW [MPR.@]
2718 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2721 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2723 SetLastError(WN_NO_NETWORK
);
2724 return WN_NO_NETWORK
;
2727 /*****************************************************************
2728 * WNetGetUniversalNameA [MPR.@]
2730 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2731 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2735 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2736 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2738 switch (dwInfoLevel
)
2740 case UNIVERSAL_NAME_INFO_LEVEL
:
2742 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2744 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2746 err
= ERROR_NOT_CONNECTED
;
2750 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2751 if (*lpBufferSize
< size
)
2756 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2757 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2761 case REMOTE_NAME_INFO_LEVEL
:
2762 err
= WN_NOT_CONNECTED
;
2774 /*****************************************************************
2775 * WNetGetUniversalNameW [MPR.@]
2777 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2778 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2782 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2783 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2785 switch (dwInfoLevel
)
2787 case UNIVERSAL_NAME_INFO_LEVEL
:
2789 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2791 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2793 err
= ERROR_NOT_CONNECTED
;
2797 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2798 if (*lpBufferSize
< size
)
2800 *lpBufferSize
= size
;
2804 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2805 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2809 case REMOTE_NAME_INFO_LEVEL
:
2810 err
= WN_NO_NETWORK
;
2818 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2822 /*****************************************************************
2823 * WNetClearConnections [MPR.@]
2825 DWORD WINAPI
WNetClearConnections ( HWND owner
)
2829 DWORD ret
, size
, count
;
2830 NETRESOURCEW
* resources
, * iter
;
2832 ret
= WNetOpenEnumW(RESOURCE_CONNECTED
, RESOURCETYPE_ANY
, 0, NULL
, &connected
);
2833 if (ret
!= WN_SUCCESS
)
2835 if (ret
!= WN_NO_NETWORK
)
2840 /* Means no provider, then, clearing is OK */
2845 resources
= HeapAlloc(GetProcessHeap(), 0, size
);
2848 WNetCloseEnum(connected
);
2849 return WN_OUT_OF_MEMORY
;
2857 memset(resources
, 0, size
);
2858 ret
= WNetEnumResourceW(connected
, &count
, resources
, &size
);
2859 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2861 for (iter
= resources
; count
; count
--, iter
++)
2863 if (iter
->lpLocalName
&& iter
->lpLocalName
[0])
2864 connection
= iter
->lpLocalName
;
2866 connection
= iter
->lpRemoteName
;
2868 WNetCancelConnection2W(connection
, 0, TRUE
);
2875 HeapFree(GetProcessHeap(), 0, resources
);
2876 WNetCloseEnum(connected
);
2886 /**************************************************************************
2887 * WNetGetUserA [MPR.@]
2889 * FIXME: we should not return ourselves, but the owner of the drive lpName
2891 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2893 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2894 return GetLastError();
2897 /*****************************************************************
2898 * WNetGetUserW [MPR.@]
2900 * FIXME: we should not return ourselves, but the owner of the drive lpName
2902 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2904 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2905 return GetLastError();
2908 /*********************************************************************
2909 * WNetConnectionDialog [MPR.@]
2911 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2913 CONNECTDLGSTRUCTW conn_dlg
;
2914 NETRESOURCEW net_res
;
2916 ZeroMemory(&conn_dlg
, sizeof(conn_dlg
));
2917 ZeroMemory(&net_res
, sizeof(net_res
));
2919 conn_dlg
.cbStructure
= sizeof(conn_dlg
);
2920 conn_dlg
.lpConnRes
= &net_res
;
2921 conn_dlg
.hwndOwner
= hwnd
;
2922 net_res
.dwType
= dwType
;
2924 return WNetConnectionDialog1W(&conn_dlg
);
2927 /*********************************************************************
2928 * WNetConnectionDialog1A [MPR.@]
2930 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2932 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2934 SetLastError(WN_NO_NETWORK
);
2935 return WN_NO_NETWORK
;
2938 /*********************************************************************
2939 * WNetConnectionDialog1W [MPR.@]
2941 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2943 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2945 SetLastError(WN_NO_NETWORK
);
2946 return WN_NO_NETWORK
;
2949 /*********************************************************************
2950 * WNetDisconnectDialog [MPR.@]
2952 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2956 HMODULE hDll
= LoadLibraryW(L
"netplwiz.dll");
2957 static BOOL (WINAPI
*pSHDisconnectNetDrives
)(PVOID
);
2958 pSHDisconnectNetDrives
= (VOID
*) GetProcAddress(hDll
, "SHDisconnectNetDrives");
2960 dwRet
= pSHDisconnectNetDrives(NULL
);
2965 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2967 SetLastError(WN_NO_NETWORK
);
2968 return WN_NO_NETWORK
;
2972 /*********************************************************************
2973 * WNetDisconnectDialog1A [MPR.@]
2975 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2977 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2979 SetLastError(WN_NO_NETWORK
);
2980 return WN_NO_NETWORK
;
2983 /*********************************************************************
2984 * WNetDisconnectDialog1W [MPR.@]
2986 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2988 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2990 SetLastError(WN_NO_NETWORK
);
2991 return WN_NO_NETWORK
;
2994 /*********************************************************************
2995 * WNetGetLastErrorA [MPR.@]
2997 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2998 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2999 LPSTR lpNameBuf
, DWORD nNameBufSize
)
3001 FIXME( "(%p, %p, %d, %p, %d): stub\n",
3002 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
3004 SetLastError(WN_NO_NETWORK
);
3005 return WN_NO_NETWORK
;
3008 /*********************************************************************
3009 * WNetGetLastErrorW [MPR.@]
3011 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
3012 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
3013 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
3015 FIXME( "(%p, %p, %d, %p, %d): stub\n",
3016 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
3018 SetLastError(WN_NO_NETWORK
);
3019 return WN_NO_NETWORK
;
3022 /*********************************************************************
3023 * WNetGetNetworkInformationA [MPR.@]
3025 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
3026 LPNETINFOSTRUCT lpNetInfoStruct
)
3030 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
3033 ret
= WN_BAD_POINTER
;
3038 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
3041 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3045 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
3047 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
3048 HeapFree(GetProcessHeap(), 0, wideProvider
);
3051 ret
= WN_OUT_OF_MEMORY
;
3054 ret
= GetLastError();
3058 TRACE("Returning %d\n", ret
);
3062 /*********************************************************************
3063 * WNetGetNetworkInformationW [MPR.@]
3065 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
3066 LPNETINFOSTRUCT lpNetInfoStruct
)
3070 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
3073 ret
= WN_BAD_POINTER
;
3074 else if (!lpNetInfoStruct
)
3075 ret
= WN_BAD_POINTER
;
3076 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
3080 if (providerTable
&& providerTable
->numProviders
)
3082 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
3084 if (providerIndex
!= BAD_PROVIDER_INDEX
)
3086 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
3087 lpNetInfoStruct
->dwProviderVersion
=
3088 providerTable
->table
[providerIndex
].dwSpecVersion
;
3089 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
3090 lpNetInfoStruct
->dwCharacteristics
= 0;
3091 lpNetInfoStruct
->dwHandle
= 0;
3092 lpNetInfoStruct
->wNetType
=
3093 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
3094 lpNetInfoStruct
->dwPrinters
= -1;
3095 lpNetInfoStruct
->dwDrives
= -1;
3099 ret
= WN_BAD_PROVIDER
;
3102 ret
= WN_NO_NETWORK
;
3106 TRACE("Returning %d\n", ret
);
3110 /*****************************************************************
3111 * WNetGetProviderNameA [MPR.@]
3113 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
3114 LPSTR lpProvider
, LPDWORD lpBufferSize
)
3118 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
3122 ret
= WN_BAD_POINTER
;
3123 else if (!lpBufferSize
)
3124 ret
= WN_BAD_POINTER
;
3131 ret
= WN_NO_NETWORK
;
3132 for (i
= 0; i
< providerTable
->numProviders
&&
3133 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
3136 if (i
< providerTable
->numProviders
)
3138 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
3139 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
3141 if (*lpBufferSize
< sizeNeeded
)
3143 *lpBufferSize
= sizeNeeded
;
3148 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
3149 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
3151 /* FIXME: is *lpBufferSize set to the number of characters
3157 ret
= WN_NO_NETWORK
;
3161 TRACE("Returning %d\n", ret
);
3165 /*****************************************************************
3166 * WNetGetProviderNameW [MPR.@]
3168 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
3169 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
3173 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
3177 ret
= WN_BAD_POINTER
;
3178 else if (!lpBufferSize
)
3179 ret
= WN_BAD_POINTER
;
3186 ret
= WN_NO_NETWORK
;
3187 for (i
= 0; i
< providerTable
->numProviders
&&
3188 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
3191 if (i
< providerTable
->numProviders
)
3193 DWORD sizeNeeded
= lstrlenW(providerTable
->table
[i
].name
) + 1;
3195 if (*lpBufferSize
< sizeNeeded
)
3197 *lpBufferSize
= sizeNeeded
;
3202 lstrcpyW(lpProvider
, providerTable
->table
[i
].name
);
3204 /* FIXME: is *lpBufferSize set to the number of characters
3210 ret
= WN_NO_NETWORK
;
3214 TRACE("Returning %d\n", ret
);