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
28 #define WINE_MOUNTMGR_EXTENSIONS
29 #include <ddk/mountmgr.h>
30 #include <wine/unicode.h>
32 /* Data structures representing network service providers. Assumes only one
33 * thread creates them, and that they are constant for the life of the process
34 * (and therefore doesn't synchronize access).
35 * FIXME: only basic provider data and enumeration-related data are implemented
36 * so far, need to implement the rest too.
38 typedef struct _WNetProvider
46 PF_NPOpenEnum openEnum
;
47 PF_NPEnumResource enumResource
;
48 PF_NPCloseEnum closeEnum
;
49 PF_NPGetResourceInformation getResourceInformation
;
50 PF_NPAddConnection addConnection
;
51 PF_NPAddConnection3 addConnection3
;
52 PF_NPCancelConnection cancelConnection
;
54 PF_NPGetConnection getConnection
;
56 } WNetProvider
, *PWNetProvider
;
58 typedef struct _WNetProviderTable
63 WNetProvider table
[1];
64 } WNetProviderTable
, *PWNetProviderTable
;
66 #define WNET_ENUMERATOR_TYPE_NULL 0
67 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
68 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
69 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
70 #define WNET_ENUMERATOR_TYPE_CONNECTED 4
72 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
73 * the enumeration; it represents one of the following types:
74 * - a 'null' enumeration, one that contains no members
75 * - a global enumeration, one that's executed across all providers
76 * - a provider-specific enumeration, one that's only executed by a single
78 * - a context enumeration. I know this contradicts what I just said about
79 * there being no correspondence between the scope and the type, but it's
80 * necessary for the special case that a "Entire Network" entry needs to
81 * be enumerated in an enumeration of the context scope. Thus an enumeration
82 * of the context scope results in a context type enumerator, which morphs
83 * into a global enumeration (so the enumeration continues across all
86 typedef struct _WNetEnumerator
100 } WNetEnumerator
, *PWNetEnumerator
;
102 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
104 /* Returns an index (into the global WNetProviderTable) of the provider with
105 * the given name, or BAD_PROVIDER_INDEX if not found.
107 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
109 static PWNetProviderTable providerTable
;
112 * Global provider table functions
115 static void _tryLoadProvider(PCWSTR provider
)
117 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
118 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
119 'S','e','r','v','i','c','e','s','\\',0 };
120 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
121 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
122 WCHAR serviceName
[MAX_PATH
];
125 TRACE("%s\n", debugstr_w(provider
));
126 snprintfW(serviceName
, sizeof(serviceName
) / sizeof(WCHAR
), serviceFmt
,
127 servicePrefix
, provider
);
128 serviceName
[sizeof(serviceName
) / sizeof(WCHAR
) - 1] = '\0';
129 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
132 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
134 WCHAR providerPath
[MAX_PATH
];
135 DWORD type
, size
= sizeof(providerPath
);
137 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
138 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
140 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
143 if (type
== REG_EXPAND_SZ
)
145 WCHAR path
[MAX_PATH
];
146 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
150 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
153 name
= HeapAlloc(GetProcessHeap(), 0, size
);
154 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
155 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
157 HeapFree(GetProcessHeap(), 0, name
);
163 HMODULE hLib
= LoadLibraryW(providerPath
);
167 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
169 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
171 TRACE("loaded lib %p\n", hLib
);
175 PWNetProvider provider
=
176 &providerTable
->table
[providerTable
->numProviders
];
178 provider
->hLib
= hLib
;
179 provider
->name
= name
;
180 TRACE("name is %s\n", debugstr_w(name
));
181 provider
->getCaps
= getCaps
;
182 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
183 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
184 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
185 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
186 if (provider
->dwEnumScopes
)
188 TRACE("supports enumeration\n");
189 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
190 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
191 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
192 TRACE("NPEnumResource %p\n", provider
->enumResource
);
193 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
194 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
195 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
196 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
197 if (!provider
->openEnum
||
198 !provider
->enumResource
||
199 !provider
->closeEnum
)
201 provider
->openEnum
= NULL
;
202 provider
->enumResource
= NULL
;
203 provider
->closeEnum
= NULL
;
204 provider
->dwEnumScopes
= 0;
205 WARN("Couldn't load enumeration functions\n");
208 connectCap
= getCaps(WNNC_CONNECTION
);
209 if (connectCap
& WNNC_CON_ADDCONNECTION
)
210 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
211 if (connectCap
& WNNC_CON_ADDCONNECTION3
)
212 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
213 if (connectCap
& WNNC_CON_CANCELCONNECTION
)
214 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
216 if (connectCap
& WNNC_CON_GETCONNECTIONS
)
217 provider
->getConnection
= MPR_GETPROC(NPGetConnection
);
219 TRACE("NPAddConnection %p\n", provider
->addConnection
);
220 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
221 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
222 providerTable
->numProviders
++;
226 WARN("Provider %s didn't export NPGetCaps\n",
227 debugstr_w(provider
));
228 HeapFree(GetProcessHeap(), 0, name
);
236 WARN("Couldn't load library %s for provider %s\n",
237 debugstr_w(providerPath
), debugstr_w(provider
));
238 HeapFree(GetProcessHeap(), 0, name
);
243 WARN("Couldn't get provider name for provider %s\n",
244 debugstr_w(provider
));
248 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
252 WARN("Couldn't open service key for provider %s\n",
253 debugstr_w(provider
));
257 static void _restoreSavedConnection(HKEY connection
, WCHAR
* local
)
260 DWORD type
, prov
, index
, size
;
262 net
.lpProvider
= NULL
;
263 net
.lpRemoteName
= NULL
;
264 net
.lpLocalName
= NULL
;
266 TRACE("Restoring: %S\n", local
);
268 size
= sizeof(DWORD
);
269 if (RegQueryValueExW(connection
, L
"ConnectionType", NULL
, &type
, (BYTE
*)&net
.dwType
, &size
) != ERROR_SUCCESS
)
272 if (type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
275 if (RegQueryValueExW(connection
, L
"ProviderName", NULL
, &type
, NULL
, &size
) != ERROR_SUCCESS
)
281 net
.lpProvider
= HeapAlloc(GetProcessHeap(), 0, size
);
285 if (RegQueryValueExW(connection
, L
"ProviderName", NULL
, NULL
, (BYTE
*)net
.lpProvider
, &size
) != ERROR_SUCCESS
)
288 size
= sizeof(DWORD
);
289 if (RegQueryValueExW(connection
, L
"ProviderType", NULL
, &type
, (BYTE
*)&prov
, &size
) != ERROR_SUCCESS
)
292 if (type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
295 index
= _findProviderIndexW(net
.lpProvider
);
296 if (index
== BAD_PROVIDER_INDEX
)
299 if (providerTable
->table
[index
].dwNetType
!= prov
)
302 if (RegQueryValueExW(connection
, L
"RemotePath", NULL
, &type
, NULL
, &size
) != ERROR_SUCCESS
)
308 net
.lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, size
);
309 if (!net
.lpRemoteName
)
312 if (RegQueryValueExW(connection
, L
"RemotePath", NULL
, NULL
, (BYTE
*)net
.lpRemoteName
, &size
) != ERROR_SUCCESS
)
315 size
= strlenW(local
);
316 net
.lpLocalName
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
) + 2 * sizeof(WCHAR
));
317 if (!net
.lpLocalName
)
320 strcpyW(net
.lpLocalName
, local
);
321 net
.lpLocalName
[size
] = ':';
322 net
.lpLocalName
[size
+ 1] = 0;
324 TRACE("Attempting connection\n");
326 WNetAddConnection2W(&net
, NULL
, NULL
, 0);
329 HeapFree(GetProcessHeap(), 0, net
.lpProvider
);
330 HeapFree(GetProcessHeap(), 0, net
.lpRemoteName
);
331 HeapFree(GetProcessHeap(), 0, net
.lpLocalName
);
335 void wnetInit(HINSTANCE hInstDll
)
337 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
338 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
339 'C','o','n','t','r','o','l','\\',
340 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
341 'O','r','d','e','r',0 };
342 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
343 'O','r','d','e','r',0 };
346 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
351 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
354 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
360 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
361 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
366 TRACE("provider order is %s\n", debugstr_w(providers
));
367 /* first count commas as a heuristic for how many to
368 * allocate space for */
369 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
371 ptr
= strchrW(ptr
, ',');
378 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
379 sizeof(WNetProviderTable
)
380 + (numToAllocate
- 1) * sizeof(WNetProvider
));
384 int entireNetworkLen
;
385 LPCWSTR stringresource
;
387 entireNetworkLen
= LoadStringW(hInstDll
,
388 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
389 providerTable
->entireNetwork
= HeapAlloc(
390 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
392 if (providerTable
->entireNetwork
)
394 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
395 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
397 providerTable
->numAllocated
= numToAllocate
;
398 for (ptr
= providers
; ptr
; )
401 ptr
= strchrW(ptr
, ',');
404 _tryLoadProvider(ptrPrev
);
408 HeapFree(GetProcessHeap(), 0, providers
);
419 if (RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
422 WCHAR subkey
[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
424 if (RegOpenKeyExW(user_profile
, subkey
, 0, KEY_READ
, &network
) == ERROR_SUCCESS
)
428 TRACE("Enumerating remembered connections\n");
430 if (RegQueryInfoKey(network
, NULL
, NULL
, NULL
, &max
, &size
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
434 TRACE("There are %lu connections\n", max
);
436 local
= HeapAlloc(GetProcessHeap(), 0, (size
+ 1) * sizeof(WCHAR
));
441 for (index
= 0; index
< max
; ++index
)
443 DWORD len
= size
+ 1;
446 TRACE("Trying connection %lu\n", index
);
448 if (RegEnumKeyExW(network
, index
, local
, &len
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
451 TRACE("It is %S\n", local
);
453 if (RegOpenKeyExW(network
, local
, 0, KEY_READ
, &connection
) != ERROR_SUCCESS
)
456 _restoreSavedConnection(connection
, local
);
457 RegCloseKey(connection
);
460 HeapFree(GetProcessHeap(), 0, local
);
464 RegCloseKey(network
);
467 RegCloseKey(user_profile
);
479 for (i
= 0; i
< providerTable
->numProviders
; i
++)
481 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
482 FreeModule(providerTable
->table
[i
].hLib
);
484 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
485 HeapFree(GetProcessHeap(), 0, providerTable
);
486 providerTable
= NULL
;
490 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
492 DWORD ret
= BAD_PROVIDER_INDEX
;
494 if (providerTable
&& providerTable
->numProviders
)
498 for (i
= 0; i
< providerTable
->numProviders
&&
499 ret
== BAD_PROVIDER_INDEX
; i
++)
500 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
510 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
516 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
522 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
523 if (lpNet
->lpRemoteName
)
525 len
= strlenW(lpNet
->lpRemoteName
) + 1;
526 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
527 if (ret
->lpRemoteName
)
528 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
537 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
541 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
542 HeapFree(GetProcessHeap(), 0, lpNet
);
546 static PWNetEnumerator
_createNullEnumerator(void)
548 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
549 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
552 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
556 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
557 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
559 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
560 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
564 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
565 ret
->dwScope
= dwScope
;
566 ret
->dwType
= dwType
;
567 ret
->dwUsage
= dwUsage
;
568 ret
->specific
.net
= _copyNetResourceForEnumW(lpNet
);
573 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
574 DWORD dwUsage
, DWORD index
, HANDLE handle
)
578 if (!providerTable
|| index
>= providerTable
->numProviders
)
582 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
585 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
586 ret
->providerIndex
= index
;
587 ret
->dwScope
= dwScope
;
588 ret
->dwType
= dwType
;
589 ret
->dwUsage
= dwUsage
;
590 ret
->handle
= handle
;
596 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
599 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
600 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
604 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
605 ret
->dwScope
= dwScope
;
606 ret
->dwType
= dwType
;
607 ret
->dwUsage
= dwUsage
;
612 static PWNetEnumerator
_createConnectedEnumerator(DWORD dwScope
, DWORD dwType
,
615 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
618 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONNECTED
;
619 ret
->dwScope
= dwScope
;
620 ret
->dwType
= dwType
;
621 ret
->dwUsage
= dwUsage
;
622 ret
->specific
.handles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HANDLE
) * providerTable
->numProviders
);
623 if (!ret
->specific
.handles
)
625 HeapFree(GetProcessHeap(), 0, ret
);
632 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
633 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
634 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
635 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
636 * if not all members of the array could be thunked, and something else on
639 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
640 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
642 DWORD i
, numToThunk
, totalBytes
, ret
;
646 return WN_BAD_POINTER
;
648 return WN_BAD_POINTER
;
652 return WN_BAD_POINTER
;
654 return WN_BAD_POINTER
;
656 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
658 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
660 totalBytes
+= sizeof(NETRESOURCEA
);
661 if (lpNet
->lpLocalName
)
662 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
663 -1, NULL
, 0, NULL
, NULL
);
664 if (lpNet
->lpRemoteName
)
665 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
666 -1, NULL
, 0, NULL
, NULL
);
667 if (lpNet
->lpComment
)
668 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
669 -1, NULL
, 0, NULL
, NULL
);
670 if (lpNet
->lpProvider
)
671 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
672 -1, NULL
, 0, NULL
, NULL
);
673 if (totalBytes
< *lpBufferSize
)
676 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
677 for (i
= 0; i
< numToThunk
; i
++)
679 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
680 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
682 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
683 /* lie about string lengths, we already verified how many
684 * we have space for above
686 if (lpNetIn
->lpLocalName
)
688 lpNetOut
->lpLocalName
= strNext
;
689 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
690 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
692 if (lpNetIn
->lpRemoteName
)
694 lpNetOut
->lpRemoteName
= strNext
;
695 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
696 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
698 if (lpNetIn
->lpComment
)
700 lpNetOut
->lpComment
= strNext
;
701 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
702 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
704 if (lpNetIn
->lpProvider
)
706 lpNetOut
->lpProvider
= strNext
;
707 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
708 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
711 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
712 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
717 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
718 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
719 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
720 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
721 * if not all members of the array could be thunked, and something else on
724 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
725 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
727 DWORD i
, numToThunk
, totalBytes
, ret
;
731 return WN_BAD_POINTER
;
733 return WN_BAD_POINTER
;
737 return WN_BAD_POINTER
;
739 return WN_BAD_POINTER
;
741 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
743 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
745 totalBytes
+= sizeof(NETRESOURCEW
);
746 if (lpNet
->lpLocalName
)
747 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
748 -1, NULL
, 0) * sizeof(WCHAR
);
749 if (lpNet
->lpRemoteName
)
750 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
751 -1, NULL
, 0) * sizeof(WCHAR
);
752 if (lpNet
->lpComment
)
753 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
754 -1, NULL
, 0) * sizeof(WCHAR
);
755 if (lpNet
->lpProvider
)
756 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
757 -1, NULL
, 0) * sizeof(WCHAR
);
758 if (totalBytes
< *lpBufferSize
)
761 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
762 for (i
= 0; i
< numToThunk
; i
++)
764 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
765 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
767 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
768 /* lie about string lengths, we already verified how many
769 * we have space for above
771 if (lpNetIn
->lpLocalName
)
773 lpNetOut
->lpLocalName
= strNext
;
774 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
775 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
777 if (lpNetIn
->lpRemoteName
)
779 lpNetOut
->lpRemoteName
= strNext
;
780 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
781 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
783 if (lpNetIn
->lpComment
)
785 lpNetOut
->lpComment
= strNext
;
786 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
787 -1, lpNetOut
->lpComment
, *lpBufferSize
);
789 if (lpNetIn
->lpProvider
)
791 lpNetOut
->lpProvider
= strNext
;
792 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
793 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
796 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
797 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
802 /*********************************************************************
803 * WNetOpenEnumA [MPR.@]
805 * See comments for WNetOpenEnumW.
807 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
808 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
812 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
813 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
816 ret
= WN_BAD_POINTER
;
817 else if (!providerTable
|| providerTable
->numProviders
== 0)
826 LPNETRESOURCEW lpNetWide
= NULL
;
828 DWORD size
= sizeof(buf
), count
= 1;
829 BOOL allocated
= FALSE
;
831 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
832 if (ret
== WN_MORE_DATA
)
834 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
838 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
843 ret
= WN_OUT_OF_MEMORY
;
845 else if (ret
== WN_SUCCESS
)
846 lpNetWide
= (LPNETRESOURCEW
)buf
;
847 if (ret
== WN_SUCCESS
)
848 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
851 HeapFree(GetProcessHeap(), 0, lpNetWide
);
854 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
858 TRACE("Returning %d\n", ret
);
862 /*********************************************************************
863 * WNetOpenEnumW [MPR.@]
865 * Network enumeration has way too many parameters, so I'm not positive I got
866 * them right. What I've got so far:
868 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
869 * all the network providers should be enumerated.
871 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
872 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
873 * lpProvider is set, all the network providers should be enumerated.
874 * (This means the enumeration is a list of network providers, not that the
875 * enumeration is passed on to the providers.)
877 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
878 * resource matches the "Entire Network" resource (no remote name, no
879 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
880 * enumeration is done on every network provider.
882 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
883 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
884 * only to the given network provider.
886 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
887 * no lpProvider is set, enumeration will be tried on every network provider,
888 * in the order in which they're loaded.
890 * - The LPNETRESOURCE should be disregarded for scopes besides
891 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
892 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
894 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
895 * resource in the enumerated list, as well as any machines in your
896 * workgroup. The machines in your workgroup come from doing a
897 * RESOURCE_CONTEXT enumeration of every Network Provider.
899 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
900 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
904 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
905 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
908 ret
= WN_BAD_POINTER
;
909 else if (!providerTable
|| providerTable
->numProviders
== 0)
918 case RESOURCE_GLOBALNET
:
921 if (lpNet
->lpProvider
)
923 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
925 if (index
!= BAD_PROVIDER_INDEX
)
927 if (providerTable
->table
[index
].openEnum
&&
928 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
931 PWSTR RemoteName
= lpNet
->lpRemoteName
;
933 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
934 RemoteName
&& !strcmpW(RemoteName
, lpNet
->lpProvider
))
935 lpNet
->lpRemoteName
= NULL
;
937 ret
= providerTable
->table
[index
].openEnum(
938 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
939 if (ret
== WN_SUCCESS
)
941 *lphEnum
= _createProviderEnumerator(
942 dwScope
, dwType
, dwUsage
, index
, handle
);
943 ret
= *lphEnum
? WN_SUCCESS
:
947 lpNet
->lpRemoteName
= RemoteName
;
950 ret
= WN_NOT_SUPPORTED
;
953 ret
= WN_BAD_PROVIDER
;
955 else if (lpNet
->lpRemoteName
)
957 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
958 dwType
, dwUsage
, lpNet
);
959 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
963 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
964 providerTable
->entireNetwork
))
966 /* comment matches the "Entire Network", enumerate
967 * global scope of every provider
969 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
970 dwType
, dwUsage
, lpNet
);
974 /* this is the same as not having passed lpNet */
975 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
976 dwType
, dwUsage
, NULL
);
978 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
983 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
985 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
988 case RESOURCE_CONTEXT
:
989 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
990 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
992 case RESOURCE_CONNECTED
:
993 *lphEnum
= _createConnectedEnumerator(dwScope
, dwType
, dwUsage
);
994 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
996 case RESOURCE_REMEMBERED
:
997 *lphEnum
= _createNullEnumerator();
998 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
1001 WARN("unknown scope 0x%08x\n", dwScope
);
1007 TRACE("Returning %d\n", ret
);
1011 /*********************************************************************
1012 * WNetEnumResourceA [MPR.@]
1014 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
1015 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1019 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1022 ret
= WN_BAD_POINTER
;
1024 ret
= WN_BAD_POINTER
;
1026 ret
= WN_BAD_POINTER
;
1027 else if (!lpBufferSize
)
1028 ret
= WN_BAD_POINTER
;
1029 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
1031 *lpBufferSize
= sizeof(NETRESOURCEA
);
1036 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
1037 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
1041 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
1043 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
1045 /* FIXME: this isn't necessarily going to work in the case of
1046 * WN_MORE_DATA, because our enumerator may have moved on to
1047 * the next provider. MSDN states that a large (16KB) buffer
1048 * size is the appropriate usage of this function, so
1049 * hopefully it won't be an issue.
1051 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
1052 lpBuffer
, lpBufferSize
);
1053 *lpcCount
= localCount
;
1055 HeapFree(GetProcessHeap(), 0, localBuffer
);
1058 ret
= WN_OUT_OF_MEMORY
;
1062 TRACE("Returning %d\n", ret
);
1066 static DWORD
_countProviderBytesW(PWNetProvider provider
)
1072 ret
= sizeof(NETRESOURCEW
);
1073 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
1080 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1081 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
1086 return WN_BAD_POINTER
;
1087 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1088 return WN_BAD_VALUE
;
1090 return WN_BAD_POINTER
;
1092 return WN_BAD_POINTER
;
1094 return WN_BAD_POINTER
;
1095 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
1096 return WN_MORE_DATA
;
1098 if (!providerTable
|| enumerator
->providerIndex
>=
1099 providerTable
->numProviders
)
1100 ret
= WN_NO_MORE_ENTRIES
;
1103 DWORD bytes
= 0, count
= 0, countLimit
, i
;
1104 LPNETRESOURCEW resource
;
1107 countLimit
= *lpcCount
== -1 ?
1108 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
1109 while (count
< countLimit
&& bytes
< *lpBufferSize
)
1111 DWORD bytesNext
= _countProviderBytesW(
1112 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
1114 if (bytes
+ bytesNext
< *lpBufferSize
)
1120 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
1121 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
1123 resource
->dwScope
= RESOURCE_GLOBALNET
;
1124 resource
->dwType
= RESOURCETYPE_ANY
;
1125 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
1126 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
1127 RESOURCEUSAGE_RESERVED
;
1128 resource
->lpLocalName
= NULL
;
1129 resource
->lpRemoteName
= strNext
;
1130 strcpyW(resource
->lpRemoteName
,
1131 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1132 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
1133 resource
->lpComment
= NULL
;
1134 resource
->lpProvider
= strNext
;
1135 strcpyW(resource
->lpProvider
,
1136 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1137 strNext
+= strlenW(resource
->lpProvider
) + 1;
1139 enumerator
->providerIndex
+= count
;
1141 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
1143 TRACE("Returning %d\n", ret
);
1147 /* Advances the enumerator (assumed to be a global enumerator) to the next
1148 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1149 * not open a handle with the next provider.
1150 * If the existing handle is NULL, may leave the enumerator unchanged, since
1151 * the current provider may support the desired scope.
1152 * If the existing handle is not NULL, closes it before moving on.
1153 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1154 * provider, and another error on failure.
1156 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
1159 return WN_BAD_POINTER
;
1160 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1161 return WN_BAD_VALUE
;
1162 if (!providerTable
|| enumerator
->providerIndex
>=
1163 providerTable
->numProviders
)
1164 return WN_NO_MORE_ENTRIES
;
1166 if (enumerator
->providerDone
)
1169 enumerator
->providerDone
= FALSE
;
1170 if (enumerator
->handle
)
1172 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1173 enumerator
->handle
);
1174 enumerator
->handle
= NULL
;
1175 enumerator
->providerIndex
++;
1177 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1178 dwEnum
= WNNC_ENUM_LOCAL
;
1179 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1180 dwEnum
= WNNC_ENUM_GLOBAL
;
1181 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1182 dwEnum
= WNNC_ENUM_CONTEXT
;
1183 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1184 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1185 & dwEnum
); enumerator
->providerIndex
++)
1188 return enumerator
->providerIndex
< providerTable
->numProviders
?
1189 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1192 /* "Passes through" call to the next provider that supports the enumeration
1194 * FIXME: if one call to a provider's enumerator succeeds while there's still
1195 * space in lpBuffer, I don't call to the next provider. The caller may not
1196 * expect that it should call EnumResourceW again with a return value of
1197 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1198 * may have to be moved around a bit, ick.
1200 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1201 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1206 return WN_BAD_POINTER
;
1207 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1208 return WN_BAD_VALUE
;
1210 return WN_BAD_POINTER
;
1212 return WN_BAD_POINTER
;
1214 return WN_BAD_POINTER
;
1215 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1216 return WN_MORE_DATA
;
1218 ret
= _globalEnumeratorAdvance(enumerator
);
1219 if (ret
== WN_SUCCESS
)
1221 ret
= providerTable
->table
[enumerator
->providerIndex
].
1222 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1223 enumerator
->dwUsage
, enumerator
->specific
.net
,
1224 &enumerator
->handle
);
1225 if (ret
== WN_SUCCESS
)
1227 ret
= providerTable
->table
[enumerator
->providerIndex
].
1228 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1230 if (ret
!= WN_MORE_DATA
)
1231 enumerator
->providerDone
= TRUE
;
1234 TRACE("Returning %d\n", ret
);
1238 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1239 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1244 return WN_BAD_POINTER
;
1245 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1246 return WN_BAD_VALUE
;
1248 return WN_BAD_POINTER
;
1250 return WN_BAD_POINTER
;
1252 return WN_BAD_POINTER
;
1253 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1254 return WN_MORE_DATA
;
1256 return WN_NO_NETWORK
;
1258 switch (enumerator
->dwScope
)
1260 case RESOURCE_GLOBALNET
:
1261 if (enumerator
->specific
.net
)
1262 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1263 lpBuffer
, lpBufferSize
);
1265 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1268 case RESOURCE_CONTEXT
:
1269 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1273 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1274 ret
= WN_NO_MORE_ENTRIES
;
1276 TRACE("Returning %d\n", ret
);
1280 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1281 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1284 return WN_BAD_POINTER
;
1285 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1286 return WN_BAD_VALUE
;
1287 if (!enumerator
->handle
)
1288 return WN_BAD_VALUE
;
1290 return WN_BAD_POINTER
;
1292 return WN_BAD_POINTER
;
1294 return WN_BAD_POINTER
;
1296 return WN_NO_NETWORK
;
1297 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1298 return WN_NO_MORE_ENTRIES
;
1299 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1300 return WN_BAD_VALUE
;
1301 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1302 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1305 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1306 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1309 size_t cchEntireNetworkLen
, bytesNeeded
;
1312 return WN_BAD_POINTER
;
1313 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1314 return WN_BAD_VALUE
;
1316 return WN_BAD_POINTER
;
1318 return WN_BAD_POINTER
;
1320 return WN_BAD_POINTER
;
1322 return WN_NO_NETWORK
;
1324 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1325 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1326 if (*lpBufferSize
< bytesNeeded
)
1328 *lpBufferSize
= bytesNeeded
;
1333 LPNETRESOURCEW lpNet
= lpBuffer
;
1335 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1336 lpNet
->dwType
= enumerator
->dwType
;
1337 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1338 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1339 lpNet
->lpLocalName
= NULL
;
1340 lpNet
->lpRemoteName
= NULL
;
1341 lpNet
->lpProvider
= NULL
;
1342 /* odd, but correct: put comment at end of buffer, so it won't get
1343 * overwritten by subsequent calls to a provider's enumResource
1345 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1346 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1347 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1350 if (ret
== WN_SUCCESS
)
1352 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1354 /* "Entire Network" entry enumerated--morph this into a global
1355 * enumerator. enumerator->lpNet continues to be NULL, since it has
1356 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1358 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1359 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1360 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1361 if (ret
== WN_SUCCESS
)
1363 /* reflect the fact that we already enumerated "Entire Network" */
1365 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1369 /* the provider enumeration failed, but we already succeeded in
1370 * enumerating "Entire Network"--leave type as global to allow a
1371 * retry, but indicate success with a count of one.
1375 *lpBufferSize
= bytesNeeded
;
1378 TRACE("Returning %d\n", ret
);
1382 static DWORD
_copyStringToEnumW(const WCHAR
*source
, DWORD
* left
, void** end
)
1385 WCHAR
* local
= *end
;
1387 len
= strlenW(source
) + 1;
1388 len
*= sizeof(WCHAR
);
1390 return WN_MORE_DATA
;
1392 local
-= (len
/ sizeof(WCHAR
));
1393 memcpy(local
, source
, len
);
1400 static DWORD
_enumerateConnectedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1401 void* user_buffer
, DWORD
* user_size
)
1403 DWORD ret
, index
, count
, total_count
, size
, i
, left
;
1405 NETRESOURCEW
* curr
, * buffer
;
1409 return WN_BAD_POINTER
;
1410 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONNECTED
)
1411 return WN_BAD_VALUE
;
1412 if (!user_count
|| !user_buffer
|| !user_size
)
1413 return WN_BAD_POINTER
;
1415 return WN_NO_NETWORK
;
1417 handles
= enumerator
->specific
.handles
;
1420 buffer
= HeapAlloc(GetProcessHeap(), 0, *user_size
);
1422 return WN_NO_NETWORK
;
1425 end
= (char *)user_buffer
+ size
;
1426 count
= *user_count
;
1429 ret
= WN_NO_MORE_ENTRIES
;
1430 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1432 if (providerTable
->table
[index
].dwEnumScopes
)
1434 if (handles
[index
] == 0)
1436 ret
= providerTable
->table
[index
].openEnum(enumerator
->dwScope
,
1438 enumerator
->dwUsage
,
1439 NULL
, &handles
[index
]);
1440 if (ret
!= WN_SUCCESS
)
1444 ret
= providerTable
->table
[index
].enumResource(handles
[index
],
1447 total_count
+= count
;
1448 if (ret
== WN_MORE_DATA
)
1451 if (ret
== WN_SUCCESS
)
1453 for (i
= 0; i
< count
; ++i
)
1455 if (left
< sizeof(NETRESOURCEW
))
1461 memcpy(curr
, &buffer
[i
], sizeof(NETRESOURCEW
));
1462 left
-= sizeof(NETRESOURCEW
);
1464 ret
= _copyStringToEnumW(buffer
[i
].lpLocalName
, &left
, &end
);
1465 if (ret
== WN_MORE_DATA
)
1467 curr
->lpLocalName
= end
;
1469 ret
= _copyStringToEnumW(buffer
[i
].lpRemoteName
, &left
, &end
);
1470 if (ret
== WN_MORE_DATA
)
1472 curr
->lpRemoteName
= end
;
1474 ret
= _copyStringToEnumW(buffer
[i
].lpProvider
, &left
, &end
);
1475 if (ret
== WN_MORE_DATA
)
1477 curr
->lpProvider
= end
;
1485 if (*user_count
!= -1)
1486 count
= *user_count
- total_count
;
1488 count
= *user_count
;
1492 if (total_count
== 0)
1493 ret
= WN_NO_MORE_ENTRIES
;
1495 *user_count
= total_count
;
1496 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1499 HeapFree(GetProcessHeap(), 0, buffer
);
1501 TRACE("Returning %d\n", ret
);
1505 /*********************************************************************
1506 * WNetEnumResourceW [MPR.@]
1508 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1509 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1513 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1516 ret
= WN_BAD_POINTER
;
1518 ret
= WN_BAD_POINTER
;
1520 ret
= WN_BAD_POINTER
;
1521 else if (!lpBufferSize
)
1522 ret
= WN_BAD_POINTER
;
1523 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1525 *lpBufferSize
= sizeof(NETRESOURCEW
);
1530 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1532 switch (enumerator
->enumType
)
1534 case WNET_ENUMERATOR_TYPE_NULL
:
1535 ret
= WN_NO_MORE_ENTRIES
;
1537 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1538 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1541 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1542 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1545 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1546 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1549 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1550 ret
= _enumerateConnectedW(enumerator
, lpcCount
, lpBuffer
,
1554 WARN("bogus enumerator type!\n");
1555 ret
= WN_NO_NETWORK
;
1560 TRACE("Returning %d\n", ret
);
1564 /*********************************************************************
1565 * WNetCloseEnum [MPR.@]
1567 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1572 TRACE( "(%p)\n", hEnum
);
1576 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1578 switch (enumerator
->enumType
)
1580 case WNET_ENUMERATOR_TYPE_NULL
:
1583 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1584 if (enumerator
->specific
.net
)
1585 _freeEnumNetResource(enumerator
->specific
.net
);
1586 if (enumerator
->handle
)
1587 providerTable
->table
[enumerator
->providerIndex
].
1588 closeEnum(enumerator
->handle
);
1591 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1592 if (enumerator
->handle
)
1593 providerTable
->table
[enumerator
->providerIndex
].
1594 closeEnum(enumerator
->handle
);
1597 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1598 handles
= enumerator
->specific
.handles
;
1599 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1601 if (providerTable
->table
[index
].dwEnumScopes
&& handles
[index
])
1602 providerTable
->table
[index
].closeEnum(handles
[index
]);
1604 HeapFree(GetProcessHeap(), 0, handles
);
1608 WARN("bogus enumerator type!\n");
1609 ret
= WN_BAD_HANDLE
;
1611 HeapFree(GetProcessHeap(), 0, hEnum
);
1614 ret
= WN_BAD_HANDLE
;
1617 TRACE("Returning %d\n", ret
);
1621 /*********************************************************************
1622 * WNetGetResourceInformationA [MPR.@]
1624 * See WNetGetResourceInformationW
1626 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1627 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1632 TRACE( "(%p, %p, %p, %p)\n",
1633 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1635 if (!providerTable
|| providerTable
->numProviders
== 0)
1636 ret
= WN_NO_NETWORK
;
1637 else if (lpNetResource
)
1639 LPNETRESOURCEW lpNetResourceW
= NULL
;
1640 DWORD size
= 1024, count
= 1;
1643 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1644 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1645 if (ret
== WN_MORE_DATA
)
1647 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1648 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1650 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1651 &count
, lpNetResourceW
, &size
);
1653 ret
= WN_OUT_OF_MEMORY
;
1655 if (ret
== WN_SUCCESS
)
1657 LPWSTR lpSystemW
= NULL
;
1660 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1663 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1664 lpBufferW
, &size
, &lpSystemW
);
1665 if (ret
== WN_MORE_DATA
)
1667 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1668 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1670 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1671 lpBufferW
, &size
, &lpSystemW
);
1673 ret
= WN_OUT_OF_MEMORY
;
1675 if (ret
== WN_SUCCESS
)
1677 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1678 &count
, lpBuffer
, cbBuffer
);
1679 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1680 lpNetResourceW
= lpBufferW
;
1681 size
= sizeof(NETRESOURCEA
);
1682 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1683 -1, NULL
, 0, NULL
, NULL
);
1684 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1685 -1, NULL
, 0, NULL
, NULL
);
1687 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1688 -1, NULL
, 0, NULL
, NULL
);
1689 if ((len
) && ( size
+ len
< *cbBuffer
))
1691 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1692 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1693 *lplpSystem
, len
, NULL
, NULL
);
1700 ret
= WN_OUT_OF_MEMORY
;
1701 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1704 ret
= WN_OUT_OF_MEMORY
;
1705 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1707 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1710 ret
= WN_NO_NETWORK
;
1714 TRACE("Returning %d\n", ret
);
1718 /*********************************************************************
1719 * WNetGetResourceInformationW [MPR.@]
1721 * WNetGetResourceInformationW function identifies the network provider
1722 * that owns the resource and gets information about the type of the resource.
1725 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1726 * defines a network resource.
1727 * lpBuffer [ O] the pointer to buffer, containing result. It
1728 * contains NETRESOURCEW structure and strings to
1729 * which the members of the NETRESOURCEW structure
1731 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1733 * lplpSystem [ O] the pointer to string in the output buffer,
1734 * containing the part of the resource name without
1735 * names of the server and share.
1738 * NO_ERROR if the function succeeds. System error code if the function fails.
1741 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1742 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1743 LPWSTR
*lplpSystem
)
1745 DWORD ret
= WN_NO_NETWORK
;
1748 TRACE( "(%p, %p, %p, %p)\n",
1749 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1752 ret
= WN_OUT_OF_MEMORY
;
1753 else if (providerTable
!= NULL
)
1755 /* FIXME: For function value of a variable is indifferent, it does
1756 * search of all providers in a network.
1758 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1760 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1761 WNNC_DLG_GETRESOURCEINFORMATION
)
1763 if (providerTable
->table
[index
].getResourceInformation
)
1764 ret
= providerTable
->table
[index
].getResourceInformation(
1765 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1767 ret
= WN_NO_NETWORK
;
1768 if (ret
== WN_SUCCESS
)
1778 /*********************************************************************
1779 * WNetGetResourceParentA [MPR.@]
1781 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1782 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1784 FIXME( "(%p, %p, %p): stub\n",
1785 lpNetResource
, lpBuffer
, lpBufferSize
);
1787 SetLastError(WN_NO_NETWORK
);
1788 return WN_NO_NETWORK
;
1791 /*********************************************************************
1792 * WNetGetResourceParentW [MPR.@]
1794 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1795 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1797 FIXME( "(%p, %p, %p): stub\n",
1798 lpNetResource
, lpBuffer
, lpBufferSize
);
1800 SetLastError(WN_NO_NETWORK
);
1801 return WN_NO_NETWORK
;
1807 * Connection Functions
1810 /*********************************************************************
1811 * WNetAddConnectionA [MPR.@]
1813 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1814 LPCSTR lpLocalName
)
1816 NETRESOURCEA resourcesA
;
1818 memset(&resourcesA
, 0, sizeof(resourcesA
));
1819 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
1820 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
1821 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1824 /*********************************************************************
1825 * WNetAddConnectionW [MPR.@]
1827 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1828 LPCWSTR lpLocalName
)
1830 NETRESOURCEW resourcesW
;
1832 memset(&resourcesW
, 0, sizeof(resourcesW
));
1833 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
1834 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
1835 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1838 /*********************************************************************
1839 * WNetAddConnection2A [MPR.@]
1841 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1842 LPCSTR lpPassword
, LPCSTR lpUserID
,
1845 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1849 /*********************************************************************
1850 * WNetAddConnection2W [MPR.@]
1852 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1853 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1856 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1860 /*********************************************************************
1861 * WNetAddConnection3A [MPR.@]
1863 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1864 LPCSTR lpPassword
, LPCSTR lpUserID
,
1867 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1868 dwFlags
, NULL
, 0, NULL
);
1871 /*********************************************************************
1872 * WNetAddConnection3W [MPR.@]
1874 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1875 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1878 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1879 dwFlags
, NULL
, 0, NULL
);
1882 struct use_connection_context
1885 NETRESOURCEW
*resource
;
1886 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
1893 DWORD (*pre_set_accessname
)(struct use_connection_context
*, WCHAR
*);
1894 void (*set_accessname
)(struct use_connection_context
*, WCHAR
*);
1897 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1899 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1904 len
= strlenW(local_name
);
1906 len
= strlenW(ctxt
->resource
->lpRemoteName
);
1908 if (++len
> *ctxt
->buffer_size
)
1910 *ctxt
->buffer_size
= len
;
1911 return ERROR_MORE_DATA
;
1915 ctxt
->accessname
= NULL
;
1917 return ERROR_SUCCESS
;
1920 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1922 WCHAR
*accessname
= ctxt
->accessname
;
1925 strcpyW(accessname
, local_name
);
1927 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1930 strcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
1933 static DWORD
wnet_use_provider( struct use_connection_context
*ctxt
, NETRESOURCEW
* netres
, WNetProvider
*provider
, BOOLEAN redirect
)
1937 caps
= provider
->getCaps(WNNC_CONNECTION
);
1938 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
1939 return ERROR_BAD_PROVIDER
;
1941 ret
= WN_ACCESS_DENIED
;
1944 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
1945 ret
= provider
->addConnection3(ctxt
->hwndOwner
, netres
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
1946 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
1947 ret
= provider
->addConnection(netres
, ctxt
->password
, ctxt
->userid
);
1949 if (ret
== WN_ALREADY_CONNECTED
&& redirect
)
1950 netres
->lpLocalName
[0] -= 1;
1951 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& netres
->lpLocalName
[0] >= 'C');
1953 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
1954 ctxt
->set_accessname(ctxt
, netres
->lpLocalName
);
1959 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
1961 WNetProvider
*provider
;
1962 DWORD index
, ret
= WN_NO_NETWORK
;
1963 BOOL redirect
= FALSE
;
1964 WCHAR letter
[3] = {'Z', ':', 0};
1965 NETRESOURCEW netres
;
1967 if (!providerTable
|| providerTable
->numProviders
== 0)
1968 return WN_NO_NETWORK
;
1970 if (!ctxt
->resource
)
1971 return ERROR_INVALID_PARAMETER
;
1972 netres
= *ctxt
->resource
;
1974 if (!netres
.lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
1976 if (netres
.dwType
!= RESOURCETYPE_DISK
&& netres
.dwType
!= RESOURCETYPE_PRINT
)
1977 return ERROR_BAD_DEV_TYPE
;
1979 if (netres
.dwType
== RESOURCETYPE_PRINT
)
1981 FIXME("Local device selection is not implemented for printers.\n");
1982 return WN_NO_NETWORK
;
1986 netres
.lpLocalName
= letter
;
1989 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
1990 return ERROR_BAD_NET_NAME
;
1992 if ((ret
= ctxt
->pre_set_accessname(ctxt
, netres
.lpLocalName
)))
1995 if (netres
.lpProvider
)
1997 index
= _findProviderIndexW(netres
.lpProvider
);
1998 if (index
== BAD_PROVIDER_INDEX
)
1999 return ERROR_BAD_PROVIDER
;
2001 provider
= &providerTable
->table
[index
];
2002 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2006 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2008 provider
= &providerTable
->table
[index
];
2009 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2010 if (ret
== WN_SUCCESS
|| ret
== WN_ALREADY_CONNECTED
)
2016 if (ret
== WN_SUCCESS
&& ctxt
->flags
& CONNECT_UPDATE_PROFILE
)
2020 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2022 FIXME("Persistent connection are not supported for printers\n");
2026 if (RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2029 WCHAR subkey
[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres
.lpLocalName
[0], 0};
2031 if (RegCreateKeyExW(user_profile
, subkey
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &network
, NULL
) == ERROR_SUCCESS
)
2033 DWORD dword_arg
= RESOURCETYPE_DISK
;
2034 DWORD len
= (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
2036 RegSetValueExW(network
, L
"ConnectionType", 0, REG_DWORD
, (const BYTE
*)&dword_arg
, sizeof(DWORD
));
2037 RegSetValueExW(network
, L
"ProviderName", 0, REG_SZ
, (const BYTE
*)provider
->name
, len
);
2038 dword_arg
= provider
->dwNetType
;
2039 RegSetValueExW(network
, L
"ProviderType", 0, REG_DWORD
, (const BYTE
*)&dword_arg
, sizeof(DWORD
));
2040 len
= (strlenW(netres
.lpRemoteName
) + 1) * sizeof(WCHAR
);
2041 RegSetValueExW(network
, L
"RemotePath", 0, REG_SZ
, (const BYTE
*)netres
.lpRemoteName
, len
);
2043 RegSetValueExW(network
, L
"UserName", 0, REG_SZ
, (const BYTE
*)netres
.lpRemoteName
, len
);
2044 RegCloseKey(network
);
2047 RegCloseKey(user_profile
);
2055 /*****************************************************************
2056 * WNetUseConnectionW [MPR.@]
2058 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
2059 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
2061 struct use_connection_context ctxt
;
2063 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
2064 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
2065 accessname
, buffer_size
, result
);
2067 ctxt
.hwndOwner
= hwndOwner
;
2068 ctxt
.resource
= resource
;
2069 ctxt
.resourceA
= NULL
;
2070 ctxt
.password
= (WCHAR
*)password
;
2071 ctxt
.userid
= (WCHAR
*)userid
;
2073 ctxt
.accessname
= accessname
;
2074 ctxt
.buffer_size
= buffer_size
;
2075 ctxt
.result
= result
;
2076 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
2077 ctxt
.set_accessname
= use_connection_set_accessnameW
;
2079 return wnet_use_connection(&ctxt
);
2082 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2084 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
2089 len
= WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, NULL
, 0, NULL
, NULL
) - 1;
2091 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
2093 if (++len
> *ctxt
->buffer_size
)
2095 *ctxt
->buffer_size
= len
;
2096 return ERROR_MORE_DATA
;
2100 ctxt
->accessname
= NULL
;
2102 return ERROR_SUCCESS
;
2105 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2107 char *accessname
= ctxt
->accessname
;
2110 WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, accessname
, *ctxt
->buffer_size
, NULL
, NULL
);
2112 *ctxt
->result
= CONNECT_LOCALDRIVE
;
2115 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
2118 static LPWSTR
strdupAtoW( LPCSTR str
)
2123 if (!str
) return NULL
;
2124 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
2125 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2126 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
2130 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
2132 resourceW
->dwScope
= resourceA
->dwScope
;
2133 resourceW
->dwType
= resourceA
->dwType
;
2134 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
2135 resourceW
->dwUsage
= resourceA
->dwUsage
;
2136 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
2137 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
2138 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
2139 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
2142 static void free_netresourceW( NETRESOURCEW
*resource
)
2144 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
2145 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
2146 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
2147 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
2150 /*****************************************************************
2151 * WNetUseConnectionA [MPR.@]
2153 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
2154 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
2155 DWORD
*buffer_size
, DWORD
*result
)
2157 struct use_connection_context ctxt
;
2158 NETRESOURCEW resourceW
;
2161 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
2162 accessname
, buffer_size
, result
);
2164 netresource_a_to_w(resource
, &resourceW
);
2166 ctxt
.hwndOwner
= hwndOwner
;
2167 ctxt
.resource
= &resourceW
;
2168 ctxt
.resourceA
= resource
;
2169 ctxt
.password
= strdupAtoW(password
);
2170 ctxt
.userid
= strdupAtoW(userid
);
2172 ctxt
.accessname
= accessname
;
2173 ctxt
.buffer_size
= buffer_size
;
2174 ctxt
.result
= result
;
2175 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
2176 ctxt
.set_accessname
= use_connection_set_accessnameA
;
2178 ret
= wnet_use_connection(&ctxt
);
2180 free_netresourceW(&resourceW
);
2181 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
2182 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
2187 /*********************************************************************
2188 * WNetCancelConnectionA [MPR.@]
2190 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
2192 return WNetCancelConnection2A(lpName
, 0, fForce
);
2195 /*********************************************************************
2196 * WNetCancelConnectionW [MPR.@]
2198 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
2200 return WNetCancelConnection2W(lpName
, 0, fForce
);
2203 /*********************************************************************
2204 * WNetCancelConnection2A [MPR.@]
2206 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2209 WCHAR
* name
= strdupAtoW(lpName
);
2211 return ERROR_NOT_CONNECTED
;
2213 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
2214 HeapFree(GetProcessHeap(), 0, name
);
2219 /*********************************************************************
2220 * WNetCancelConnection2W [MPR.@]
2222 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2224 DWORD ret
= WN_NO_NETWORK
;
2227 if (providerTable
!= NULL
)
2229 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2231 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2232 WNNC_CON_CANCELCONNECTION
)
2234 if (providerTable
->table
[index
].cancelConnection
)
2235 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
2237 ret
= WN_NO_NETWORK
;
2238 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
2245 if (dwFlags
& CONNECT_UPDATE_PROFILE
)
2248 WCHAR
*coma
= strchrW(lpName
, ':');
2250 if (coma
&& RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2255 len
= (ULONG_PTR
)coma
- (ULONG_PTR
)lpName
+ sizeof(L
"Network\\");
2256 subkey
= HeapAlloc(GetProcessHeap(), 0, len
);
2259 strcpyW(subkey
, L
"Network\\");
2260 memcpy(subkey
+ (sizeof(L
"Network\\") / sizeof(WCHAR
)) - 1, lpName
, (ULONG_PTR
)coma
- (ULONG_PTR
)lpName
);
2261 subkey
[len
/ sizeof(WCHAR
) - 1] = 0;
2263 TRACE("Removing: %S\n", subkey
);
2265 RegDeleteKeyW(user_profile
, subkey
);
2266 HeapFree(GetProcessHeap(), 0, subkey
);
2269 RegCloseKey(user_profile
);
2277 /*****************************************************************
2278 * WNetRestoreConnectionA [MPR.@]
2280 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
2282 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
2284 SetLastError(WN_NO_NETWORK
);
2285 return WN_NO_NETWORK
;
2288 /*****************************************************************
2289 * WNetRestoreConnectionW [MPR.@]
2291 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
2293 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
2295 SetLastError(WN_NO_NETWORK
);
2296 return WN_NO_NETWORK
;
2299 /**************************************************************************
2300 * WNetGetConnectionA [MPR.@]
2303 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2304 * - WN_NOT_CONNECTED drive is a local drive
2305 * - WN_MORE_DATA buffer isn't big enough
2306 * - WN_SUCCESS success (net path in buffer)
2308 * FIXME: need to test return values under different errors
2310 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
2311 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
2316 ret
= WN_BAD_POINTER
;
2317 else if (!lpBufferSize
)
2318 ret
= WN_BAD_POINTER
;
2319 else if (!lpRemoteName
&& *lpBufferSize
)
2320 ret
= WN_BAD_POINTER
;
2323 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
2327 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2331 WCHAR wideRemoteStatic
[MAX_PATH
];
2332 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
2334 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
2336 /* try once without memory allocation */
2337 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
2339 if (ret
== WN_SUCCESS
)
2341 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2342 -1, NULL
, 0, NULL
, NULL
);
2344 if (len
<= *lpBufferSize
)
2346 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
2347 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2352 *lpBufferSize
= len
;
2356 else if (ret
== WN_MORE_DATA
)
2358 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2359 wideRemoteSize
* sizeof(WCHAR
));
2363 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2365 if (ret
== WN_SUCCESS
)
2367 if (len
<= *lpBufferSize
)
2369 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2370 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2375 *lpBufferSize
= len
;
2379 HeapFree(GetProcessHeap(), 0, wideRemote
);
2382 ret
= WN_OUT_OF_MEMORY
;
2384 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2387 ret
= WN_OUT_OF_MEMORY
;
2390 ret
= WN_BAD_LOCALNAME
;
2394 TRACE("Returning %d\n", ret
);
2398 /* find the network connection for a given drive; helper for WNetGetConnection */
2399 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2403 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2405 DWORD ret
= WN_NOT_CONNECTED
;
2406 DWORD bytes_returned
;
2408 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2409 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2410 0, 0 )) == INVALID_HANDLE_VALUE
)
2412 ERR( "failed to open mount manager err %u\n", GetLastError() );
2415 memset( data
, 0, sizeof(*data
) );
2416 data
->letter
= letter
;
2417 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2418 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2420 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2423 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2426 mount_point
[0] = '\\';
2427 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2429 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2437 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2445 DWORD ret
= WN_NO_NETWORK
;
2447 WCHAR local
[3] = {letter
, ':', 0};
2449 if (providerTable
!= NULL
)
2451 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2453 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2454 WNNC_CON_GETCONNECTIONS
)
2456 if (providerTable
->table
[index
].getConnection
)
2457 ret
= providerTable
->table
[index
].getConnection(
2458 local
, remote
, size
);
2460 ret
= WN_NO_NETWORK
;
2461 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2472 /**************************************************************************
2473 * WNetGetConnectionW [MPR.@]
2475 * FIXME: need to test return values under different errors
2477 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2478 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2482 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2486 ret
= WN_BAD_POINTER
;
2487 else if (!lpBufferSize
)
2488 ret
= WN_BAD_POINTER
;
2489 else if (!lpRemoteName
&& *lpBufferSize
)
2490 ret
= WN_BAD_POINTER
;
2491 else if (!lpLocalName
[0])
2492 ret
= WN_BAD_LOCALNAME
;
2495 if (lpLocalName
[1] == ':')
2497 switch(GetDriveTypeW(lpLocalName
))
2500 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2502 case DRIVE_REMOVABLE
:
2505 TRACE("file is local\n");
2506 ret
= WN_NOT_CONNECTED
;
2509 ret
= WN_BAD_LOCALNAME
;
2513 ret
= WN_BAD_LOCALNAME
;
2517 TRACE("Returning %d\n", ret
);
2521 /**************************************************************************
2522 * WNetSetConnectionA [MPR.@]
2524 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2527 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2529 SetLastError(WN_NO_NETWORK
);
2530 return WN_NO_NETWORK
;
2533 /**************************************************************************
2534 * WNetSetConnectionW [MPR.@]
2536 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2539 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2541 SetLastError(WN_NO_NETWORK
);
2542 return WN_NO_NETWORK
;
2545 /*****************************************************************
2546 * WNetGetUniversalNameA [MPR.@]
2548 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2549 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2553 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2554 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2556 switch (dwInfoLevel
)
2558 case UNIVERSAL_NAME_INFO_LEVEL
:
2560 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2562 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2564 err
= ERROR_NOT_CONNECTED
;
2568 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2569 if (*lpBufferSize
< size
)
2574 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2575 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2579 case REMOTE_NAME_INFO_LEVEL
:
2580 err
= WN_NOT_CONNECTED
;
2592 /*****************************************************************
2593 * WNetGetUniversalNameW [MPR.@]
2595 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2596 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2600 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2601 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2603 switch (dwInfoLevel
)
2605 case UNIVERSAL_NAME_INFO_LEVEL
:
2607 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2609 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2611 err
= ERROR_NOT_CONNECTED
;
2615 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2616 if (*lpBufferSize
< size
)
2621 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2622 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2626 case REMOTE_NAME_INFO_LEVEL
:
2627 err
= WN_NO_NETWORK
;
2635 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2645 /**************************************************************************
2646 * WNetGetUserA [MPR.@]
2648 * FIXME: we should not return ourselves, but the owner of the drive lpName
2650 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2652 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2653 return GetLastError();
2656 /*****************************************************************
2657 * WNetGetUserW [MPR.@]
2659 * FIXME: we should not return ourselves, but the owner of the drive lpName
2661 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2663 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2664 return GetLastError();
2667 /*********************************************************************
2668 * WNetConnectionDialog [MPR.@]
2670 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2672 CONNECTDLGSTRUCTW conn_dlg
;
2673 NETRESOURCEW net_res
;
2675 ZeroMemory(&conn_dlg
, sizeof(conn_dlg
));
2676 ZeroMemory(&net_res
, sizeof(net_res
));
2678 conn_dlg
.cbStructure
= sizeof(conn_dlg
);
2679 conn_dlg
.lpConnRes
= &net_res
;
2680 conn_dlg
.hwndOwner
= hwnd
;
2681 net_res
.dwType
= dwType
;
2683 return WNetConnectionDialog1W(&conn_dlg
);
2686 /*********************************************************************
2687 * WNetConnectionDialog1A [MPR.@]
2689 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2691 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2693 SetLastError(WN_NO_NETWORK
);
2694 return WN_NO_NETWORK
;
2697 /*********************************************************************
2698 * WNetConnectionDialog1W [MPR.@]
2700 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2702 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2704 SetLastError(WN_NO_NETWORK
);
2705 return WN_NO_NETWORK
;
2708 /*********************************************************************
2709 * WNetDisconnectDialog [MPR.@]
2711 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2713 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2715 SetLastError(WN_NO_NETWORK
);
2716 return WN_NO_NETWORK
;
2719 /*********************************************************************
2720 * WNetDisconnectDialog1A [MPR.@]
2722 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2724 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2726 SetLastError(WN_NO_NETWORK
);
2727 return WN_NO_NETWORK
;
2730 /*********************************************************************
2731 * WNetDisconnectDialog1W [MPR.@]
2733 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2735 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2737 SetLastError(WN_NO_NETWORK
);
2738 return WN_NO_NETWORK
;
2741 /*********************************************************************
2742 * WNetGetLastErrorA [MPR.@]
2744 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2745 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2746 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2748 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2749 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2751 SetLastError(WN_NO_NETWORK
);
2752 return WN_NO_NETWORK
;
2755 /*********************************************************************
2756 * WNetGetLastErrorW [MPR.@]
2758 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2759 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2760 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2762 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2763 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2765 SetLastError(WN_NO_NETWORK
);
2766 return WN_NO_NETWORK
;
2769 /*********************************************************************
2770 * WNetGetNetworkInformationA [MPR.@]
2772 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2773 LPNETINFOSTRUCT lpNetInfoStruct
)
2777 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2780 ret
= WN_BAD_POINTER
;
2785 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2788 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2792 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2794 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2795 HeapFree(GetProcessHeap(), 0, wideProvider
);
2798 ret
= WN_OUT_OF_MEMORY
;
2801 ret
= GetLastError();
2805 TRACE("Returning %d\n", ret
);
2809 /*********************************************************************
2810 * WNetGetNetworkInformationW [MPR.@]
2812 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2813 LPNETINFOSTRUCT lpNetInfoStruct
)
2817 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2820 ret
= WN_BAD_POINTER
;
2821 else if (!lpNetInfoStruct
)
2822 ret
= WN_BAD_POINTER
;
2823 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2827 if (providerTable
&& providerTable
->numProviders
)
2829 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2831 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2833 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2834 lpNetInfoStruct
->dwProviderVersion
=
2835 providerTable
->table
[providerIndex
].dwSpecVersion
;
2836 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2837 lpNetInfoStruct
->dwCharacteristics
= 0;
2838 lpNetInfoStruct
->dwHandle
= 0;
2839 lpNetInfoStruct
->wNetType
=
2840 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2841 lpNetInfoStruct
->dwPrinters
= -1;
2842 lpNetInfoStruct
->dwDrives
= -1;
2846 ret
= WN_BAD_PROVIDER
;
2849 ret
= WN_NO_NETWORK
;
2853 TRACE("Returning %d\n", ret
);
2857 /*****************************************************************
2858 * WNetGetProviderNameA [MPR.@]
2860 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2861 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2865 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2869 ret
= WN_BAD_POINTER
;
2870 else if (!lpBufferSize
)
2871 ret
= WN_BAD_POINTER
;
2878 ret
= WN_NO_NETWORK
;
2879 for (i
= 0; i
< providerTable
->numProviders
&&
2880 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2883 if (i
< providerTable
->numProviders
)
2885 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2886 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2888 if (*lpBufferSize
< sizeNeeded
)
2890 *lpBufferSize
= sizeNeeded
;
2895 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2896 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2898 /* FIXME: is *lpBufferSize set to the number of characters
2904 ret
= WN_NO_NETWORK
;
2908 TRACE("Returning %d\n", ret
);
2912 /*****************************************************************
2913 * WNetGetProviderNameW [MPR.@]
2915 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2916 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2920 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2924 ret
= WN_BAD_POINTER
;
2925 else if (!lpBufferSize
)
2926 ret
= WN_BAD_POINTER
;
2933 ret
= WN_NO_NETWORK
;
2934 for (i
= 0; i
< providerTable
->numProviders
&&
2935 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2938 if (i
< providerTable
->numProviders
)
2940 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2942 if (*lpBufferSize
< sizeNeeded
)
2944 *lpBufferSize
= sizeNeeded
;
2949 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2951 /* FIXME: is *lpBufferSize set to the number of characters
2957 ret
= WN_NO_NETWORK
;
2961 TRACE("Returning %d\n", ret
);