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
;
76 #define WNET_ENUMERATOR_TYPE_NULL 0
77 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
78 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
79 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
80 #define WNET_ENUMERATOR_TYPE_CONNECTED 4
82 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
83 * the enumeration; it represents one of the following types:
84 * - a 'null' enumeration, one that contains no members
85 * - a global enumeration, one that's executed across all providers
86 * - a provider-specific enumeration, one that's only executed by a single
88 * - a context enumeration. I know this contradicts what I just said about
89 * there being no correspondence between the scope and the type, but it's
90 * necessary for the special case that a "Entire Network" entry needs to
91 * be enumerated in an enumeration of the context scope. Thus an enumeration
92 * of the context scope results in a context type enumerator, which morphs
93 * into a global enumeration (so the enumeration continues across all
96 typedef struct _WNetEnumerator
110 } WNetEnumerator
, *PWNetEnumerator
;
112 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
114 /* Returns an index (into the global WNetProviderTable) of the provider with
115 * the given name, or BAD_PROVIDER_INDEX if not found.
117 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
119 static PWNetProviderTable providerTable
;
122 * Global provider table functions
125 static void _tryLoadProvider(PCWSTR provider
)
127 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
128 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
129 'S','e','r','v','i','c','e','s','\\',0 };
130 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
131 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
132 WCHAR serviceName
[MAX_PATH
];
135 TRACE("%s\n", debugstr_w(provider
));
136 snprintfW(serviceName
, sizeof(serviceName
) / sizeof(WCHAR
), serviceFmt
,
137 servicePrefix
, provider
);
138 serviceName
[sizeof(serviceName
) / sizeof(WCHAR
) - 1] = '\0';
139 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
142 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
144 WCHAR providerPath
[MAX_PATH
];
145 DWORD type
, size
= sizeof(providerPath
);
147 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
148 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
150 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
153 if (type
== REG_EXPAND_SZ
)
155 WCHAR path
[MAX_PATH
];
156 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
160 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
163 name
= HeapAlloc(GetProcessHeap(), 0, size
);
164 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
165 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
167 HeapFree(GetProcessHeap(), 0, name
);
173 HMODULE hLib
= LoadLibraryW(providerPath
);
177 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
179 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
181 TRACE("loaded lib %p\n", hLib
);
185 PWNetProvider provider
=
186 &providerTable
->table
[providerTable
->numProviders
];
188 provider
->hLib
= hLib
;
189 provider
->name
= name
;
190 TRACE("name is %s\n", debugstr_w(name
));
191 provider
->getCaps
= getCaps
;
192 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
193 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
194 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
195 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
196 if (provider
->dwEnumScopes
)
198 TRACE("supports enumeration\n");
199 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
200 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
201 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
202 TRACE("NPEnumResource %p\n", provider
->enumResource
);
203 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
204 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
205 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
206 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
207 if (!provider
->openEnum
||
208 !provider
->enumResource
||
209 !provider
->closeEnum
)
211 provider
->openEnum
= NULL
;
212 provider
->enumResource
= NULL
;
213 provider
->closeEnum
= NULL
;
214 provider
->dwEnumScopes
= 0;
215 WARN("Couldn't load enumeration functions\n");
218 connectCap
= getCaps(WNNC_CONNECTION
);
219 if (connectCap
& WNNC_CON_ADDCONNECTION
)
220 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
221 if (connectCap
& WNNC_CON_ADDCONNECTION3
)
222 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
223 if (connectCap
& WNNC_CON_CANCELCONNECTION
)
224 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
226 if (connectCap
& WNNC_CON_GETCONNECTIONS
)
227 provider
->getConnection
= MPR_GETPROC(NPGetConnection
);
229 TRACE("NPAddConnection %p\n", provider
->addConnection
);
230 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
231 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
232 providerTable
->numProviders
++;
236 WARN("Provider %s didn't export NPGetCaps\n",
237 debugstr_w(provider
));
238 HeapFree(GetProcessHeap(), 0, name
);
246 WARN("Couldn't load library %s for provider %s\n",
247 debugstr_w(providerPath
), debugstr_w(provider
));
248 HeapFree(GetProcessHeap(), 0, name
);
253 WARN("Couldn't get provider name for provider %s\n",
254 debugstr_w(provider
));
258 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
262 WARN("Couldn't open service key for provider %s\n",
263 debugstr_w(provider
));
267 static void _restoreSavedConnection(HKEY connection
, WCHAR
* local
)
270 DWORD type
, prov
, index
, size
;
272 net
.lpProvider
= NULL
;
273 net
.lpRemoteName
= NULL
;
274 net
.lpLocalName
= NULL
;
276 TRACE("Restoring: %S\n", local
);
278 size
= sizeof(DWORD
);
279 if (RegQueryValueExW(connection
, L
"ConnectionType", NULL
, &type
, (BYTE
*)&net
.dwType
, &size
) != ERROR_SUCCESS
)
282 if (type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
285 if (RegQueryValueExW(connection
, L
"ProviderName", NULL
, &type
, NULL
, &size
) != ERROR_SUCCESS
)
291 net
.lpProvider
= HeapAlloc(GetProcessHeap(), 0, size
);
295 if (RegQueryValueExW(connection
, L
"ProviderName", NULL
, NULL
, (BYTE
*)net
.lpProvider
, &size
) != ERROR_SUCCESS
)
298 size
= sizeof(DWORD
);
299 if (RegQueryValueExW(connection
, L
"ProviderType", NULL
, &type
, (BYTE
*)&prov
, &size
) != ERROR_SUCCESS
)
302 if (type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
305 index
= _findProviderIndexW(net
.lpProvider
);
306 if (index
== BAD_PROVIDER_INDEX
)
309 if (providerTable
->table
[index
].dwNetType
!= prov
)
312 if (RegQueryValueExW(connection
, L
"RemotePath", NULL
, &type
, NULL
, &size
) != ERROR_SUCCESS
)
318 net
.lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, size
);
319 if (!net
.lpRemoteName
)
322 if (RegQueryValueExW(connection
, L
"RemotePath", NULL
, NULL
, (BYTE
*)net
.lpRemoteName
, &size
) != ERROR_SUCCESS
)
325 size
= strlenW(local
);
326 net
.lpLocalName
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
) + 2 * sizeof(WCHAR
));
327 if (!net
.lpLocalName
)
330 strcpyW(net
.lpLocalName
, local
);
331 net
.lpLocalName
[size
] = ':';
332 net
.lpLocalName
[size
+ 1] = 0;
334 TRACE("Attempting connection\n");
336 WNetAddConnection2W(&net
, NULL
, NULL
, 0);
339 HeapFree(GetProcessHeap(), 0, net
.lpProvider
);
340 HeapFree(GetProcessHeap(), 0, net
.lpRemoteName
);
341 HeapFree(GetProcessHeap(), 0, net
.lpLocalName
);
345 void wnetInit(HINSTANCE hInstDll
)
347 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
348 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
349 'C','o','n','t','r','o','l','\\',
350 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
351 'O','r','d','e','r',0 };
352 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
353 'O','r','d','e','r',0 };
356 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
361 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
364 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
370 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
371 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
376 TRACE("provider order is %s\n", debugstr_w(providers
));
377 /* first count commas as a heuristic for how many to
378 * allocate space for */
379 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
381 ptr
= strchrW(ptr
, ',');
388 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
389 sizeof(WNetProviderTable
)
390 + (numToAllocate
- 1) * sizeof(WNetProvider
));
394 int entireNetworkLen
;
395 LPCWSTR stringresource
;
397 entireNetworkLen
= LoadStringW(hInstDll
,
398 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
399 providerTable
->entireNetwork
= HeapAlloc(
400 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
402 if (providerTable
->entireNetwork
)
404 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
405 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
407 providerTable
->numAllocated
= numToAllocate
;
408 for (ptr
= providers
; ptr
; )
411 ptr
= strchrW(ptr
, ',');
414 _tryLoadProvider(ptrPrev
);
418 HeapFree(GetProcessHeap(), 0, providers
);
429 if (RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
432 WCHAR subkey
[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
434 if (RegOpenKeyExW(user_profile
, subkey
, 0, KEY_READ
, &network
) == ERROR_SUCCESS
)
438 TRACE("Enumerating remembered connections\n");
440 if (RegQueryInfoKey(network
, NULL
, NULL
, NULL
, &max
, &size
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
444 TRACE("There are %lu connections\n", max
);
446 local
= HeapAlloc(GetProcessHeap(), 0, (size
+ 1) * sizeof(WCHAR
));
451 for (index
= 0; index
< max
; ++index
)
453 DWORD len
= size
+ 1;
456 TRACE("Trying connection %lu\n", index
);
458 if (RegEnumKeyExW(network
, index
, local
, &len
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
461 TRACE("It is %S\n", local
);
463 if (RegOpenKeyExW(network
, local
, 0, KEY_READ
, &connection
) != ERROR_SUCCESS
)
466 _restoreSavedConnection(connection
, local
);
467 RegCloseKey(connection
);
470 HeapFree(GetProcessHeap(), 0, local
);
474 RegCloseKey(network
);
477 RegCloseKey(user_profile
);
489 for (i
= 0; i
< providerTable
->numProviders
; i
++)
491 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
492 FreeModule(providerTable
->table
[i
].hLib
);
494 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
495 HeapFree(GetProcessHeap(), 0, providerTable
);
496 providerTable
= NULL
;
500 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
502 DWORD ret
= BAD_PROVIDER_INDEX
;
504 if (providerTable
&& providerTable
->numProviders
)
508 for (i
= 0; i
< providerTable
->numProviders
&&
509 ret
== BAD_PROVIDER_INDEX
; i
++)
510 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
520 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
526 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
532 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
533 if (lpNet
->lpRemoteName
)
535 len
= strlenW(lpNet
->lpRemoteName
) + 1;
536 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
537 if (ret
->lpRemoteName
)
538 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
547 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
551 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
552 HeapFree(GetProcessHeap(), 0, lpNet
);
556 static PWNetEnumerator
_createNullEnumerator(void)
558 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
559 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
562 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
566 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
567 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
569 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
570 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
574 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
575 ret
->dwScope
= dwScope
;
576 ret
->dwType
= dwType
;
577 ret
->dwUsage
= dwUsage
;
578 ret
->specific
.net
= _copyNetResourceForEnumW(lpNet
);
583 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
584 DWORD dwUsage
, DWORD index
, HANDLE handle
)
588 if (!providerTable
|| index
>= providerTable
->numProviders
)
592 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
595 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
596 ret
->providerIndex
= index
;
597 ret
->dwScope
= dwScope
;
598 ret
->dwType
= dwType
;
599 ret
->dwUsage
= dwUsage
;
600 ret
->handle
= handle
;
606 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
609 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
610 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
614 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
615 ret
->dwScope
= dwScope
;
616 ret
->dwType
= dwType
;
617 ret
->dwUsage
= dwUsage
;
622 static PWNetEnumerator
_createConnectedEnumerator(DWORD dwScope
, DWORD dwType
,
625 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
628 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONNECTED
;
629 ret
->dwScope
= dwScope
;
630 ret
->dwType
= dwType
;
631 ret
->dwUsage
= dwUsage
;
632 ret
->specific
.handles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HANDLE
) * providerTable
->numProviders
);
633 if (!ret
->specific
.handles
)
635 HeapFree(GetProcessHeap(), 0, ret
);
642 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
643 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
644 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
645 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
646 * if not all members of the array could be thunked, and something else on
649 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
650 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
652 DWORD i
, numToThunk
, totalBytes
, ret
;
656 return WN_BAD_POINTER
;
658 return WN_BAD_POINTER
;
662 return WN_BAD_POINTER
;
664 return WN_BAD_POINTER
;
666 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
668 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
670 totalBytes
+= sizeof(NETRESOURCEA
);
671 if (lpNet
->lpLocalName
)
672 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
673 -1, NULL
, 0, NULL
, NULL
);
674 if (lpNet
->lpRemoteName
)
675 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
676 -1, NULL
, 0, NULL
, NULL
);
677 if (lpNet
->lpComment
)
678 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
679 -1, NULL
, 0, NULL
, NULL
);
680 if (lpNet
->lpProvider
)
681 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
682 -1, NULL
, 0, NULL
, NULL
);
683 if (totalBytes
< *lpBufferSize
)
686 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
687 for (i
= 0; i
< numToThunk
; i
++)
689 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
690 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
692 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
693 /* lie about string lengths, we already verified how many
694 * we have space for above
696 if (lpNetIn
->lpLocalName
)
698 lpNetOut
->lpLocalName
= strNext
;
699 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
700 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
702 if (lpNetIn
->lpRemoteName
)
704 lpNetOut
->lpRemoteName
= strNext
;
705 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
706 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
708 if (lpNetIn
->lpComment
)
710 lpNetOut
->lpComment
= strNext
;
711 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
712 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
714 if (lpNetIn
->lpProvider
)
716 lpNetOut
->lpProvider
= strNext
;
717 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
718 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
721 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
722 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
727 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
728 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
729 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
730 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
731 * if not all members of the array could be thunked, and something else on
734 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
735 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
737 DWORD i
, numToThunk
, totalBytes
, ret
;
741 return WN_BAD_POINTER
;
743 return WN_BAD_POINTER
;
747 return WN_BAD_POINTER
;
749 return WN_BAD_POINTER
;
751 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
753 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
755 totalBytes
+= sizeof(NETRESOURCEW
);
756 if (lpNet
->lpLocalName
)
757 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
758 -1, NULL
, 0) * sizeof(WCHAR
);
759 if (lpNet
->lpRemoteName
)
760 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
761 -1, NULL
, 0) * sizeof(WCHAR
);
762 if (lpNet
->lpComment
)
763 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
764 -1, NULL
, 0) * sizeof(WCHAR
);
765 if (lpNet
->lpProvider
)
766 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
767 -1, NULL
, 0) * sizeof(WCHAR
);
768 if (totalBytes
< *lpBufferSize
)
771 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
772 for (i
= 0; i
< numToThunk
; i
++)
774 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
775 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
777 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
778 /* lie about string lengths, we already verified how many
779 * we have space for above
781 if (lpNetIn
->lpLocalName
)
783 lpNetOut
->lpLocalName
= strNext
;
784 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
785 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
787 if (lpNetIn
->lpRemoteName
)
789 lpNetOut
->lpRemoteName
= strNext
;
790 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
791 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
793 if (lpNetIn
->lpComment
)
795 lpNetOut
->lpComment
= strNext
;
796 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
797 -1, lpNetOut
->lpComment
, *lpBufferSize
);
799 if (lpNetIn
->lpProvider
)
801 lpNetOut
->lpProvider
= strNext
;
802 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
803 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
806 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
807 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
812 /*********************************************************************
813 * WNetOpenEnumA [MPR.@]
815 * See comments for WNetOpenEnumW.
817 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
818 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
822 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
823 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
826 ret
= WN_BAD_POINTER
;
827 else if (!providerTable
|| providerTable
->numProviders
== 0)
836 LPNETRESOURCEW lpNetWide
= NULL
;
838 DWORD size
= sizeof(buf
), count
= 1;
839 BOOL allocated
= FALSE
;
841 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
842 if (ret
== WN_MORE_DATA
)
844 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
848 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
853 ret
= WN_OUT_OF_MEMORY
;
855 else if (ret
== WN_SUCCESS
)
856 lpNetWide
= (LPNETRESOURCEW
)buf
;
857 if (ret
== WN_SUCCESS
)
858 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
861 HeapFree(GetProcessHeap(), 0, lpNetWide
);
864 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
868 TRACE("Returning %d\n", ret
);
872 /*********************************************************************
873 * WNetOpenEnumW [MPR.@]
875 * Network enumeration has way too many parameters, so I'm not positive I got
876 * them right. What I've got so far:
878 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
879 * all the network providers should be enumerated.
881 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
882 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
883 * lpProvider is set, all the network providers should be enumerated.
884 * (This means the enumeration is a list of network providers, not that the
885 * enumeration is passed on to the providers.)
887 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
888 * resource matches the "Entire Network" resource (no remote name, no
889 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
890 * enumeration is done on every network provider.
892 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
893 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
894 * only to the given network provider.
896 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
897 * no lpProvider is set, enumeration will be tried on every network provider,
898 * in the order in which they're loaded.
900 * - The LPNETRESOURCE should be disregarded for scopes besides
901 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
902 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
904 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
905 * resource in the enumerated list, as well as any machines in your
906 * workgroup. The machines in your workgroup come from doing a
907 * RESOURCE_CONTEXT enumeration of every Network Provider.
909 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
910 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
914 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
915 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
918 ret
= WN_BAD_POINTER
;
919 else if (!providerTable
|| providerTable
->numProviders
== 0)
928 case RESOURCE_GLOBALNET
:
931 if (lpNet
->lpProvider
)
933 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
935 if (index
!= BAD_PROVIDER_INDEX
)
937 if (providerTable
->table
[index
].openEnum
&&
938 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
941 PWSTR RemoteName
= lpNet
->lpRemoteName
;
943 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
944 RemoteName
&& !strcmpW(RemoteName
, lpNet
->lpProvider
))
945 lpNet
->lpRemoteName
= NULL
;
947 ret
= providerTable
->table
[index
].openEnum(
948 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
949 if (ret
== WN_SUCCESS
)
951 *lphEnum
= _createProviderEnumerator(
952 dwScope
, dwType
, dwUsage
, index
, handle
);
953 ret
= *lphEnum
? WN_SUCCESS
:
957 lpNet
->lpRemoteName
= RemoteName
;
960 ret
= WN_NOT_SUPPORTED
;
963 ret
= WN_BAD_PROVIDER
;
965 else if (lpNet
->lpRemoteName
)
967 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
968 dwType
, dwUsage
, lpNet
);
969 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
973 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
974 providerTable
->entireNetwork
))
976 /* comment matches the "Entire Network", enumerate
977 * global scope of every provider
979 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
980 dwType
, dwUsage
, lpNet
);
984 /* this is the same as not having passed lpNet */
985 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
986 dwType
, dwUsage
, NULL
);
988 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
993 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
995 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
998 case RESOURCE_CONTEXT
:
999 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
1000 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1002 case RESOURCE_CONNECTED
:
1003 *lphEnum
= _createConnectedEnumerator(dwScope
, dwType
, dwUsage
);
1004 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1006 case RESOURCE_REMEMBERED
:
1007 *lphEnum
= _createNullEnumerator();
1008 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1011 WARN("unknown scope 0x%08x\n", dwScope
);
1017 TRACE("Returning %d\n", ret
);
1021 /*********************************************************************
1022 * WNetEnumResourceA [MPR.@]
1024 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
1025 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1029 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1032 ret
= WN_BAD_POINTER
;
1034 ret
= WN_BAD_POINTER
;
1036 ret
= WN_BAD_POINTER
;
1037 else if (!lpBufferSize
)
1038 ret
= WN_BAD_POINTER
;
1039 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
1041 *lpBufferSize
= sizeof(NETRESOURCEA
);
1046 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
1047 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
1051 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
1053 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
1055 /* FIXME: this isn't necessarily going to work in the case of
1056 * WN_MORE_DATA, because our enumerator may have moved on to
1057 * the next provider. MSDN states that a large (16KB) buffer
1058 * size is the appropriate usage of this function, so
1059 * hopefully it won't be an issue.
1061 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
1062 lpBuffer
, lpBufferSize
);
1063 *lpcCount
= localCount
;
1065 HeapFree(GetProcessHeap(), 0, localBuffer
);
1068 ret
= WN_OUT_OF_MEMORY
;
1072 TRACE("Returning %d\n", ret
);
1076 static DWORD
_countProviderBytesW(PWNetProvider provider
)
1082 ret
= sizeof(NETRESOURCEW
);
1083 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
1090 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1091 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
1096 return WN_BAD_POINTER
;
1097 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1098 return WN_BAD_VALUE
;
1100 return WN_BAD_POINTER
;
1102 return WN_BAD_POINTER
;
1104 return WN_BAD_POINTER
;
1105 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
1106 return WN_MORE_DATA
;
1108 if (!providerTable
|| enumerator
->providerIndex
>=
1109 providerTable
->numProviders
)
1110 ret
= WN_NO_MORE_ENTRIES
;
1113 DWORD bytes
= 0, count
= 0, countLimit
, i
;
1114 LPNETRESOURCEW resource
;
1117 countLimit
= *lpcCount
== -1 ?
1118 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
1119 while (count
< countLimit
&& bytes
< *lpBufferSize
)
1121 DWORD bytesNext
= _countProviderBytesW(
1122 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
1124 if (bytes
+ bytesNext
< *lpBufferSize
)
1130 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
1131 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
1133 resource
->dwScope
= RESOURCE_GLOBALNET
;
1134 resource
->dwType
= RESOURCETYPE_ANY
;
1135 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
1136 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
1137 RESOURCEUSAGE_RESERVED
;
1138 resource
->lpLocalName
= NULL
;
1139 resource
->lpRemoteName
= strNext
;
1140 strcpyW(resource
->lpRemoteName
,
1141 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1142 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
1143 resource
->lpComment
= NULL
;
1144 resource
->lpProvider
= strNext
;
1145 strcpyW(resource
->lpProvider
,
1146 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1147 strNext
+= strlenW(resource
->lpProvider
) + 1;
1149 enumerator
->providerIndex
+= count
;
1151 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
1153 TRACE("Returning %d\n", ret
);
1157 /* Advances the enumerator (assumed to be a global enumerator) to the next
1158 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1159 * not open a handle with the next provider.
1160 * If the existing handle is NULL, may leave the enumerator unchanged, since
1161 * the current provider may support the desired scope.
1162 * If the existing handle is not NULL, closes it before moving on.
1163 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1164 * provider, and another error on failure.
1166 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
1169 return WN_BAD_POINTER
;
1170 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1171 return WN_BAD_VALUE
;
1172 if (!providerTable
|| enumerator
->providerIndex
>=
1173 providerTable
->numProviders
)
1174 return WN_NO_MORE_ENTRIES
;
1176 if (enumerator
->providerDone
)
1179 enumerator
->providerDone
= FALSE
;
1180 if (enumerator
->handle
)
1182 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1183 enumerator
->handle
);
1184 enumerator
->handle
= NULL
;
1185 enumerator
->providerIndex
++;
1187 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1188 dwEnum
= WNNC_ENUM_LOCAL
;
1189 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1190 dwEnum
= WNNC_ENUM_GLOBAL
;
1191 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1192 dwEnum
= WNNC_ENUM_CONTEXT
;
1193 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1194 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1195 & dwEnum
); enumerator
->providerIndex
++)
1198 return enumerator
->providerIndex
< providerTable
->numProviders
?
1199 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1202 /* "Passes through" call to the next provider that supports the enumeration
1204 * FIXME: if one call to a provider's enumerator succeeds while there's still
1205 * space in lpBuffer, I don't call to the next provider. The caller may not
1206 * expect that it should call EnumResourceW again with a return value of
1207 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1208 * may have to be moved around a bit, ick.
1210 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1211 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1216 return WN_BAD_POINTER
;
1217 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1218 return WN_BAD_VALUE
;
1220 return WN_BAD_POINTER
;
1222 return WN_BAD_POINTER
;
1224 return WN_BAD_POINTER
;
1225 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1226 return WN_MORE_DATA
;
1228 ret
= _globalEnumeratorAdvance(enumerator
);
1229 if (ret
== WN_SUCCESS
)
1231 ret
= providerTable
->table
[enumerator
->providerIndex
].
1232 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1233 enumerator
->dwUsage
, enumerator
->specific
.net
,
1234 &enumerator
->handle
);
1235 if (ret
== WN_SUCCESS
)
1237 ret
= providerTable
->table
[enumerator
->providerIndex
].
1238 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1240 if (ret
!= WN_MORE_DATA
)
1241 enumerator
->providerDone
= TRUE
;
1244 TRACE("Returning %d\n", ret
);
1248 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1249 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1254 return WN_BAD_POINTER
;
1255 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1256 return WN_BAD_VALUE
;
1258 return WN_BAD_POINTER
;
1260 return WN_BAD_POINTER
;
1262 return WN_BAD_POINTER
;
1263 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1264 return WN_MORE_DATA
;
1266 return WN_NO_NETWORK
;
1268 switch (enumerator
->dwScope
)
1270 case RESOURCE_GLOBALNET
:
1271 if (enumerator
->specific
.net
)
1272 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1273 lpBuffer
, lpBufferSize
);
1275 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1278 case RESOURCE_CONTEXT
:
1279 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1283 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1284 ret
= WN_NO_MORE_ENTRIES
;
1286 TRACE("Returning %d\n", ret
);
1290 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1291 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1294 return WN_BAD_POINTER
;
1295 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1296 return WN_BAD_VALUE
;
1297 if (!enumerator
->handle
)
1298 return WN_BAD_VALUE
;
1300 return WN_BAD_POINTER
;
1302 return WN_BAD_POINTER
;
1304 return WN_BAD_POINTER
;
1306 return WN_NO_NETWORK
;
1307 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1308 return WN_NO_MORE_ENTRIES
;
1309 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1310 return WN_BAD_VALUE
;
1311 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1312 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1315 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1316 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1319 size_t cchEntireNetworkLen
, bytesNeeded
;
1322 return WN_BAD_POINTER
;
1323 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
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
;
1334 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1335 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1336 if (*lpBufferSize
< bytesNeeded
)
1338 *lpBufferSize
= bytesNeeded
;
1343 LPNETRESOURCEW lpNet
= lpBuffer
;
1345 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1346 lpNet
->dwType
= enumerator
->dwType
;
1347 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1348 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1349 lpNet
->lpLocalName
= NULL
;
1350 lpNet
->lpRemoteName
= NULL
;
1351 lpNet
->lpProvider
= NULL
;
1352 /* odd, but correct: put comment at end of buffer, so it won't get
1353 * overwritten by subsequent calls to a provider's enumResource
1355 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1356 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1357 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1360 if (ret
== WN_SUCCESS
)
1362 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1364 /* "Entire Network" entry enumerated--morph this into a global
1365 * enumerator. enumerator->lpNet continues to be NULL, since it has
1366 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1368 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1369 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1370 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1371 if (ret
== WN_SUCCESS
)
1373 /* reflect the fact that we already enumerated "Entire Network" */
1375 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1379 /* the provider enumeration failed, but we already succeeded in
1380 * enumerating "Entire Network"--leave type as global to allow a
1381 * retry, but indicate success with a count of one.
1385 *lpBufferSize
= bytesNeeded
;
1388 TRACE("Returning %d\n", ret
);
1392 static DWORD
_copyStringToEnumW(const WCHAR
*source
, DWORD
* left
, void** end
)
1395 WCHAR
* local
= *end
;
1397 len
= strlenW(source
) + 1;
1398 len
*= sizeof(WCHAR
);
1400 return WN_MORE_DATA
;
1402 local
-= (len
/ sizeof(WCHAR
));
1403 memcpy(local
, source
, len
);
1410 static DWORD
_enumerateConnectedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1411 void* user_buffer
, DWORD
* user_size
)
1413 DWORD ret
, index
, count
, total_count
, size
, i
, left
;
1415 NETRESOURCEW
* curr
, * buffer
;
1419 return WN_BAD_POINTER
;
1420 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONNECTED
)
1421 return WN_BAD_VALUE
;
1422 if (!user_count
|| !user_buffer
|| !user_size
)
1423 return WN_BAD_POINTER
;
1425 return WN_NO_NETWORK
;
1427 handles
= enumerator
->specific
.handles
;
1430 buffer
= HeapAlloc(GetProcessHeap(), 0, *user_size
);
1432 return WN_NO_NETWORK
;
1435 end
= (char *)user_buffer
+ size
;
1436 count
= *user_count
;
1439 ret
= WN_NO_MORE_ENTRIES
;
1440 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1442 if (providerTable
->table
[index
].dwEnumScopes
)
1444 if (handles
[index
] == 0)
1446 ret
= providerTable
->table
[index
].openEnum(enumerator
->dwScope
,
1448 enumerator
->dwUsage
,
1449 NULL
, &handles
[index
]);
1450 if (ret
!= WN_SUCCESS
)
1454 ret
= providerTable
->table
[index
].enumResource(handles
[index
],
1457 total_count
+= count
;
1458 if (ret
== WN_MORE_DATA
)
1461 if (ret
== WN_SUCCESS
)
1463 for (i
= 0; i
< count
; ++i
)
1465 if (left
< sizeof(NETRESOURCEW
))
1471 memcpy(curr
, &buffer
[i
], sizeof(NETRESOURCEW
));
1472 left
-= sizeof(NETRESOURCEW
);
1474 ret
= _copyStringToEnumW(buffer
[i
].lpLocalName
, &left
, &end
);
1475 if (ret
== WN_MORE_DATA
)
1477 curr
->lpLocalName
= end
;
1479 ret
= _copyStringToEnumW(buffer
[i
].lpRemoteName
, &left
, &end
);
1480 if (ret
== WN_MORE_DATA
)
1482 curr
->lpRemoteName
= end
;
1484 ret
= _copyStringToEnumW(buffer
[i
].lpProvider
, &left
, &end
);
1485 if (ret
== WN_MORE_DATA
)
1487 curr
->lpProvider
= end
;
1495 if (*user_count
!= -1)
1496 count
= *user_count
- total_count
;
1498 count
= *user_count
;
1502 if (total_count
== 0)
1503 ret
= WN_NO_MORE_ENTRIES
;
1505 *user_count
= total_count
;
1506 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1509 HeapFree(GetProcessHeap(), 0, buffer
);
1511 TRACE("Returning %d\n", ret
);
1515 /*********************************************************************
1516 * WNetEnumResourceW [MPR.@]
1518 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1519 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1523 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1526 ret
= WN_BAD_POINTER
;
1528 ret
= WN_BAD_POINTER
;
1530 ret
= WN_BAD_POINTER
;
1531 else if (!lpBufferSize
)
1532 ret
= WN_BAD_POINTER
;
1533 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1535 *lpBufferSize
= sizeof(NETRESOURCEW
);
1540 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1542 switch (enumerator
->enumType
)
1544 case WNET_ENUMERATOR_TYPE_NULL
:
1545 ret
= WN_NO_MORE_ENTRIES
;
1547 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1548 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1551 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1552 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1555 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1556 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1559 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1560 ret
= _enumerateConnectedW(enumerator
, lpcCount
, lpBuffer
,
1564 WARN("bogus enumerator type!\n");
1565 ret
= WN_NO_NETWORK
;
1570 TRACE("Returning %d\n", ret
);
1574 /*********************************************************************
1575 * WNetCloseEnum [MPR.@]
1577 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1582 TRACE( "(%p)\n", hEnum
);
1586 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1588 switch (enumerator
->enumType
)
1590 case WNET_ENUMERATOR_TYPE_NULL
:
1593 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1594 if (enumerator
->specific
.net
)
1595 _freeEnumNetResource(enumerator
->specific
.net
);
1596 if (enumerator
->handle
)
1597 providerTable
->table
[enumerator
->providerIndex
].
1598 closeEnum(enumerator
->handle
);
1601 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1602 if (enumerator
->handle
)
1603 providerTable
->table
[enumerator
->providerIndex
].
1604 closeEnum(enumerator
->handle
);
1607 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1608 handles
= enumerator
->specific
.handles
;
1609 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1611 if (providerTable
->table
[index
].dwEnumScopes
&& handles
[index
])
1612 providerTable
->table
[index
].closeEnum(handles
[index
]);
1614 HeapFree(GetProcessHeap(), 0, handles
);
1618 WARN("bogus enumerator type!\n");
1619 ret
= WN_BAD_HANDLE
;
1621 HeapFree(GetProcessHeap(), 0, hEnum
);
1624 ret
= WN_BAD_HANDLE
;
1627 TRACE("Returning %d\n", ret
);
1631 /*********************************************************************
1632 * WNetGetResourceInformationA [MPR.@]
1634 * See WNetGetResourceInformationW
1636 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1637 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1642 TRACE( "(%p, %p, %p, %p)\n",
1643 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1645 if (!providerTable
|| providerTable
->numProviders
== 0)
1646 ret
= WN_NO_NETWORK
;
1647 else if (lpNetResource
)
1649 LPNETRESOURCEW lpNetResourceW
= NULL
;
1650 DWORD size
= 1024, count
= 1;
1653 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1654 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1655 if (ret
== WN_MORE_DATA
)
1657 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1658 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1660 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1661 &count
, lpNetResourceW
, &size
);
1663 ret
= WN_OUT_OF_MEMORY
;
1665 if (ret
== WN_SUCCESS
)
1667 LPWSTR lpSystemW
= NULL
;
1670 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1673 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1674 lpBufferW
, &size
, &lpSystemW
);
1675 if (ret
== WN_MORE_DATA
)
1677 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1678 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1680 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1681 lpBufferW
, &size
, &lpSystemW
);
1683 ret
= WN_OUT_OF_MEMORY
;
1685 if (ret
== WN_SUCCESS
)
1687 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1688 &count
, lpBuffer
, cbBuffer
);
1689 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1690 lpNetResourceW
= lpBufferW
;
1691 size
= sizeof(NETRESOURCEA
);
1692 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1693 -1, NULL
, 0, NULL
, NULL
);
1694 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1695 -1, NULL
, 0, NULL
, NULL
);
1697 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1698 -1, NULL
, 0, NULL
, NULL
);
1699 if ((len
) && ( size
+ len
< *cbBuffer
))
1701 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1702 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1703 *lplpSystem
, len
, NULL
, NULL
);
1710 ret
= WN_OUT_OF_MEMORY
;
1711 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1714 ret
= WN_OUT_OF_MEMORY
;
1715 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1717 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1720 ret
= WN_NO_NETWORK
;
1724 TRACE("Returning %d\n", ret
);
1728 /*********************************************************************
1729 * WNetGetResourceInformationW [MPR.@]
1731 * WNetGetResourceInformationW function identifies the network provider
1732 * that owns the resource and gets information about the type of the resource.
1735 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1736 * defines a network resource.
1737 * lpBuffer [ O] the pointer to buffer, containing result. It
1738 * contains NETRESOURCEW structure and strings to
1739 * which the members of the NETRESOURCEW structure
1741 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1743 * lplpSystem [ O] the pointer to string in the output buffer,
1744 * containing the part of the resource name without
1745 * names of the server and share.
1748 * NO_ERROR if the function succeeds. System error code if the function fails.
1751 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1752 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1753 LPWSTR
*lplpSystem
)
1755 DWORD ret
= WN_NO_NETWORK
;
1758 TRACE( "(%p, %p, %p, %p)\n",
1759 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1762 ret
= WN_OUT_OF_MEMORY
;
1763 else if (providerTable
!= NULL
)
1765 /* FIXME: For function value of a variable is indifferent, it does
1766 * search of all providers in a network.
1768 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1770 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1771 WNNC_DLG_GETRESOURCEINFORMATION
)
1773 if (providerTable
->table
[index
].getResourceInformation
)
1774 ret
= providerTable
->table
[index
].getResourceInformation(
1775 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1777 ret
= WN_NO_NETWORK
;
1778 if (ret
== WN_SUCCESS
)
1788 /*********************************************************************
1789 * WNetGetResourceParentA [MPR.@]
1791 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1792 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1794 FIXME( "(%p, %p, %p): stub\n",
1795 lpNetResource
, lpBuffer
, lpBufferSize
);
1797 SetLastError(WN_NO_NETWORK
);
1798 return WN_NO_NETWORK
;
1801 /*********************************************************************
1802 * WNetGetResourceParentW [MPR.@]
1804 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1805 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1807 FIXME( "(%p, %p, %p): stub\n",
1808 lpNetResource
, lpBuffer
, lpBufferSize
);
1810 SetLastError(WN_NO_NETWORK
);
1811 return WN_NO_NETWORK
;
1817 * Connection Functions
1820 /*********************************************************************
1821 * WNetAddConnectionA [MPR.@]
1823 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1824 LPCSTR lpLocalName
)
1826 NETRESOURCEA resourcesA
;
1828 memset(&resourcesA
, 0, sizeof(resourcesA
));
1829 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
1830 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
1831 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1834 /*********************************************************************
1835 * WNetAddConnectionW [MPR.@]
1837 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1838 LPCWSTR lpLocalName
)
1840 NETRESOURCEW resourcesW
;
1842 memset(&resourcesW
, 0, sizeof(resourcesW
));
1843 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
1844 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
1845 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1848 /*********************************************************************
1849 * WNetAddConnection2A [MPR.@]
1851 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1852 LPCSTR lpPassword
, LPCSTR lpUserID
,
1855 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1859 /*********************************************************************
1860 * WNetAddConnection2W [MPR.@]
1862 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1863 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1866 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1870 /*********************************************************************
1871 * WNetAddConnection3A [MPR.@]
1873 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1874 LPCSTR lpPassword
, LPCSTR lpUserID
,
1877 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1878 dwFlags
, NULL
, 0, NULL
);
1881 /*********************************************************************
1882 * WNetAddConnection3W [MPR.@]
1884 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1885 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1888 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1889 dwFlags
, NULL
, 0, NULL
);
1892 struct use_connection_context
1895 NETRESOURCEW
*resource
;
1896 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
1903 DWORD (*pre_set_accessname
)(struct use_connection_context
*, WCHAR
*);
1904 void (*set_accessname
)(struct use_connection_context
*, WCHAR
*);
1907 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1909 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1914 len
= strlenW(local_name
);
1916 len
= strlenW(ctxt
->resource
->lpRemoteName
);
1918 if (++len
> *ctxt
->buffer_size
)
1920 *ctxt
->buffer_size
= len
;
1921 return ERROR_MORE_DATA
;
1925 ctxt
->accessname
= NULL
;
1927 return ERROR_SUCCESS
;
1930 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1932 WCHAR
*accessname
= ctxt
->accessname
;
1935 strcpyW(accessname
, local_name
);
1937 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1940 strcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
1943 static DWORD
wnet_use_provider( struct use_connection_context
*ctxt
, NETRESOURCEW
* netres
, WNetProvider
*provider
, BOOLEAN redirect
)
1947 caps
= provider
->getCaps(WNNC_CONNECTION
);
1948 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
1949 return ERROR_BAD_PROVIDER
;
1951 ret
= WN_ACCESS_DENIED
;
1954 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
1955 ret
= provider
->addConnection3(ctxt
->hwndOwner
, netres
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
1956 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
1957 ret
= provider
->addConnection(netres
, ctxt
->password
, ctxt
->userid
);
1959 if (ret
== WN_ALREADY_CONNECTED
&& redirect
)
1960 netres
->lpLocalName
[0] -= 1;
1961 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& netres
->lpLocalName
[0] >= 'C');
1963 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
1964 ctxt
->set_accessname(ctxt
, netres
->lpLocalName
);
1969 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
1971 WNetProvider
*provider
;
1972 DWORD index
, ret
= WN_NO_NETWORK
;
1973 BOOL redirect
= FALSE
;
1974 WCHAR letter
[3] = {'Z', ':', 0};
1975 NETRESOURCEW netres
;
1977 if (!providerTable
|| providerTable
->numProviders
== 0)
1978 return WN_NO_NETWORK
;
1980 if (!ctxt
->resource
)
1981 return ERROR_INVALID_PARAMETER
;
1982 netres
= *ctxt
->resource
;
1984 if (!netres
.lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
1986 if (netres
.dwType
!= RESOURCETYPE_DISK
&& netres
.dwType
!= RESOURCETYPE_PRINT
)
1987 return ERROR_BAD_DEV_TYPE
;
1989 if (netres
.dwType
== RESOURCETYPE_PRINT
)
1991 FIXME("Local device selection is not implemented for printers.\n");
1992 return WN_NO_NETWORK
;
1996 netres
.lpLocalName
= letter
;
1999 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
2000 return ERROR_BAD_NET_NAME
;
2002 if ((ret
= ctxt
->pre_set_accessname(ctxt
, netres
.lpLocalName
)))
2005 if (netres
.lpProvider
)
2007 index
= _findProviderIndexW(netres
.lpProvider
);
2008 if (index
== BAD_PROVIDER_INDEX
)
2009 return ERROR_BAD_PROVIDER
;
2011 provider
= &providerTable
->table
[index
];
2012 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2016 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2018 provider
= &providerTable
->table
[index
];
2019 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2020 if (ret
== WN_SUCCESS
|| ret
== WN_ALREADY_CONNECTED
)
2026 if (ret
== WN_SUCCESS
&& ctxt
->flags
& CONNECT_UPDATE_PROFILE
)
2030 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2032 FIXME("Persistent connection are not supported for printers\n");
2036 if (RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2039 WCHAR subkey
[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres
.lpLocalName
[0], 0};
2041 if (RegCreateKeyExW(user_profile
, subkey
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &network
, NULL
) == ERROR_SUCCESS
)
2043 DWORD dword_arg
= RESOURCETYPE_DISK
;
2044 DWORD len
= (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
2046 RegSetValueExW(network
, L
"ConnectionType", 0, REG_DWORD
, (const BYTE
*)&dword_arg
, sizeof(DWORD
));
2047 RegSetValueExW(network
, L
"ProviderName", 0, REG_SZ
, (const BYTE
*)provider
->name
, len
);
2048 dword_arg
= provider
->dwNetType
;
2049 RegSetValueExW(network
, L
"ProviderType", 0, REG_DWORD
, (const BYTE
*)&dword_arg
, sizeof(DWORD
));
2050 len
= (strlenW(netres
.lpRemoteName
) + 1) * sizeof(WCHAR
);
2051 RegSetValueExW(network
, L
"RemotePath", 0, REG_SZ
, (const BYTE
*)netres
.lpRemoteName
, len
);
2053 RegSetValueExW(network
, L
"UserName", 0, REG_SZ
, (const BYTE
*)netres
.lpRemoteName
, len
);
2054 RegCloseKey(network
);
2057 RegCloseKey(user_profile
);
2065 /*****************************************************************
2066 * WNetUseConnectionW [MPR.@]
2068 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
2069 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
2071 struct use_connection_context ctxt
;
2073 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
2074 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
2075 accessname
, buffer_size
, result
);
2077 ctxt
.hwndOwner
= hwndOwner
;
2078 ctxt
.resource
= resource
;
2079 ctxt
.resourceA
= NULL
;
2080 ctxt
.password
= (WCHAR
*)password
;
2081 ctxt
.userid
= (WCHAR
*)userid
;
2083 ctxt
.accessname
= accessname
;
2084 ctxt
.buffer_size
= buffer_size
;
2085 ctxt
.result
= result
;
2086 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
2087 ctxt
.set_accessname
= use_connection_set_accessnameW
;
2089 return wnet_use_connection(&ctxt
);
2092 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2094 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
2099 len
= WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, NULL
, 0, NULL
, NULL
) - 1;
2101 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
2103 if (++len
> *ctxt
->buffer_size
)
2105 *ctxt
->buffer_size
= len
;
2106 return ERROR_MORE_DATA
;
2110 ctxt
->accessname
= NULL
;
2112 return ERROR_SUCCESS
;
2115 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2117 char *accessname
= ctxt
->accessname
;
2120 WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, accessname
, *ctxt
->buffer_size
, NULL
, NULL
);
2122 *ctxt
->result
= CONNECT_LOCALDRIVE
;
2125 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
2128 static LPWSTR
strdupAtoW( LPCSTR str
)
2133 if (!str
) return NULL
;
2134 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
2135 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2136 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
2140 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
2142 resourceW
->dwScope
= resourceA
->dwScope
;
2143 resourceW
->dwType
= resourceA
->dwType
;
2144 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
2145 resourceW
->dwUsage
= resourceA
->dwUsage
;
2146 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
2147 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
2148 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
2149 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
2152 static void free_netresourceW( NETRESOURCEW
*resource
)
2154 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
2155 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
2156 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
2157 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
2160 /*****************************************************************
2161 * WNetUseConnectionA [MPR.@]
2163 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
2164 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
2165 DWORD
*buffer_size
, DWORD
*result
)
2167 struct use_connection_context ctxt
;
2168 NETRESOURCEW resourceW
;
2171 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
2172 accessname
, buffer_size
, result
);
2174 netresource_a_to_w(resource
, &resourceW
);
2176 ctxt
.hwndOwner
= hwndOwner
;
2177 ctxt
.resource
= &resourceW
;
2178 ctxt
.resourceA
= resource
;
2179 ctxt
.password
= strdupAtoW(password
);
2180 ctxt
.userid
= strdupAtoW(userid
);
2182 ctxt
.accessname
= accessname
;
2183 ctxt
.buffer_size
= buffer_size
;
2184 ctxt
.result
= result
;
2185 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
2186 ctxt
.set_accessname
= use_connection_set_accessnameA
;
2188 ret
= wnet_use_connection(&ctxt
);
2190 free_netresourceW(&resourceW
);
2191 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
2192 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
2197 /*********************************************************************
2198 * WNetCancelConnectionA [MPR.@]
2200 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
2202 return WNetCancelConnection2A(lpName
, 0, fForce
);
2205 /*********************************************************************
2206 * WNetCancelConnectionW [MPR.@]
2208 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
2210 return WNetCancelConnection2W(lpName
, 0, fForce
);
2213 /*********************************************************************
2214 * WNetCancelConnection2A [MPR.@]
2216 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2219 WCHAR
* name
= strdupAtoW(lpName
);
2221 return ERROR_NOT_CONNECTED
;
2223 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
2224 HeapFree(GetProcessHeap(), 0, name
);
2229 /*********************************************************************
2230 * WNetCancelConnection2W [MPR.@]
2232 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2234 DWORD ret
= WN_NO_NETWORK
;
2237 if (providerTable
!= NULL
)
2239 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2241 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2242 WNNC_CON_CANCELCONNECTION
)
2244 if (providerTable
->table
[index
].cancelConnection
)
2245 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
2247 ret
= WN_NO_NETWORK
;
2248 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
2255 if (dwFlags
& CONNECT_UPDATE_PROFILE
)
2258 WCHAR
*coma
= strchrW(lpName
, ':');
2260 if (coma
&& RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2265 len
= (ULONG_PTR
)coma
- (ULONG_PTR
)lpName
+ sizeof(L
"Network\\");
2266 subkey
= HeapAlloc(GetProcessHeap(), 0, len
);
2269 strcpyW(subkey
, L
"Network\\");
2270 memcpy(subkey
+ (sizeof(L
"Network\\") / sizeof(WCHAR
)) - 1, lpName
, (ULONG_PTR
)coma
- (ULONG_PTR
)lpName
);
2271 subkey
[len
/ sizeof(WCHAR
) - 1] = 0;
2273 TRACE("Removing: %S\n", subkey
);
2275 RegDeleteKeyW(user_profile
, subkey
);
2276 HeapFree(GetProcessHeap(), 0, subkey
);
2279 RegCloseKey(user_profile
);
2287 /*****************************************************************
2288 * WNetRestoreConnectionA [MPR.@]
2290 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
2292 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
2294 SetLastError(WN_NO_NETWORK
);
2295 return WN_NO_NETWORK
;
2298 /*****************************************************************
2299 * WNetRestoreConnectionW [MPR.@]
2301 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
2303 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
2305 SetLastError(WN_NO_NETWORK
);
2306 return WN_NO_NETWORK
;
2309 /**************************************************************************
2310 * WNetGetConnectionA [MPR.@]
2313 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2314 * - WN_NOT_CONNECTED drive is a local drive
2315 * - WN_MORE_DATA buffer isn't big enough
2316 * - WN_SUCCESS success (net path in buffer)
2318 * FIXME: need to test return values under different errors
2320 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
2321 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
2326 ret
= WN_BAD_POINTER
;
2327 else if (!lpBufferSize
)
2328 ret
= WN_BAD_POINTER
;
2329 else if (!lpRemoteName
&& *lpBufferSize
)
2330 ret
= WN_BAD_POINTER
;
2333 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
2337 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2341 WCHAR wideRemoteStatic
[MAX_PATH
];
2342 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
2344 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
2346 /* try once without memory allocation */
2347 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
2349 if (ret
== WN_SUCCESS
)
2351 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2352 -1, NULL
, 0, NULL
, NULL
);
2354 if (len
<= *lpBufferSize
)
2356 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
2357 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2362 *lpBufferSize
= len
;
2366 else if (ret
== WN_MORE_DATA
)
2368 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2369 wideRemoteSize
* sizeof(WCHAR
));
2373 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2375 if (ret
== WN_SUCCESS
)
2377 if (len
<= *lpBufferSize
)
2379 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2380 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2385 *lpBufferSize
= len
;
2389 HeapFree(GetProcessHeap(), 0, wideRemote
);
2392 ret
= WN_OUT_OF_MEMORY
;
2394 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2397 ret
= WN_OUT_OF_MEMORY
;
2400 ret
= WN_BAD_LOCALNAME
;
2404 TRACE("Returning %d\n", ret
);
2408 /* find the network connection for a given drive; helper for WNetGetConnection */
2409 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2413 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2415 DWORD ret
= WN_NOT_CONNECTED
;
2416 DWORD bytes_returned
;
2418 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2419 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2420 0, 0 )) == INVALID_HANDLE_VALUE
)
2422 ERR( "failed to open mount manager err %u\n", GetLastError() );
2425 memset( data
, 0, sizeof(*data
) );
2426 data
->letter
= letter
;
2427 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2428 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2430 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2433 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2436 mount_point
[0] = '\\';
2437 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2439 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2447 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2455 DWORD ret
= WN_NO_NETWORK
;
2457 WCHAR local
[3] = {letter
, ':', 0};
2459 if (providerTable
!= NULL
)
2461 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2463 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2464 WNNC_CON_GETCONNECTIONS
)
2466 if (providerTable
->table
[index
].getConnection
)
2467 ret
= providerTable
->table
[index
].getConnection(
2468 local
, remote
, size
);
2470 ret
= WN_NO_NETWORK
;
2471 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2482 /**************************************************************************
2483 * WNetGetConnectionW [MPR.@]
2485 * FIXME: need to test return values under different errors
2487 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2488 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2492 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2496 ret
= WN_BAD_POINTER
;
2497 else if (!lpBufferSize
)
2498 ret
= WN_BAD_POINTER
;
2499 else if (!lpRemoteName
&& *lpBufferSize
)
2500 ret
= WN_BAD_POINTER
;
2501 else if (!lpLocalName
[0])
2502 ret
= WN_BAD_LOCALNAME
;
2505 if (lpLocalName
[1] == ':')
2507 switch(GetDriveTypeW(lpLocalName
))
2510 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2512 case DRIVE_REMOVABLE
:
2515 TRACE("file is local\n");
2516 ret
= WN_NOT_CONNECTED
;
2519 ret
= WN_BAD_LOCALNAME
;
2523 ret
= WN_BAD_LOCALNAME
;
2527 TRACE("Returning %d\n", ret
);
2531 /**************************************************************************
2532 * WNetSetConnectionA [MPR.@]
2534 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2537 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2539 SetLastError(WN_NO_NETWORK
);
2540 return WN_NO_NETWORK
;
2543 /**************************************************************************
2544 * WNetSetConnectionW [MPR.@]
2546 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2549 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2551 SetLastError(WN_NO_NETWORK
);
2552 return WN_NO_NETWORK
;
2555 /*****************************************************************
2556 * WNetGetUniversalNameA [MPR.@]
2558 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2559 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2563 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2564 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2566 switch (dwInfoLevel
)
2568 case UNIVERSAL_NAME_INFO_LEVEL
:
2570 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2572 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2574 err
= ERROR_NOT_CONNECTED
;
2578 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2579 if (*lpBufferSize
< size
)
2584 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2585 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2589 case REMOTE_NAME_INFO_LEVEL
:
2590 err
= WN_NOT_CONNECTED
;
2602 /*****************************************************************
2603 * WNetGetUniversalNameW [MPR.@]
2605 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2606 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2610 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2611 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2613 switch (dwInfoLevel
)
2615 case UNIVERSAL_NAME_INFO_LEVEL
:
2617 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2619 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2621 err
= ERROR_NOT_CONNECTED
;
2625 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2626 if (*lpBufferSize
< size
)
2631 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2632 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2636 case REMOTE_NAME_INFO_LEVEL
:
2637 err
= WN_NO_NETWORK
;
2645 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2650 /*****************************************************************
2651 * WNetClearConnections [MPR.@]
2653 DWORD WINAPI
WNetClearConnections ( DWORD unknown
)
2656 DWORD ret
, size
, count
;
2657 NETRESOURCEW
* resources
, * iter
;
2659 ret
= WNetOpenEnumW(RESOURCE_CONNECTED
, RESOURCETYPE_ANY
, 0, NULL
, &connected
);
2660 if (ret
!= WN_SUCCESS
)
2662 if (ret
!= WN_NO_NETWORK
)
2667 /* Means no provider, then, clearing is OK */
2672 resources
= HeapAlloc(GetProcessHeap(), 0, size
);
2675 WNetCloseEnum(connected
);
2676 return WN_OUT_OF_MEMORY
;
2684 memset(resources
, 0, size
);
2685 ret
= WNetEnumResourceW(connected
, &count
, resources
, &size
);
2686 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2689 for (; count
; count
--)
2691 WNetCancelConnection2W(iter
->lpLocalName
, 0, TRUE
);
2698 } while (ret
!= WN_NO_MORE_ENTRIES
);
2700 HeapFree(GetProcessHeap(), 0, resources
);
2701 WNetCloseEnum(connected
);
2713 /**************************************************************************
2714 * WNetGetUserA [MPR.@]
2716 * FIXME: we should not return ourselves, but the owner of the drive lpName
2718 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2720 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2721 return GetLastError();
2724 /*****************************************************************
2725 * WNetGetUserW [MPR.@]
2727 * FIXME: we should not return ourselves, but the owner of the drive lpName
2729 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2731 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2732 return GetLastError();
2735 /*********************************************************************
2736 * WNetConnectionDialog [MPR.@]
2738 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2740 CONNECTDLGSTRUCTW conn_dlg
;
2741 NETRESOURCEW net_res
;
2743 ZeroMemory(&conn_dlg
, sizeof(conn_dlg
));
2744 ZeroMemory(&net_res
, sizeof(net_res
));
2746 conn_dlg
.cbStructure
= sizeof(conn_dlg
);
2747 conn_dlg
.lpConnRes
= &net_res
;
2748 conn_dlg
.hwndOwner
= hwnd
;
2749 net_res
.dwType
= dwType
;
2751 return WNetConnectionDialog1W(&conn_dlg
);
2754 /*********************************************************************
2755 * WNetConnectionDialog1A [MPR.@]
2757 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2759 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2761 SetLastError(WN_NO_NETWORK
);
2762 return WN_NO_NETWORK
;
2765 /*********************************************************************
2766 * WNetConnectionDialog1W [MPR.@]
2768 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2770 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2772 SetLastError(WN_NO_NETWORK
);
2773 return WN_NO_NETWORK
;
2776 /*********************************************************************
2777 * WNetDisconnectDialog [MPR.@]
2779 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2781 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2783 SetLastError(WN_NO_NETWORK
);
2784 return WN_NO_NETWORK
;
2787 /*********************************************************************
2788 * WNetDisconnectDialog1A [MPR.@]
2790 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2792 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2794 SetLastError(WN_NO_NETWORK
);
2795 return WN_NO_NETWORK
;
2798 /*********************************************************************
2799 * WNetDisconnectDialog1W [MPR.@]
2801 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2803 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2805 SetLastError(WN_NO_NETWORK
);
2806 return WN_NO_NETWORK
;
2809 /*********************************************************************
2810 * WNetGetLastErrorA [MPR.@]
2812 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2813 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2814 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2816 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2817 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2819 SetLastError(WN_NO_NETWORK
);
2820 return WN_NO_NETWORK
;
2823 /*********************************************************************
2824 * WNetGetLastErrorW [MPR.@]
2826 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2827 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2828 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2830 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2831 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2833 SetLastError(WN_NO_NETWORK
);
2834 return WN_NO_NETWORK
;
2837 /*********************************************************************
2838 * WNetGetNetworkInformationA [MPR.@]
2840 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2841 LPNETINFOSTRUCT lpNetInfoStruct
)
2845 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2848 ret
= WN_BAD_POINTER
;
2853 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2856 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2860 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2862 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2863 HeapFree(GetProcessHeap(), 0, wideProvider
);
2866 ret
= WN_OUT_OF_MEMORY
;
2869 ret
= GetLastError();
2873 TRACE("Returning %d\n", ret
);
2877 /*********************************************************************
2878 * WNetGetNetworkInformationW [MPR.@]
2880 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2881 LPNETINFOSTRUCT lpNetInfoStruct
)
2885 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2888 ret
= WN_BAD_POINTER
;
2889 else if (!lpNetInfoStruct
)
2890 ret
= WN_BAD_POINTER
;
2891 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2895 if (providerTable
&& providerTable
->numProviders
)
2897 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2899 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2901 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2902 lpNetInfoStruct
->dwProviderVersion
=
2903 providerTable
->table
[providerIndex
].dwSpecVersion
;
2904 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2905 lpNetInfoStruct
->dwCharacteristics
= 0;
2906 lpNetInfoStruct
->dwHandle
= 0;
2907 lpNetInfoStruct
->wNetType
=
2908 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2909 lpNetInfoStruct
->dwPrinters
= -1;
2910 lpNetInfoStruct
->dwDrives
= -1;
2914 ret
= WN_BAD_PROVIDER
;
2917 ret
= WN_NO_NETWORK
;
2921 TRACE("Returning %d\n", ret
);
2925 /*****************************************************************
2926 * WNetGetProviderNameA [MPR.@]
2928 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2929 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2933 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2937 ret
= WN_BAD_POINTER
;
2938 else if (!lpBufferSize
)
2939 ret
= WN_BAD_POINTER
;
2946 ret
= WN_NO_NETWORK
;
2947 for (i
= 0; i
< providerTable
->numProviders
&&
2948 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2951 if (i
< providerTable
->numProviders
)
2953 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2954 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2956 if (*lpBufferSize
< sizeNeeded
)
2958 *lpBufferSize
= sizeNeeded
;
2963 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2964 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2966 /* FIXME: is *lpBufferSize set to the number of characters
2972 ret
= WN_NO_NETWORK
;
2976 TRACE("Returning %d\n", ret
);
2980 /*****************************************************************
2981 * WNetGetProviderNameW [MPR.@]
2983 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2984 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2988 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2992 ret
= WN_BAD_POINTER
;
2993 else if (!lpBufferSize
)
2994 ret
= WN_BAD_POINTER
;
3001 ret
= WN_NO_NETWORK
;
3002 for (i
= 0; i
< providerTable
->numProviders
&&
3003 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
3006 if (i
< providerTable
->numProviders
)
3008 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
3010 if (*lpBufferSize
< sizeNeeded
)
3012 *lpBufferSize
= sizeNeeded
;
3017 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
3019 /* FIXME: is *lpBufferSize set to the number of characters
3025 ret
= WN_NO_NETWORK
;
3029 TRACE("Returning %d\n", ret
);