4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
7 * Copyright 2016 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"
36 #include "wine/unicode.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(mpr
);
42 /* Data structures representing network service providers. Assumes only one
43 * thread creates them, and that they are constant for the life of the process
44 * (and therefore doesn't synchronize access).
45 * FIXME: only basic provider data and enumeration-related data are implemented
46 * so far, need to implement the rest too.
48 typedef struct _WNetProvider
56 PF_NPOpenEnum openEnum
;
57 PF_NPEnumResource enumResource
;
58 PF_NPCloseEnum closeEnum
;
59 PF_NPGetResourceInformation getResourceInformation
;
60 PF_NPAddConnection addConnection
;
61 PF_NPAddConnection3 addConnection3
;
62 PF_NPCancelConnection cancelConnection
;
64 PF_NPGetConnection getConnection
;
66 } WNetProvider
, *PWNetProvider
;
68 typedef struct _WNetProviderTable
73 WNetProvider table
[1];
74 } WNetProviderTable
, *PWNetProviderTable
;
77 #define WNET_ENUMERATOR_TYPE_NULL 0
78 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
79 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
80 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
81 #define WNET_ENUMERATOR_TYPE_CONNECTED 4
83 #define WNET_ENUMERATOR_TYPE_GLOBAL 0
84 #define WNET_ENUMERATOR_TYPE_PROVIDER 1
85 #define WNET_ENUMERATOR_TYPE_CONTEXT 2
86 #define WNET_ENUMERATOR_TYPE_CONNECTED 3
87 #define WNET_ENUMERATOR_TYPE_REMEMBERED 4
91 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
92 * the enumeration; it represents one of the following types:
93 * - a 'null' enumeration, one that contains no members
94 * - a global enumeration, one that's executed across all providers
95 * - a provider-specific enumeration, one that's only executed by a single
97 * - a context enumeration. I know this contradicts what I just said about
98 * there being no correspondence between the scope and the type, but it's
99 * necessary for the special case that a "Entire Network" entry needs to
100 * be enumerated in an enumeration of the context scope. Thus an enumeration
101 * of the context scope results in a context type enumerator, which morphs
102 * into a global enumeration (so the enumeration continues across all
106 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
107 * the enumeration; it represents one of the following types:
108 * - a global enumeration, one that's executed across all providers
109 * - a provider-specific enumeration, one that's only executed by a single
111 * - a context enumeration. I know this contradicts what I just said about
112 * there being no correspondence between the scope and the type, but it's
113 * necessary for the special case that a "Entire Network" entry needs to
114 * be enumerated in an enumeration of the context scope. Thus an enumeration
115 * of the context scope results in a context type enumerator, which morphs
116 * into a global enumeration (so the enumeration continues across all
118 * - a remembered enumeration, not related to providers themselves, but it
119 * is a registry enumeration for saved connections
122 typedef struct _WNetEnumerator
143 } WNetEnumerator
, *PWNetEnumerator
;
145 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
147 /* Returns an index (into the global WNetProviderTable) of the provider with
148 * the given name, or BAD_PROVIDER_INDEX if not found.
150 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
152 static PWNetProviderTable providerTable
;
155 * Global provider table functions
158 static void _tryLoadProvider(PCWSTR provider
)
160 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
161 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
162 'S','e','r','v','i','c','e','s','\\',0 };
163 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
164 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
165 WCHAR serviceName
[MAX_PATH
];
168 TRACE("%s\n", debugstr_w(provider
));
169 snprintfW(serviceName
, sizeof(serviceName
) / sizeof(WCHAR
), serviceFmt
,
170 servicePrefix
, provider
);
171 serviceName
[sizeof(serviceName
) / sizeof(WCHAR
) - 1] = '\0';
172 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
175 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
177 WCHAR providerPath
[MAX_PATH
];
178 DWORD type
, size
= sizeof(providerPath
);
180 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
181 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
183 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
186 if (type
== REG_EXPAND_SZ
)
188 WCHAR path
[MAX_PATH
];
189 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
193 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
196 name
= HeapAlloc(GetProcessHeap(), 0, size
);
197 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
198 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
200 HeapFree(GetProcessHeap(), 0, name
);
206 HMODULE hLib
= LoadLibraryW(providerPath
);
210 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
212 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
214 TRACE("loaded lib %p\n", hLib
);
218 PWNetProvider provider
=
219 &providerTable
->table
[providerTable
->numProviders
];
221 provider
->hLib
= hLib
;
222 provider
->name
= name
;
223 TRACE("name is %s\n", debugstr_w(name
));
224 provider
->getCaps
= getCaps
;
225 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
226 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
227 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
228 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
229 if (provider
->dwEnumScopes
)
231 TRACE("supports enumeration\n");
232 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
233 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
234 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
235 TRACE("NPEnumResource %p\n", provider
->enumResource
);
236 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
237 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
238 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
239 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
240 if (!provider
->openEnum
||
241 !provider
->enumResource
||
242 !provider
->closeEnum
)
244 provider
->openEnum
= NULL
;
245 provider
->enumResource
= NULL
;
246 provider
->closeEnum
= NULL
;
247 provider
->dwEnumScopes
= 0;
248 WARN("Couldn't load enumeration functions\n");
251 connectCap
= getCaps(WNNC_CONNECTION
);
252 if (connectCap
& WNNC_CON_ADDCONNECTION
)
253 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
254 if (connectCap
& WNNC_CON_ADDCONNECTION3
)
255 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
256 if (connectCap
& WNNC_CON_CANCELCONNECTION
)
257 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
259 if (connectCap
& WNNC_CON_GETCONNECTIONS
)
260 provider
->getConnection
= MPR_GETPROC(NPGetConnection
);
262 TRACE("NPAddConnection %p\n", provider
->addConnection
);
263 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
264 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
265 providerTable
->numProviders
++;
269 WARN("Provider %s didn't export NPGetCaps\n",
270 debugstr_w(provider
));
271 HeapFree(GetProcessHeap(), 0, name
);
279 WARN("Couldn't load library %s for provider %s\n",
280 debugstr_w(providerPath
), debugstr_w(provider
));
281 HeapFree(GetProcessHeap(), 0, name
);
286 WARN("Couldn't get provider name for provider %s\n",
287 debugstr_w(provider
));
291 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
295 WARN("Couldn't open service key for provider %s\n",
296 debugstr_w(provider
));
300 static void _restoreSavedConnection(HKEY connection
, WCHAR
* local
)
303 DWORD type
, prov
, index
, size
;
305 net
.lpProvider
= NULL
;
306 net
.lpRemoteName
= NULL
;
307 net
.lpLocalName
= NULL
;
309 TRACE("Restoring: %S\n", local
);
311 size
= sizeof(DWORD
);
312 if (RegQueryValueExW(connection
, L
"ConnectionType", NULL
, &type
, (BYTE
*)&net
.dwType
, &size
) != ERROR_SUCCESS
)
315 if (type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
318 if (RegQueryValueExW(connection
, L
"ProviderName", NULL
, &type
, NULL
, &size
) != ERROR_SUCCESS
)
324 net
.lpProvider
= HeapAlloc(GetProcessHeap(), 0, size
);
328 if (RegQueryValueExW(connection
, L
"ProviderName", NULL
, NULL
, (BYTE
*)net
.lpProvider
, &size
) != ERROR_SUCCESS
)
331 size
= sizeof(DWORD
);
332 if (RegQueryValueExW(connection
, L
"ProviderType", NULL
, &type
, (BYTE
*)&prov
, &size
) != ERROR_SUCCESS
)
335 if (type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
338 index
= _findProviderIndexW(net
.lpProvider
);
339 if (index
== BAD_PROVIDER_INDEX
)
342 if (providerTable
->table
[index
].dwNetType
!= prov
)
345 if (RegQueryValueExW(connection
, L
"RemotePath", NULL
, &type
, NULL
, &size
) != ERROR_SUCCESS
)
351 net
.lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, size
);
352 if (!net
.lpRemoteName
)
355 if (RegQueryValueExW(connection
, L
"RemotePath", NULL
, NULL
, (BYTE
*)net
.lpRemoteName
, &size
) != ERROR_SUCCESS
)
358 size
= strlenW(local
);
359 net
.lpLocalName
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
) + 2 * sizeof(WCHAR
));
360 if (!net
.lpLocalName
)
363 strcpyW(net
.lpLocalName
, local
);
364 net
.lpLocalName
[size
] = ':';
365 net
.lpLocalName
[size
+ 1] = 0;
367 TRACE("Attempting connection\n");
369 WNetAddConnection2W(&net
, NULL
, NULL
, 0);
372 HeapFree(GetProcessHeap(), 0, net
.lpProvider
);
373 HeapFree(GetProcessHeap(), 0, net
.lpRemoteName
);
374 HeapFree(GetProcessHeap(), 0, net
.lpLocalName
);
378 void wnetInit(HINSTANCE hInstDll
)
380 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
381 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
382 'C','o','n','t','r','o','l','\\',
383 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
384 'O','r','d','e','r',0 };
385 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
386 'O','r','d','e','r',0 };
389 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
394 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
397 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
403 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
404 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
409 TRACE("provider order is %s\n", debugstr_w(providers
));
410 /* first count commas as a heuristic for how many to
411 * allocate space for */
412 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
414 ptr
= strchrW(ptr
, ',');
421 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
422 sizeof(WNetProviderTable
)
423 + (numToAllocate
- 1) * sizeof(WNetProvider
));
427 int entireNetworkLen
;
428 LPCWSTR stringresource
;
430 entireNetworkLen
= LoadStringW(hInstDll
,
431 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
432 providerTable
->entireNetwork
= HeapAlloc(
433 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
435 if (providerTable
->entireNetwork
)
437 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
438 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
440 providerTable
->numAllocated
= numToAllocate
;
441 for (ptr
= providers
; ptr
; )
444 ptr
= strchrW(ptr
, ',');
447 _tryLoadProvider(ptrPrev
);
451 HeapFree(GetProcessHeap(), 0, providers
);
462 if (RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
465 WCHAR subkey
[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
467 if (RegOpenKeyExW(user_profile
, subkey
, 0, KEY_READ
, &network
) == ERROR_SUCCESS
)
471 TRACE("Enumerating remembered connections\n");
473 if (RegQueryInfoKey(network
, NULL
, NULL
, NULL
, &max
, &size
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
477 TRACE("There are %lu connections\n", max
);
479 local
= HeapAlloc(GetProcessHeap(), 0, (size
+ 1) * sizeof(WCHAR
));
484 for (index
= 0; index
< max
; ++index
)
486 DWORD len
= size
+ 1;
489 TRACE("Trying connection %lu\n", index
);
491 if (RegEnumKeyExW(network
, index
, local
, &len
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
494 TRACE("It is %S\n", local
);
496 if (RegOpenKeyExW(network
, local
, 0, KEY_READ
, &connection
) != ERROR_SUCCESS
)
499 _restoreSavedConnection(connection
, local
);
500 RegCloseKey(connection
);
503 HeapFree(GetProcessHeap(), 0, local
);
507 RegCloseKey(network
);
510 RegCloseKey(user_profile
);
522 for (i
= 0; i
< providerTable
->numProviders
; i
++)
524 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
525 FreeModule(providerTable
->table
[i
].hLib
);
527 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
528 HeapFree(GetProcessHeap(), 0, providerTable
);
529 providerTable
= NULL
;
533 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
535 DWORD ret
= BAD_PROVIDER_INDEX
;
537 if (providerTable
&& providerTable
->numProviders
)
541 for (i
= 0; i
< providerTable
->numProviders
&&
542 ret
== BAD_PROVIDER_INDEX
; i
++)
543 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
553 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
559 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
565 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
566 if (lpNet
->lpRemoteName
)
568 len
= strlenW(lpNet
->lpRemoteName
) + 1;
569 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
570 if (ret
->lpRemoteName
)
571 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
580 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
584 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
585 HeapFree(GetProcessHeap(), 0, lpNet
);
590 static PWNetEnumerator
_createNullEnumerator(void)
592 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
593 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
596 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
601 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
602 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
604 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
605 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
609 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
610 ret
->dwScope
= dwScope
;
611 ret
->dwType
= dwType
;
612 ret
->dwUsage
= dwUsage
;
613 ret
->specific
.net
= _copyNetResourceForEnumW(lpNet
);
618 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
619 DWORD dwUsage
, DWORD index
, HANDLE handle
)
623 if (!providerTable
|| index
>= providerTable
->numProviders
)
627 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
630 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
631 ret
->providerIndex
= index
;
632 ret
->dwScope
= dwScope
;
633 ret
->dwType
= dwType
;
634 ret
->dwUsage
= dwUsage
;
635 ret
->handle
= handle
;
641 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
644 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
645 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
649 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
650 ret
->dwScope
= dwScope
;
651 ret
->dwType
= dwType
;
652 ret
->dwUsage
= dwUsage
;
657 static PWNetEnumerator
_createConnectedEnumerator(DWORD dwScope
, DWORD dwType
,
660 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
663 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONNECTED
;
664 ret
->dwScope
= dwScope
;
665 ret
->dwType
= dwType
;
666 ret
->dwUsage
= dwUsage
;
667 ret
->specific
.handles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HANDLE
) * providerTable
->numProviders
);
668 if (!ret
->specific
.handles
)
670 HeapFree(GetProcessHeap(), 0, ret
);
678 static PWNetEnumerator
_createRememberedEnumerator(DWORD dwScope
, DWORD dwType
,
681 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
684 ret
->enumType
= WNET_ENUMERATOR_TYPE_REMEMBERED
;
685 ret
->dwScope
= dwScope
;
686 ret
->dwType
= dwType
;
687 ret
->specific
.remembered
.registry
= remembered
;
693 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
694 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
695 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
696 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
697 * if not all members of the array could be thunked, and something else on
700 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
701 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
703 DWORD i
, numToThunk
, totalBytes
, ret
;
707 return WN_BAD_POINTER
;
709 return WN_BAD_POINTER
;
713 return WN_BAD_POINTER
;
715 return WN_BAD_POINTER
;
717 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
719 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
721 totalBytes
+= sizeof(NETRESOURCEA
);
722 if (lpNet
->lpLocalName
)
723 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
724 -1, NULL
, 0, NULL
, NULL
);
725 if (lpNet
->lpRemoteName
)
726 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
727 -1, NULL
, 0, NULL
, NULL
);
728 if (lpNet
->lpComment
)
729 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
730 -1, NULL
, 0, NULL
, NULL
);
731 if (lpNet
->lpProvider
)
732 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
733 -1, NULL
, 0, NULL
, NULL
);
734 if (totalBytes
< *lpBufferSize
)
737 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
738 for (i
= 0; i
< numToThunk
; i
++)
740 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
741 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
743 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
744 /* lie about string lengths, we already verified how many
745 * we have space for above
747 if (lpNetIn
->lpLocalName
)
749 lpNetOut
->lpLocalName
= strNext
;
750 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
751 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
753 if (lpNetIn
->lpRemoteName
)
755 lpNetOut
->lpRemoteName
= strNext
;
756 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
757 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
759 if (lpNetIn
->lpComment
)
761 lpNetOut
->lpComment
= strNext
;
762 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
763 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
765 if (lpNetIn
->lpProvider
)
767 lpNetOut
->lpProvider
= strNext
;
768 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
769 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
772 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
773 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
778 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
779 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
780 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
781 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
782 * if not all members of the array could be thunked, and something else on
785 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
786 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
788 DWORD i
, numToThunk
, totalBytes
, ret
;
792 return WN_BAD_POINTER
;
794 return WN_BAD_POINTER
;
798 return WN_BAD_POINTER
;
800 return WN_BAD_POINTER
;
802 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
804 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
806 totalBytes
+= sizeof(NETRESOURCEW
);
807 if (lpNet
->lpLocalName
)
808 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
809 -1, NULL
, 0) * sizeof(WCHAR
);
810 if (lpNet
->lpRemoteName
)
811 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
812 -1, NULL
, 0) * sizeof(WCHAR
);
813 if (lpNet
->lpComment
)
814 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
815 -1, NULL
, 0) * sizeof(WCHAR
);
816 if (lpNet
->lpProvider
)
817 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
818 -1, NULL
, 0) * sizeof(WCHAR
);
819 if (totalBytes
< *lpBufferSize
)
822 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
823 for (i
= 0; i
< numToThunk
; i
++)
825 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
826 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
828 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
829 /* lie about string lengths, we already verified how many
830 * we have space for above
832 if (lpNetIn
->lpLocalName
)
834 lpNetOut
->lpLocalName
= strNext
;
835 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
836 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
838 if (lpNetIn
->lpRemoteName
)
840 lpNetOut
->lpRemoteName
= strNext
;
841 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
842 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
844 if (lpNetIn
->lpComment
)
846 lpNetOut
->lpComment
= strNext
;
847 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
848 -1, lpNetOut
->lpComment
, *lpBufferSize
);
850 if (lpNetIn
->lpProvider
)
852 lpNetOut
->lpProvider
= strNext
;
853 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
854 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
857 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
858 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
863 /*********************************************************************
864 * WNetOpenEnumA [MPR.@]
866 * See comments for WNetOpenEnumW.
868 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
869 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
873 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
874 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
877 ret
= WN_BAD_POINTER
;
878 else if (!providerTable
|| providerTable
->numProviders
== 0)
887 LPNETRESOURCEW lpNetWide
= NULL
;
889 DWORD size
= sizeof(buf
), count
= 1;
890 BOOL allocated
= FALSE
;
892 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
893 if (ret
== WN_MORE_DATA
)
895 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
899 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
904 ret
= WN_OUT_OF_MEMORY
;
906 else if (ret
== WN_SUCCESS
)
907 lpNetWide
= (LPNETRESOURCEW
)buf
;
908 if (ret
== WN_SUCCESS
)
909 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
912 HeapFree(GetProcessHeap(), 0, lpNetWide
);
915 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
919 TRACE("Returning %d\n", ret
);
923 /*********************************************************************
924 * WNetOpenEnumW [MPR.@]
926 * Network enumeration has way too many parameters, so I'm not positive I got
927 * them right. What I've got so far:
929 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
930 * all the network providers should be enumerated.
932 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
933 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
934 * lpProvider is set, all the network providers should be enumerated.
935 * (This means the enumeration is a list of network providers, not that the
936 * enumeration is passed on to the providers.)
938 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
939 * resource matches the "Entire Network" resource (no remote name, no
940 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
941 * enumeration is done on every network provider.
943 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
944 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
945 * only to the given network provider.
947 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
948 * no lpProvider is set, enumeration will be tried on every network provider,
949 * in the order in which they're loaded.
951 * - The LPNETRESOURCE should be disregarded for scopes besides
952 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
953 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
955 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
956 * resource in the enumerated list, as well as any machines in your
957 * workgroup. The machines in your workgroup come from doing a
958 * RESOURCE_CONTEXT enumeration of every Network Provider.
960 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
961 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
965 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
966 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
969 ret
= WN_BAD_POINTER
;
970 else if (!providerTable
|| providerTable
->numProviders
== 0)
979 case RESOURCE_GLOBALNET
:
982 if (lpNet
->lpProvider
)
984 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
986 if (index
!= BAD_PROVIDER_INDEX
)
988 if (providerTable
->table
[index
].openEnum
&&
989 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
992 PWSTR RemoteName
= lpNet
->lpRemoteName
;
994 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
995 RemoteName
&& !strcmpW(RemoteName
, lpNet
->lpProvider
))
996 lpNet
->lpRemoteName
= NULL
;
998 ret
= providerTable
->table
[index
].openEnum(
999 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
1000 if (ret
== WN_SUCCESS
)
1002 *lphEnum
= _createProviderEnumerator(
1003 dwScope
, dwType
, dwUsage
, index
, handle
);
1004 ret
= *lphEnum
? WN_SUCCESS
:
1008 lpNet
->lpRemoteName
= RemoteName
;
1011 ret
= WN_NOT_SUPPORTED
;
1014 ret
= WN_BAD_PROVIDER
;
1016 else if (lpNet
->lpRemoteName
)
1018 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
1019 dwType
, dwUsage
, lpNet
);
1020 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1024 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
1025 providerTable
->entireNetwork
))
1027 /* comment matches the "Entire Network", enumerate
1028 * global scope of every provider
1030 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
1031 dwType
, dwUsage
, lpNet
);
1035 /* this is the same as not having passed lpNet */
1036 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
1037 dwType
, dwUsage
, NULL
);
1039 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1044 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
1046 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1049 case RESOURCE_CONTEXT
:
1050 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
1051 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1053 case RESOURCE_CONNECTED
:
1054 *lphEnum
= _createConnectedEnumerator(dwScope
, dwType
, dwUsage
);
1055 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1057 case RESOURCE_REMEMBERED
:
1059 *lphEnum
= _createNullEnumerator();
1060 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1063 HKEY remembered
, user_profile
;
1065 ret
= WN_OUT_OF_MEMORY
;
1066 if (RegOpenCurrentUser(KEY_READ
, &user_profile
) == ERROR_SUCCESS
)
1068 WCHAR subkey
[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
1070 if (RegOpenKeyExW(user_profile
, subkey
, 0, KEY_READ
, &remembered
) == ERROR_SUCCESS
)
1072 *lphEnum
= _createRememberedEnumerator(dwScope
, dwType
, remembered
);
1073 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1076 RegCloseKey(user_profile
);
1082 WARN("unknown scope 0x%08x\n", dwScope
);
1088 TRACE("Returning %d\n", ret
);
1092 /*********************************************************************
1093 * WNetEnumResourceA [MPR.@]
1095 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
1096 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1100 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1103 ret
= WN_BAD_POINTER
;
1105 ret
= WN_BAD_POINTER
;
1107 ret
= WN_BAD_POINTER
;
1108 else if (!lpBufferSize
)
1109 ret
= WN_BAD_POINTER
;
1110 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
1112 *lpBufferSize
= sizeof(NETRESOURCEA
);
1117 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
1118 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
1122 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
1124 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
1126 /* FIXME: this isn't necessarily going to work in the case of
1127 * WN_MORE_DATA, because our enumerator may have moved on to
1128 * the next provider. MSDN states that a large (16KB) buffer
1129 * size is the appropriate usage of this function, so
1130 * hopefully it won't be an issue.
1132 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
1133 lpBuffer
, lpBufferSize
);
1134 *lpcCount
= localCount
;
1136 HeapFree(GetProcessHeap(), 0, localBuffer
);
1139 ret
= WN_OUT_OF_MEMORY
;
1143 TRACE("Returning %d\n", ret
);
1147 static DWORD
_countProviderBytesW(PWNetProvider provider
)
1153 ret
= sizeof(NETRESOURCEW
);
1154 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
1161 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1162 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
1167 return WN_BAD_POINTER
;
1168 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1169 return WN_BAD_VALUE
;
1171 return WN_BAD_POINTER
;
1173 return WN_BAD_POINTER
;
1175 return WN_BAD_POINTER
;
1176 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
1177 return WN_MORE_DATA
;
1179 if (!providerTable
|| enumerator
->providerIndex
>=
1180 providerTable
->numProviders
)
1181 ret
= WN_NO_MORE_ENTRIES
;
1184 DWORD bytes
= 0, count
= 0, countLimit
, i
;
1185 LPNETRESOURCEW resource
;
1188 countLimit
= *lpcCount
== -1 ?
1189 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
1190 while (count
< countLimit
&& bytes
< *lpBufferSize
)
1192 DWORD bytesNext
= _countProviderBytesW(
1193 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
1195 if (bytes
+ bytesNext
< *lpBufferSize
)
1201 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
1202 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
1204 resource
->dwScope
= RESOURCE_GLOBALNET
;
1205 resource
->dwType
= RESOURCETYPE_ANY
;
1206 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
1207 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
1208 RESOURCEUSAGE_RESERVED
;
1209 resource
->lpLocalName
= NULL
;
1210 resource
->lpRemoteName
= strNext
;
1211 strcpyW(resource
->lpRemoteName
,
1212 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1213 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
1214 resource
->lpComment
= NULL
;
1215 resource
->lpProvider
= strNext
;
1216 strcpyW(resource
->lpProvider
,
1217 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1218 strNext
+= strlenW(resource
->lpProvider
) + 1;
1220 enumerator
->providerIndex
+= count
;
1222 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
1224 TRACE("Returning %d\n", ret
);
1228 /* Advances the enumerator (assumed to be a global enumerator) to the next
1229 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1230 * not open a handle with the next provider.
1231 * If the existing handle is NULL, may leave the enumerator unchanged, since
1232 * the current provider may support the desired scope.
1233 * If the existing handle is not NULL, closes it before moving on.
1234 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1235 * provider, and another error on failure.
1237 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
1240 return WN_BAD_POINTER
;
1241 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1242 return WN_BAD_VALUE
;
1243 if (!providerTable
|| enumerator
->providerIndex
>=
1244 providerTable
->numProviders
)
1245 return WN_NO_MORE_ENTRIES
;
1247 if (enumerator
->providerDone
)
1250 enumerator
->providerDone
= FALSE
;
1251 if (enumerator
->handle
)
1253 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1254 enumerator
->handle
);
1255 enumerator
->handle
= NULL
;
1256 enumerator
->providerIndex
++;
1258 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1259 dwEnum
= WNNC_ENUM_LOCAL
;
1260 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1261 dwEnum
= WNNC_ENUM_GLOBAL
;
1262 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1263 dwEnum
= WNNC_ENUM_CONTEXT
;
1264 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1265 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1266 & dwEnum
); enumerator
->providerIndex
++)
1269 return enumerator
->providerIndex
< providerTable
->numProviders
?
1270 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1273 /* "Passes through" call to the next provider that supports the enumeration
1275 * FIXME: if one call to a provider's enumerator succeeds while there's still
1276 * space in lpBuffer, I don't call to the next provider. The caller may not
1277 * expect that it should call EnumResourceW again with a return value of
1278 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1279 * may have to be moved around a bit, ick.
1281 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1282 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1287 return WN_BAD_POINTER
;
1288 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1289 return WN_BAD_VALUE
;
1291 return WN_BAD_POINTER
;
1293 return WN_BAD_POINTER
;
1295 return WN_BAD_POINTER
;
1296 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1297 return WN_MORE_DATA
;
1299 ret
= _globalEnumeratorAdvance(enumerator
);
1300 if (ret
== WN_SUCCESS
)
1302 ret
= providerTable
->table
[enumerator
->providerIndex
].
1303 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1304 enumerator
->dwUsage
, enumerator
->specific
.net
,
1305 &enumerator
->handle
);
1306 if (ret
== WN_SUCCESS
)
1308 ret
= providerTable
->table
[enumerator
->providerIndex
].
1309 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1311 if (ret
!= WN_MORE_DATA
)
1312 enumerator
->providerDone
= TRUE
;
1315 TRACE("Returning %d\n", ret
);
1319 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1320 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1325 return WN_BAD_POINTER
;
1326 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1327 return WN_BAD_VALUE
;
1329 return WN_BAD_POINTER
;
1331 return WN_BAD_POINTER
;
1333 return WN_BAD_POINTER
;
1334 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1335 return WN_MORE_DATA
;
1337 return WN_NO_NETWORK
;
1339 switch (enumerator
->dwScope
)
1341 case RESOURCE_GLOBALNET
:
1342 if (enumerator
->specific
.net
)
1343 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1344 lpBuffer
, lpBufferSize
);
1346 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1349 case RESOURCE_CONTEXT
:
1350 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1354 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1355 ret
= WN_NO_MORE_ENTRIES
;
1357 TRACE("Returning %d\n", ret
);
1361 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1362 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1365 return WN_BAD_POINTER
;
1366 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1367 return WN_BAD_VALUE
;
1368 if (!enumerator
->handle
)
1369 return WN_BAD_VALUE
;
1371 return WN_BAD_POINTER
;
1373 return WN_BAD_POINTER
;
1375 return WN_BAD_POINTER
;
1377 return WN_NO_NETWORK
;
1378 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1379 return WN_NO_MORE_ENTRIES
;
1380 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1381 return WN_BAD_VALUE
;
1382 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1383 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1386 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1387 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1390 size_t cchEntireNetworkLen
, bytesNeeded
;
1393 return WN_BAD_POINTER
;
1394 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1395 return WN_BAD_VALUE
;
1397 return WN_BAD_POINTER
;
1399 return WN_BAD_POINTER
;
1401 return WN_BAD_POINTER
;
1403 return WN_NO_NETWORK
;
1405 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1406 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1407 if (*lpBufferSize
< bytesNeeded
)
1409 *lpBufferSize
= bytesNeeded
;
1414 LPNETRESOURCEW lpNet
= lpBuffer
;
1416 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1417 lpNet
->dwType
= enumerator
->dwType
;
1418 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1419 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1420 lpNet
->lpLocalName
= NULL
;
1421 lpNet
->lpRemoteName
= NULL
;
1422 lpNet
->lpProvider
= NULL
;
1423 /* odd, but correct: put comment at end of buffer, so it won't get
1424 * overwritten by subsequent calls to a provider's enumResource
1426 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1427 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1428 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1431 if (ret
== WN_SUCCESS
)
1433 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1435 /* "Entire Network" entry enumerated--morph this into a global
1436 * enumerator. enumerator->lpNet continues to be NULL, since it has
1437 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1439 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1440 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1441 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1442 if (ret
== WN_SUCCESS
)
1444 /* reflect the fact that we already enumerated "Entire Network" */
1446 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1450 /* the provider enumeration failed, but we already succeeded in
1451 * enumerating "Entire Network"--leave type as global to allow a
1452 * retry, but indicate success with a count of one.
1456 *lpBufferSize
= bytesNeeded
;
1459 TRACE("Returning %d\n", ret
);
1463 static DWORD
_copyStringToEnumW(const WCHAR
*source
, DWORD
* left
, void** end
)
1466 WCHAR
* local
= *end
;
1468 len
= strlenW(source
) + 1;
1469 len
*= sizeof(WCHAR
);
1471 return WN_MORE_DATA
;
1473 local
-= (len
/ sizeof(WCHAR
));
1474 memcpy(local
, source
, len
);
1481 static DWORD
_enumerateConnectedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1482 void* user_buffer
, DWORD
* user_size
)
1484 DWORD ret
, index
, count
, total_count
, size
, i
, left
;
1486 NETRESOURCEW
* curr
, * buffer
;
1490 return WN_BAD_POINTER
;
1491 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONNECTED
)
1492 return WN_BAD_VALUE
;
1493 if (!user_count
|| !user_buffer
|| !user_size
)
1494 return WN_BAD_POINTER
;
1496 return WN_NO_NETWORK
;
1498 handles
= enumerator
->specific
.handles
;
1501 buffer
= HeapAlloc(GetProcessHeap(), 0, *user_size
);
1503 return WN_NO_NETWORK
;
1506 end
= (char *)user_buffer
+ size
;
1507 count
= *user_count
;
1510 ret
= WN_NO_MORE_ENTRIES
;
1511 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1513 if (providerTable
->table
[index
].dwEnumScopes
)
1515 if (handles
[index
] == 0)
1517 ret
= providerTable
->table
[index
].openEnum(enumerator
->dwScope
,
1519 enumerator
->dwUsage
,
1520 NULL
, &handles
[index
]);
1521 if (ret
!= WN_SUCCESS
)
1525 ret
= providerTable
->table
[index
].enumResource(handles
[index
],
1528 total_count
+= count
;
1529 if (ret
== WN_MORE_DATA
)
1532 if (ret
== WN_SUCCESS
)
1534 for (i
= 0; i
< count
; ++i
)
1536 if (left
< sizeof(NETRESOURCEW
))
1542 memcpy(curr
, &buffer
[i
], sizeof(NETRESOURCEW
));
1543 left
-= sizeof(NETRESOURCEW
);
1545 ret
= _copyStringToEnumW(buffer
[i
].lpLocalName
, &left
, &end
);
1546 if (ret
== WN_MORE_DATA
)
1548 curr
->lpLocalName
= end
;
1550 ret
= _copyStringToEnumW(buffer
[i
].lpRemoteName
, &left
, &end
);
1551 if (ret
== WN_MORE_DATA
)
1553 curr
->lpRemoteName
= end
;
1555 ret
= _copyStringToEnumW(buffer
[i
].lpProvider
, &left
, &end
);
1556 if (ret
== WN_MORE_DATA
)
1558 curr
->lpProvider
= end
;
1566 if (*user_count
!= -1)
1567 count
= *user_count
- total_count
;
1569 count
= *user_count
;
1573 if (total_count
== 0)
1574 ret
= WN_NO_MORE_ENTRIES
;
1576 *user_count
= total_count
;
1577 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1580 HeapFree(GetProcessHeap(), 0, buffer
);
1582 TRACE("Returning %d\n", ret
);
1587 static const WCHAR connectionType
[] = { 'C','o','n','n','e','c','t',
1588 'i','o','n','T','y','p','e',0 };
1589 static const WCHAR providerName
[] = { 'P','r','o','v','i','d','e','r',
1590 'N','a','m','e',0 };
1591 static const WCHAR remotePath
[] = { 'R','e','m','o','t','e','P',
1594 static DWORD
_enumeratorRememberedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1595 void* user_buffer
, DWORD
* user_size
)
1597 HKEY registry
, connection
;
1599 DWORD index
, ret
, type
, len
, size
, provider_size
, remote_size
, full_size
, total_count
, size_left
= *user_size
;
1600 NETRESOURCEW
* net_buffer
= user_buffer
;
1604 return WN_BAD_POINTER
;
1605 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_REMEMBERED
)
1606 return WN_BAD_VALUE
;
1607 if (!user_count
|| !user_buffer
|| !user_size
)
1608 return WN_BAD_POINTER
;
1610 return WN_NO_NETWORK
;
1612 /* We will do the work in a single loop, so here is some things:
1613 * we write netresource at the begin of the user buffer
1614 * we write strings at the end of the user buffer
1617 type
= enumerator
->dwType
;
1618 registry
= enumerator
->specific
.remembered
.registry
;
1619 str
= (WCHAR
*)((ULONG_PTR
)user_buffer
+ *user_size
- sizeof(WCHAR
));
1620 for (index
= enumerator
->specific
.remembered
.index
; ; ++index
)
1622 enumerator
->specific
.remembered
.index
= index
;
1624 if (*user_count
!= -1 && total_count
== *user_count
)
1630 if (size_left
< sizeof(NETRESOURCEW
))
1636 len
= ARRAY_SIZE(buffer
);
1637 ret
= RegEnumKeyExW(registry
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
);
1638 if (ret
!= ERROR_SUCCESS
)
1640 /* We're done, that's a success! */
1641 if (ret
== ERROR_NO_MORE_ITEMS
)
1650 if (RegOpenKeyExW(registry
, buffer
, 0, KEY_READ
, &connection
) != ERROR_SUCCESS
)
1655 size
= sizeof(DWORD
);
1656 RegQueryValueExW(connection
, connectionType
, NULL
, NULL
, (BYTE
*)&net_buffer
->dwType
, &size
);
1657 if (type
!= RESOURCETYPE_ANY
&& net_buffer
->dwType
!= type
)
1659 RegCloseKey(connection
);
1663 net_buffer
->dwScope
= RESOURCE_REMEMBERED
;
1664 net_buffer
->dwDisplayType
= RESOURCEDISPLAYTYPE_GENERIC
;
1665 net_buffer
->dwUsage
= RESOURCEUSAGE_CONNECTABLE
;
1667 size_left
-= sizeof(NETRESOURCEW
);
1669 /* Compute the whole size */
1671 if (RegQueryValueExW(connection
, providerName
, NULL
, NULL
, NULL
, &provider_size
) != ERROR_SUCCESS
)
1673 RegCloseKey(connection
);
1676 full_size
+= provider_size
;
1678 if (RegQueryValueExW(connection
, remotePath
, NULL
, NULL
, NULL
, &remote_size
) != ERROR_SUCCESS
)
1680 RegCloseKey(connection
);
1683 full_size
+= remote_size
;
1685 /* FIXME: this only supports drive letters */
1686 full_size
+= 3 * sizeof(WCHAR
);
1687 if (full_size
> size_left
)
1689 RegCloseKey(connection
);
1698 net_buffer
->lpLocalName
= str
;
1699 size_left
-= 3 * sizeof(WCHAR
);
1701 size
= provider_size
;
1702 str
-= (provider_size
/ sizeof(WCHAR
));
1703 ret
= RegQueryValueExW(connection
, providerName
, NULL
, NULL
, (BYTE
*)str
, &size
);
1704 if (ret
== ERROR_MORE_DATA
)
1706 RegCloseKey(connection
);
1710 net_buffer
->lpProvider
= str
;
1714 str
-= (remote_size
/ sizeof(WCHAR
));
1715 ret
= RegQueryValueExW(connection
, remotePath
, NULL
, NULL
, (BYTE
*)str
, &size
);
1716 if (ret
== ERROR_MORE_DATA
)
1718 RegCloseKey(connection
);
1722 net_buffer
->lpRemoteName
= str
;
1725 RegCloseKey(connection
);
1727 net_buffer
->lpComment
= NULL
;
1733 if (total_count
== 0)
1734 ret
= WN_NO_MORE_ENTRIES
;
1736 *user_count
= total_count
;
1738 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1741 if (ret
== WN_MORE_DATA
)
1742 *user_size
= *user_size
+ full_size
;
1748 /*********************************************************************
1749 * WNetEnumResourceW [MPR.@]
1751 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1752 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1756 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1759 ret
= WN_BAD_POINTER
;
1761 ret
= WN_BAD_POINTER
;
1763 ret
= WN_BAD_POINTER
;
1764 else if (!lpBufferSize
)
1765 ret
= WN_BAD_POINTER
;
1766 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1768 *lpBufferSize
= sizeof(NETRESOURCEW
);
1773 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1775 switch (enumerator
->enumType
)
1778 case WNET_ENUMERATOR_TYPE_NULL
:
1779 ret
= WN_NO_MORE_ENTRIES
;
1782 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1783 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1786 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1787 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1790 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1791 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1794 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1795 ret
= _enumerateConnectedW(enumerator
, lpcCount
, lpBuffer
,
1799 case WNET_ENUMERATOR_TYPE_REMEMBERED
:
1800 ret
= _enumeratorRememberedW(enumerator
, lpcCount
, lpBuffer
,
1805 WARN("bogus enumerator type!\n");
1806 ret
= WN_NO_NETWORK
;
1811 TRACE("Returning %d\n", ret
);
1815 /*********************************************************************
1816 * WNetCloseEnum [MPR.@]
1818 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1823 TRACE( "(%p)\n", hEnum
);
1827 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1829 switch (enumerator
->enumType
)
1832 case WNET_ENUMERATOR_TYPE_NULL
:
1836 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1837 if (enumerator
->specific
.net
)
1838 _freeEnumNetResource(enumerator
->specific
.net
);
1839 if (enumerator
->handle
)
1840 providerTable
->table
[enumerator
->providerIndex
].
1841 closeEnum(enumerator
->handle
);
1844 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1845 if (enumerator
->handle
)
1846 providerTable
->table
[enumerator
->providerIndex
].
1847 closeEnum(enumerator
->handle
);
1850 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1851 handles
= enumerator
->specific
.handles
;
1852 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1854 if (providerTable
->table
[index
].dwEnumScopes
&& handles
[index
])
1855 providerTable
->table
[index
].closeEnum(handles
[index
]);
1857 HeapFree(GetProcessHeap(), 0, handles
);
1861 case WNET_ENUMERATOR_TYPE_REMEMBERED
:
1862 RegCloseKey(enumerator
->specific
.remembered
.registry
);
1867 WARN("bogus enumerator type!\n");
1868 ret
= WN_BAD_HANDLE
;
1870 HeapFree(GetProcessHeap(), 0, hEnum
);
1873 ret
= WN_BAD_HANDLE
;
1876 TRACE("Returning %d\n", ret
);
1880 /*********************************************************************
1881 * WNetGetResourceInformationA [MPR.@]
1883 * See WNetGetResourceInformationW
1885 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1886 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1891 TRACE( "(%p, %p, %p, %p)\n",
1892 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1894 if (!providerTable
|| providerTable
->numProviders
== 0)
1895 ret
= WN_NO_NETWORK
;
1896 else if (lpNetResource
)
1898 LPNETRESOURCEW lpNetResourceW
= NULL
;
1899 DWORD size
= 1024, count
= 1;
1902 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1903 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1904 if (ret
== WN_MORE_DATA
)
1906 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1907 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1909 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1910 &count
, lpNetResourceW
, &size
);
1912 ret
= WN_OUT_OF_MEMORY
;
1914 if (ret
== WN_SUCCESS
)
1916 LPWSTR lpSystemW
= NULL
;
1919 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1922 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1923 lpBufferW
, &size
, &lpSystemW
);
1924 if (ret
== WN_MORE_DATA
)
1926 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1927 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1929 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1930 lpBufferW
, &size
, &lpSystemW
);
1932 ret
= WN_OUT_OF_MEMORY
;
1934 if (ret
== WN_SUCCESS
)
1936 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1937 &count
, lpBuffer
, cbBuffer
);
1938 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1939 lpNetResourceW
= lpBufferW
;
1940 size
= sizeof(NETRESOURCEA
);
1941 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1942 -1, NULL
, 0, NULL
, NULL
);
1943 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1944 -1, NULL
, 0, NULL
, NULL
);
1946 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1947 -1, NULL
, 0, NULL
, NULL
);
1948 if ((len
) && ( size
+ len
< *cbBuffer
))
1950 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1951 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1952 *lplpSystem
, len
, NULL
, NULL
);
1959 ret
= WN_OUT_OF_MEMORY
;
1960 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1963 ret
= WN_OUT_OF_MEMORY
;
1964 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1966 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1969 ret
= WN_NO_NETWORK
;
1973 TRACE("Returning %d\n", ret
);
1977 /*********************************************************************
1978 * WNetGetResourceInformationW [MPR.@]
1980 * WNetGetResourceInformationW function identifies the network provider
1981 * that owns the resource and gets information about the type of the resource.
1984 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1985 * defines a network resource.
1986 * lpBuffer [ O] the pointer to buffer, containing result. It
1987 * contains NETRESOURCEW structure and strings to
1988 * which the members of the NETRESOURCEW structure
1990 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1992 * lplpSystem [ O] the pointer to string in the output buffer,
1993 * containing the part of the resource name without
1994 * names of the server and share.
1997 * NO_ERROR if the function succeeds. System error code if the function fails.
2000 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
2001 LPVOID lpBuffer
, LPDWORD cbBuffer
,
2002 LPWSTR
*lplpSystem
)
2004 DWORD ret
= WN_NO_NETWORK
;
2007 TRACE( "(%p, %p, %p, %p)\n",
2008 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
2011 ret
= WN_OUT_OF_MEMORY
;
2012 else if (providerTable
!= NULL
)
2014 /* FIXME: For function value of a variable is indifferent, it does
2015 * search of all providers in a network.
2017 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2019 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
2020 WNNC_DLG_GETRESOURCEINFORMATION
)
2022 if (providerTable
->table
[index
].getResourceInformation
)
2023 ret
= providerTable
->table
[index
].getResourceInformation(
2024 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
2026 ret
= WN_NO_NETWORK
;
2027 if (ret
== WN_SUCCESS
)
2037 /*********************************************************************
2038 * WNetGetResourceParentA [MPR.@]
2040 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
2041 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2043 FIXME( "(%p, %p, %p): stub\n",
2044 lpNetResource
, lpBuffer
, lpBufferSize
);
2046 SetLastError(WN_NO_NETWORK
);
2047 return WN_NO_NETWORK
;
2050 /*********************************************************************
2051 * WNetGetResourceParentW [MPR.@]
2053 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
2054 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2056 FIXME( "(%p, %p, %p): stub\n",
2057 lpNetResource
, lpBuffer
, lpBufferSize
);
2059 SetLastError(WN_NO_NETWORK
);
2060 return WN_NO_NETWORK
;
2066 * Connection Functions
2069 /*********************************************************************
2070 * WNetAddConnectionA [MPR.@]
2072 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
2073 LPCSTR lpLocalName
)
2075 NETRESOURCEA resourcesA
;
2077 memset(&resourcesA
, 0, sizeof(resourcesA
));
2078 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
2079 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
2080 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
2083 /*********************************************************************
2084 * WNetAddConnectionW [MPR.@]
2086 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
2087 LPCWSTR lpLocalName
)
2089 NETRESOURCEW resourcesW
;
2091 memset(&resourcesW
, 0, sizeof(resourcesW
));
2092 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
2093 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
2094 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
2097 /*********************************************************************
2098 * WNetAddConnection2A [MPR.@]
2100 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
2101 LPCSTR lpPassword
, LPCSTR lpUserID
,
2104 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
2108 /*********************************************************************
2109 * WNetAddConnection2W [MPR.@]
2111 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
2112 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
2115 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
2119 /*********************************************************************
2120 * WNetAddConnection3A [MPR.@]
2122 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
2123 LPCSTR lpPassword
, LPCSTR lpUserID
,
2126 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
2127 dwFlags
, NULL
, 0, NULL
);
2130 /*********************************************************************
2131 * WNetAddConnection3W [MPR.@]
2133 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
2134 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
2137 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
2138 dwFlags
, NULL
, 0, NULL
);
2141 struct use_connection_context
2144 NETRESOURCEW
*resource
;
2145 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
2152 DWORD (*pre_set_accessname
)(struct use_connection_context
*, WCHAR
*);
2153 void (*set_accessname
)(struct use_connection_context
*, WCHAR
*);
2156 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2158 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
2163 len
= strlenW(local_name
);
2165 len
= strlenW(ctxt
->resource
->lpRemoteName
);
2167 if (++len
> *ctxt
->buffer_size
)
2169 *ctxt
->buffer_size
= len
;
2170 return ERROR_MORE_DATA
;
2174 ctxt
->accessname
= NULL
;
2176 return ERROR_SUCCESS
;
2179 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2181 WCHAR
*accessname
= ctxt
->accessname
;
2184 strcpyW(accessname
, local_name
);
2186 *ctxt
->result
= CONNECT_LOCALDRIVE
;
2189 strcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
2192 static DWORD
wnet_use_provider( struct use_connection_context
*ctxt
, NETRESOURCEW
* netres
, WNetProvider
*provider
, BOOLEAN redirect
)
2196 caps
= provider
->getCaps(WNNC_CONNECTION
);
2197 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
2198 return ERROR_BAD_PROVIDER
;
2200 ret
= WN_ACCESS_DENIED
;
2203 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
2204 ret
= provider
->addConnection3(ctxt
->hwndOwner
, netres
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
2205 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
2206 ret
= provider
->addConnection(netres
, ctxt
->password
, ctxt
->userid
);
2208 if (ret
== WN_ALREADY_CONNECTED
&& redirect
)
2209 netres
->lpLocalName
[0] -= 1;
2210 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& netres
->lpLocalName
[0] >= 'C');
2212 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
2213 ctxt
->set_accessname(ctxt
, netres
->lpLocalName
);
2218 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
2220 WNetProvider
*provider
;
2221 DWORD index
, ret
= WN_NO_NETWORK
;
2222 BOOL redirect
= FALSE
;
2223 WCHAR letter
[3] = {'Z', ':', 0};
2224 NETRESOURCEW netres
;
2226 if (!providerTable
|| providerTable
->numProviders
== 0)
2227 return WN_NO_NETWORK
;
2229 if (!ctxt
->resource
)
2230 return ERROR_INVALID_PARAMETER
;
2231 netres
= *ctxt
->resource
;
2233 if (!netres
.lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
2235 if (netres
.dwType
!= RESOURCETYPE_DISK
&& netres
.dwType
!= RESOURCETYPE_PRINT
)
2236 return ERROR_BAD_DEV_TYPE
;
2238 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2240 FIXME("Local device selection is not implemented for printers.\n");
2241 return WN_NO_NETWORK
;
2245 netres
.lpLocalName
= letter
;
2248 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
2249 return ERROR_BAD_NET_NAME
;
2251 if ((ret
= ctxt
->pre_set_accessname(ctxt
, netres
.lpLocalName
)))
2254 if (netres
.lpProvider
)
2256 index
= _findProviderIndexW(netres
.lpProvider
);
2257 if (index
== BAD_PROVIDER_INDEX
)
2258 return ERROR_BAD_PROVIDER
;
2260 provider
= &providerTable
->table
[index
];
2261 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2265 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2267 provider
= &providerTable
->table
[index
];
2268 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2269 if (ret
== WN_SUCCESS
|| ret
== WN_ALREADY_CONNECTED
)
2275 if (ret
== WN_SUCCESS
&& ctxt
->flags
& CONNECT_UPDATE_PROFILE
)
2279 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2281 FIXME("Persistent connection are not supported for printers\n");
2285 if (RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2288 WCHAR subkey
[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres
.lpLocalName
[0], 0};
2290 if (RegCreateKeyExW(user_profile
, subkey
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &network
, NULL
) == ERROR_SUCCESS
)
2292 DWORD dword_arg
= RESOURCETYPE_DISK
;
2293 DWORD len
= (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
2295 RegSetValueExW(network
, L
"ConnectionType", 0, REG_DWORD
, (const BYTE
*)&dword_arg
, sizeof(DWORD
));
2296 RegSetValueExW(network
, L
"ProviderName", 0, REG_SZ
, (const BYTE
*)provider
->name
, len
);
2297 dword_arg
= provider
->dwNetType
;
2298 RegSetValueExW(network
, L
"ProviderType", 0, REG_DWORD
, (const BYTE
*)&dword_arg
, sizeof(DWORD
));
2299 len
= (strlenW(netres
.lpRemoteName
) + 1) * sizeof(WCHAR
);
2300 RegSetValueExW(network
, L
"RemotePath", 0, REG_SZ
, (const BYTE
*)netres
.lpRemoteName
, len
);
2302 RegSetValueExW(network
, L
"UserName", 0, REG_SZ
, (const BYTE
*)netres
.lpRemoteName
, len
);
2303 RegCloseKey(network
);
2306 RegCloseKey(user_profile
);
2314 /*****************************************************************
2315 * WNetUseConnectionW [MPR.@]
2317 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
2318 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
2320 struct use_connection_context ctxt
;
2322 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
2323 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
2324 accessname
, buffer_size
, result
);
2326 ctxt
.hwndOwner
= hwndOwner
;
2327 ctxt
.resource
= resource
;
2328 ctxt
.resourceA
= NULL
;
2329 ctxt
.password
= (WCHAR
*)password
;
2330 ctxt
.userid
= (WCHAR
*)userid
;
2332 ctxt
.accessname
= accessname
;
2333 ctxt
.buffer_size
= buffer_size
;
2334 ctxt
.result
= result
;
2335 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
2336 ctxt
.set_accessname
= use_connection_set_accessnameW
;
2338 return wnet_use_connection(&ctxt
);
2341 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2343 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
2348 len
= WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, NULL
, 0, NULL
, NULL
) - 1;
2350 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
2352 if (++len
> *ctxt
->buffer_size
)
2354 *ctxt
->buffer_size
= len
;
2355 return ERROR_MORE_DATA
;
2359 ctxt
->accessname
= NULL
;
2361 return ERROR_SUCCESS
;
2364 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2366 char *accessname
= ctxt
->accessname
;
2369 WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, accessname
, *ctxt
->buffer_size
, NULL
, NULL
);
2371 *ctxt
->result
= CONNECT_LOCALDRIVE
;
2374 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
2377 static LPWSTR
strdupAtoW( LPCSTR str
)
2382 if (!str
) return NULL
;
2383 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
2384 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2385 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
2389 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
2391 resourceW
->dwScope
= resourceA
->dwScope
;
2392 resourceW
->dwType
= resourceA
->dwType
;
2393 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
2394 resourceW
->dwUsage
= resourceA
->dwUsage
;
2395 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
2396 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
2397 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
2398 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
2401 static void free_netresourceW( NETRESOURCEW
*resource
)
2403 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
2404 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
2405 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
2406 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
2409 /*****************************************************************
2410 * WNetUseConnectionA [MPR.@]
2412 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
2413 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
2414 DWORD
*buffer_size
, DWORD
*result
)
2416 struct use_connection_context ctxt
;
2417 NETRESOURCEW resourceW
;
2420 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
2421 accessname
, buffer_size
, result
);
2423 netresource_a_to_w(resource
, &resourceW
);
2425 ctxt
.hwndOwner
= hwndOwner
;
2426 ctxt
.resource
= &resourceW
;
2427 ctxt
.resourceA
= resource
;
2428 ctxt
.password
= strdupAtoW(password
);
2429 ctxt
.userid
= strdupAtoW(userid
);
2431 ctxt
.accessname
= accessname
;
2432 ctxt
.buffer_size
= buffer_size
;
2433 ctxt
.result
= result
;
2434 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
2435 ctxt
.set_accessname
= use_connection_set_accessnameA
;
2437 ret
= wnet_use_connection(&ctxt
);
2439 free_netresourceW(&resourceW
);
2440 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
2441 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
2446 /*********************************************************************
2447 * WNetCancelConnectionA [MPR.@]
2449 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
2451 return WNetCancelConnection2A(lpName
, 0, fForce
);
2454 /*********************************************************************
2455 * WNetCancelConnectionW [MPR.@]
2457 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
2459 return WNetCancelConnection2W(lpName
, 0, fForce
);
2462 /*********************************************************************
2463 * WNetCancelConnection2A [MPR.@]
2465 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2468 WCHAR
* name
= strdupAtoW(lpName
);
2470 return ERROR_NOT_CONNECTED
;
2472 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
2473 HeapFree(GetProcessHeap(), 0, name
);
2478 /*********************************************************************
2479 * WNetCancelConnection2W [MPR.@]
2481 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2483 DWORD ret
= WN_NO_NETWORK
;
2486 if (providerTable
!= NULL
)
2488 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2490 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2491 WNNC_CON_CANCELCONNECTION
)
2493 if (providerTable
->table
[index
].cancelConnection
)
2494 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
2496 ret
= WN_NO_NETWORK
;
2497 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
2504 if (dwFlags
& CONNECT_UPDATE_PROFILE
)
2507 WCHAR
*coma
= strchrW(lpName
, ':');
2509 if (coma
&& RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2514 len
= (ULONG_PTR
)coma
- (ULONG_PTR
)lpName
+ sizeof(L
"Network\\");
2515 subkey
= HeapAlloc(GetProcessHeap(), 0, len
);
2518 strcpyW(subkey
, L
"Network\\");
2519 memcpy(subkey
+ (sizeof(L
"Network\\") / sizeof(WCHAR
)) - 1, lpName
, (ULONG_PTR
)coma
- (ULONG_PTR
)lpName
);
2520 subkey
[len
/ sizeof(WCHAR
) - 1] = 0;
2522 TRACE("Removing: %S\n", subkey
);
2524 RegDeleteKeyW(user_profile
, subkey
);
2525 HeapFree(GetProcessHeap(), 0, subkey
);
2528 RegCloseKey(user_profile
);
2536 /*****************************************************************
2537 * WNetRestoreConnectionA [MPR.@]
2539 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
2541 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
2543 SetLastError(WN_NO_NETWORK
);
2544 return WN_NO_NETWORK
;
2547 /*****************************************************************
2548 * WNetRestoreConnectionW [MPR.@]
2550 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
2552 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
2554 SetLastError(WN_NO_NETWORK
);
2555 return WN_NO_NETWORK
;
2558 /**************************************************************************
2559 * WNetGetConnectionA [MPR.@]
2562 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2563 * - WN_NOT_CONNECTED drive is a local drive
2564 * - WN_MORE_DATA buffer isn't big enough
2565 * - WN_SUCCESS success (net path in buffer)
2567 * FIXME: need to test return values under different errors
2569 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
2570 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
2575 ret
= WN_BAD_POINTER
;
2576 else if (!lpBufferSize
)
2577 ret
= WN_BAD_POINTER
;
2578 else if (!lpRemoteName
&& *lpBufferSize
)
2579 ret
= WN_BAD_POINTER
;
2582 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
2586 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2590 WCHAR wideRemoteStatic
[MAX_PATH
];
2591 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
2593 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
2595 /* try once without memory allocation */
2596 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
2598 if (ret
== WN_SUCCESS
)
2600 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2601 -1, NULL
, 0, NULL
, NULL
);
2603 if (len
<= *lpBufferSize
)
2605 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
2606 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2611 *lpBufferSize
= len
;
2615 else if (ret
== WN_MORE_DATA
)
2617 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2618 wideRemoteSize
* sizeof(WCHAR
));
2622 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2624 if (ret
== WN_SUCCESS
)
2626 if (len
<= *lpBufferSize
)
2628 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2629 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2634 *lpBufferSize
= len
;
2638 HeapFree(GetProcessHeap(), 0, wideRemote
);
2641 ret
= WN_OUT_OF_MEMORY
;
2643 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2646 ret
= WN_OUT_OF_MEMORY
;
2649 ret
= WN_BAD_LOCALNAME
;
2653 TRACE("Returning %d\n", ret
);
2657 /* find the network connection for a given drive; helper for WNetGetConnection */
2658 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2662 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2664 DWORD ret
= WN_NOT_CONNECTED
;
2665 DWORD bytes_returned
;
2667 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2668 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2669 0, 0 )) == INVALID_HANDLE_VALUE
)
2671 ERR( "failed to open mount manager err %u\n", GetLastError() );
2674 memset( data
, 0, sizeof(*data
) );
2675 data
->letter
= letter
;
2676 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2677 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2679 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2682 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2685 mount_point
[0] = '\\';
2686 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2688 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2696 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2704 DWORD ret
= WN_NO_NETWORK
;
2706 WCHAR local
[3] = {letter
, ':', 0};
2708 if (providerTable
!= NULL
)
2710 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2712 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2713 WNNC_CON_GETCONNECTIONS
)
2715 if (providerTable
->table
[index
].getConnection
)
2716 ret
= providerTable
->table
[index
].getConnection(
2717 local
, remote
, size
);
2719 ret
= WN_NO_NETWORK
;
2720 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2731 /**************************************************************************
2732 * WNetGetConnectionW [MPR.@]
2734 * FIXME: need to test return values under different errors
2736 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2737 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2741 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2745 ret
= WN_BAD_POINTER
;
2746 else if (!lpBufferSize
)
2747 ret
= WN_BAD_POINTER
;
2748 else if (!lpRemoteName
&& *lpBufferSize
)
2749 ret
= WN_BAD_POINTER
;
2750 else if (!lpLocalName
[0])
2751 ret
= WN_BAD_LOCALNAME
;
2754 if (lpLocalName
[1] == ':')
2756 switch(GetDriveTypeW(lpLocalName
))
2759 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2761 case DRIVE_REMOVABLE
:
2764 TRACE("file is local\n");
2765 ret
= WN_NOT_CONNECTED
;
2768 ret
= WN_BAD_LOCALNAME
;
2772 ret
= WN_BAD_LOCALNAME
;
2776 TRACE("Returning %d\n", ret
);
2780 /**************************************************************************
2781 * WNetSetConnectionA [MPR.@]
2783 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2786 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2788 SetLastError(WN_NO_NETWORK
);
2789 return WN_NO_NETWORK
;
2792 /**************************************************************************
2793 * WNetSetConnectionW [MPR.@]
2795 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2798 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2800 SetLastError(WN_NO_NETWORK
);
2801 return WN_NO_NETWORK
;
2804 /*****************************************************************
2805 * WNetGetUniversalNameA [MPR.@]
2807 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2808 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2812 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2813 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2815 switch (dwInfoLevel
)
2817 case UNIVERSAL_NAME_INFO_LEVEL
:
2819 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2821 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2823 err
= ERROR_NOT_CONNECTED
;
2827 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2828 if (*lpBufferSize
< size
)
2833 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2834 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2838 case REMOTE_NAME_INFO_LEVEL
:
2839 err
= WN_NOT_CONNECTED
;
2851 /*****************************************************************
2852 * WNetGetUniversalNameW [MPR.@]
2854 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2855 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2859 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2860 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2862 switch (dwInfoLevel
)
2864 case UNIVERSAL_NAME_INFO_LEVEL
:
2866 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2868 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2870 err
= ERROR_NOT_CONNECTED
;
2874 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2875 if (*lpBufferSize
< size
)
2880 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2881 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2885 case REMOTE_NAME_INFO_LEVEL
:
2886 err
= WN_NO_NETWORK
;
2894 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2898 /*****************************************************************
2899 * WNetClearConnections [MPR.@]
2901 DWORD WINAPI
WNetClearConnections ( HWND owner
)
2905 DWORD ret
, size
, count
;
2906 NETRESOURCEW
* resources
, * iter
;
2908 ret
= WNetOpenEnumW(RESOURCE_CONNECTED
, RESOURCETYPE_ANY
, 0, NULL
, &connected
);
2909 if (ret
!= WN_SUCCESS
)
2911 if (ret
!= WN_NO_NETWORK
)
2916 /* Means no provider, then, clearing is OK */
2921 resources
= HeapAlloc(GetProcessHeap(), 0, size
);
2924 WNetCloseEnum(connected
);
2925 return WN_OUT_OF_MEMORY
;
2933 memset(resources
, 0, size
);
2934 ret
= WNetEnumResourceW(connected
, &count
, resources
, &size
);
2935 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2937 for (iter
= resources
; count
; count
--, iter
++)
2939 if (iter
->lpLocalName
&& iter
->lpLocalName
[0])
2940 connection
= iter
->lpLocalName
;
2942 connection
= iter
->lpRemoteName
;
2944 WNetCancelConnection2W(connection
, 0, TRUE
);
2951 HeapFree(GetProcessHeap(), 0, resources
);
2952 WNetCloseEnum(connected
);
2962 /**************************************************************************
2963 * WNetGetUserA [MPR.@]
2965 * FIXME: we should not return ourselves, but the owner of the drive lpName
2967 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2969 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2970 return GetLastError();
2973 /*****************************************************************
2974 * WNetGetUserW [MPR.@]
2976 * FIXME: we should not return ourselves, but the owner of the drive lpName
2978 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2980 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2981 return GetLastError();
2984 /*********************************************************************
2985 * WNetConnectionDialog [MPR.@]
2987 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2989 CONNECTDLGSTRUCTW conn_dlg
;
2990 NETRESOURCEW net_res
;
2992 ZeroMemory(&conn_dlg
, sizeof(conn_dlg
));
2993 ZeroMemory(&net_res
, sizeof(net_res
));
2995 conn_dlg
.cbStructure
= sizeof(conn_dlg
);
2996 conn_dlg
.lpConnRes
= &net_res
;
2997 conn_dlg
.hwndOwner
= hwnd
;
2998 net_res
.dwType
= dwType
;
3000 return WNetConnectionDialog1W(&conn_dlg
);
3003 /*********************************************************************
3004 * WNetConnectionDialog1A [MPR.@]
3006 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
3008 FIXME( "(%p): stub\n", lpConnDlgStruct
);
3010 SetLastError(WN_NO_NETWORK
);
3011 return WN_NO_NETWORK
;
3014 /*********************************************************************
3015 * WNetConnectionDialog1W [MPR.@]
3017 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
3019 FIXME( "(%p): stub\n", lpConnDlgStruct
);
3021 SetLastError(WN_NO_NETWORK
);
3022 return WN_NO_NETWORK
;
3025 /*********************************************************************
3026 * WNetDisconnectDialog [MPR.@]
3028 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
3030 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
3032 SetLastError(WN_NO_NETWORK
);
3033 return WN_NO_NETWORK
;
3036 /*********************************************************************
3037 * WNetDisconnectDialog1A [MPR.@]
3039 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
3041 FIXME( "(%p): stub\n", lpConnDlgStruct
);
3043 SetLastError(WN_NO_NETWORK
);
3044 return WN_NO_NETWORK
;
3047 /*********************************************************************
3048 * WNetDisconnectDialog1W [MPR.@]
3050 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
3052 FIXME( "(%p): stub\n", lpConnDlgStruct
);
3054 SetLastError(WN_NO_NETWORK
);
3055 return WN_NO_NETWORK
;
3058 /*********************************************************************
3059 * WNetGetLastErrorA [MPR.@]
3061 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
3062 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
3063 LPSTR lpNameBuf
, DWORD nNameBufSize
)
3065 FIXME( "(%p, %p, %d, %p, %d): stub\n",
3066 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
3068 SetLastError(WN_NO_NETWORK
);
3069 return WN_NO_NETWORK
;
3072 /*********************************************************************
3073 * WNetGetLastErrorW [MPR.@]
3075 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
3076 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
3077 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
3079 FIXME( "(%p, %p, %d, %p, %d): stub\n",
3080 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
3082 SetLastError(WN_NO_NETWORK
);
3083 return WN_NO_NETWORK
;
3086 /*********************************************************************
3087 * WNetGetNetworkInformationA [MPR.@]
3089 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
3090 LPNETINFOSTRUCT lpNetInfoStruct
)
3094 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
3097 ret
= WN_BAD_POINTER
;
3102 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
3105 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3109 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
3111 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
3112 HeapFree(GetProcessHeap(), 0, wideProvider
);
3115 ret
= WN_OUT_OF_MEMORY
;
3118 ret
= GetLastError();
3122 TRACE("Returning %d\n", ret
);
3126 /*********************************************************************
3127 * WNetGetNetworkInformationW [MPR.@]
3129 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
3130 LPNETINFOSTRUCT lpNetInfoStruct
)
3134 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
3137 ret
= WN_BAD_POINTER
;
3138 else if (!lpNetInfoStruct
)
3139 ret
= WN_BAD_POINTER
;
3140 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
3144 if (providerTable
&& providerTable
->numProviders
)
3146 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
3148 if (providerIndex
!= BAD_PROVIDER_INDEX
)
3150 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
3151 lpNetInfoStruct
->dwProviderVersion
=
3152 providerTable
->table
[providerIndex
].dwSpecVersion
;
3153 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
3154 lpNetInfoStruct
->dwCharacteristics
= 0;
3155 lpNetInfoStruct
->dwHandle
= 0;
3156 lpNetInfoStruct
->wNetType
=
3157 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
3158 lpNetInfoStruct
->dwPrinters
= -1;
3159 lpNetInfoStruct
->dwDrives
= -1;
3163 ret
= WN_BAD_PROVIDER
;
3166 ret
= WN_NO_NETWORK
;
3170 TRACE("Returning %d\n", ret
);
3174 /*****************************************************************
3175 * WNetGetProviderNameA [MPR.@]
3177 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
3178 LPSTR lpProvider
, LPDWORD lpBufferSize
)
3182 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
3186 ret
= WN_BAD_POINTER
;
3187 else if (!lpBufferSize
)
3188 ret
= WN_BAD_POINTER
;
3195 ret
= WN_NO_NETWORK
;
3196 for (i
= 0; i
< providerTable
->numProviders
&&
3197 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
3200 if (i
< providerTable
->numProviders
)
3202 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
3203 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
3205 if (*lpBufferSize
< sizeNeeded
)
3207 *lpBufferSize
= sizeNeeded
;
3212 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
3213 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
3215 /* FIXME: is *lpBufferSize set to the number of characters
3221 ret
= WN_NO_NETWORK
;
3225 TRACE("Returning %d\n", ret
);
3229 /*****************************************************************
3230 * WNetGetProviderNameW [MPR.@]
3232 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
3233 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
3237 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
3241 ret
= WN_BAD_POINTER
;
3242 else if (!lpBufferSize
)
3243 ret
= WN_BAD_POINTER
;
3250 ret
= WN_NO_NETWORK
;
3251 for (i
= 0; i
< providerTable
->numProviders
&&
3252 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
3255 if (i
< providerTable
->numProviders
)
3257 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
3259 if (*lpBufferSize
< sizeNeeded
)
3261 *lpBufferSize
= sizeNeeded
;
3266 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
3268 /* FIXME: is *lpBufferSize set to the number of characters
3274 ret
= WN_NO_NETWORK
;
3278 TRACE("Returning %d\n", ret
);