4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
7 * Copyright 2016-2018 Pierre Schweitzer
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #define WINE_MOUNTMGR_EXTENSIONS
34 #include "ddk/mountmgr.h"
35 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(mpr
);
41 /* Data structures representing network service providers. Assumes only one
42 * thread creates them, and that they are constant for the life of the process
43 * (and therefore doesn't synchronize access).
44 * FIXME: only basic provider data and enumeration-related data are implemented
45 * so far, need to implement the rest too.
47 typedef struct _WNetProvider
55 PF_NPOpenEnum openEnum
;
56 PF_NPEnumResource enumResource
;
57 PF_NPCloseEnum closeEnum
;
58 PF_NPGetResourceInformation getResourceInformation
;
59 PF_NPAddConnection addConnection
;
60 PF_NPAddConnection3 addConnection3
;
61 PF_NPCancelConnection cancelConnection
;
62 } WNetProvider
, *PWNetProvider
;
64 typedef struct _WNetProviderTable
69 WNetProvider table
[1];
70 } WNetProviderTable
, *PWNetProviderTable
;
72 #define WNET_ENUMERATOR_TYPE_GLOBAL 0
73 #define WNET_ENUMERATOR_TYPE_PROVIDER 1
74 #define WNET_ENUMERATOR_TYPE_CONTEXT 2
75 #define WNET_ENUMERATOR_TYPE_CONNECTED 3
76 #define WNET_ENUMERATOR_TYPE_REMEMBERED 4
78 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
79 * the enumeration; it represents one of the following types:
80 * - a global enumeration, one that's executed across all providers
81 * - a provider-specific enumeration, one that's only executed by a single
83 * - a context enumeration. I know this contradicts what I just said about
84 * there being no correspondence between the scope and the type, but it's
85 * necessary for the special case that a "Entire Network" entry needs to
86 * be enumerated in an enumeration of the context scope. Thus an enumeration
87 * of the context scope results in a context type enumerator, which morphs
88 * into a global enumeration (so the enumeration continues across all
90 * - a remembered enumeration, not related to providers themselves, but it
91 * is a registry enumeration for saved connections
93 typedef struct _WNetEnumerator
112 } WNetEnumerator
, *PWNetEnumerator
;
114 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
116 /* Returns an index (into the global WNetProviderTable) of the provider with
117 * the given name, or BAD_PROVIDER_INDEX if not found.
119 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
121 static PWNetProviderTable providerTable
;
124 * Global provider table functions
127 static void _tryLoadProvider(PCWSTR provider
)
129 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
130 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
131 'S','e','r','v','i','c','e','s','\\',0 };
132 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
133 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
134 WCHAR serviceName
[MAX_PATH
];
137 TRACE("%s\n", debugstr_w(provider
));
138 swprintf(serviceName
, ARRAY_SIZE(serviceName
), serviceFmt
, servicePrefix
, provider
);
139 serviceName
[ARRAY_SIZE(serviceName
) - 1] = '\0';
140 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
143 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
145 WCHAR providerPath
[MAX_PATH
];
146 DWORD type
, size
= sizeof(providerPath
);
148 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
149 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
151 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
154 if (type
== REG_EXPAND_SZ
)
156 WCHAR path
[MAX_PATH
];
157 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
161 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
164 name
= HeapAlloc(GetProcessHeap(), 0, size
);
165 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
166 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
168 HeapFree(GetProcessHeap(), 0, name
);
174 HMODULE hLib
= LoadLibraryW(providerPath
);
178 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
180 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
182 TRACE("loaded lib %p\n", hLib
);
186 PWNetProvider provider
=
187 &providerTable
->table
[providerTable
->numProviders
];
189 provider
->hLib
= hLib
;
190 provider
->name
= name
;
191 TRACE("name is %s\n", debugstr_w(name
));
192 provider
->getCaps
= getCaps
;
193 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
194 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
195 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
196 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
197 if (provider
->dwEnumScopes
)
199 TRACE("supports enumeration\n");
200 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
201 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
202 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
203 TRACE("NPEnumResource %p\n", provider
->enumResource
);
204 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
205 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
206 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
207 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
208 if (!provider
->openEnum
||
209 !provider
->enumResource
||
210 !provider
->closeEnum
)
212 provider
->openEnum
= NULL
;
213 provider
->enumResource
= NULL
;
214 provider
->closeEnum
= NULL
;
215 provider
->dwEnumScopes
= 0;
216 WARN("Couldn't load enumeration functions\n");
219 connectCap
= getCaps(WNNC_CONNECTION
);
220 if (connectCap
& WNNC_CON_ADDCONNECTION
)
221 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
222 if (connectCap
& WNNC_CON_ADDCONNECTION3
)
223 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
224 if (connectCap
& WNNC_CON_CANCELCONNECTION
)
225 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
226 TRACE("NPAddConnection %p\n", provider
->addConnection
);
227 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
228 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
229 providerTable
->numProviders
++;
233 WARN("Provider %s didn't export NPGetCaps\n",
234 debugstr_w(provider
));
235 HeapFree(GetProcessHeap(), 0, name
);
243 WARN("Couldn't load library %s for provider %s\n",
244 debugstr_w(providerPath
), debugstr_w(provider
));
245 HeapFree(GetProcessHeap(), 0, name
);
250 WARN("Couldn't get provider name for provider %s\n",
251 debugstr_w(provider
));
255 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
259 WARN("Couldn't open service key for provider %s\n",
260 debugstr_w(provider
));
263 void wnetInit(HINSTANCE hInstDll
)
265 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
266 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
267 'C','o','n','t','r','o','l','\\',
268 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
269 'O','r','d','e','r',0 };
270 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
271 'O','r','d','e','r',0 };
274 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
279 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
282 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
288 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
289 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
294 TRACE("provider order is %s\n", debugstr_w(providers
));
295 /* first count commas as a heuristic for how many to
296 * allocate space for */
297 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
299 ptr
= wcschr(ptr
, ',');
306 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
307 sizeof(WNetProviderTable
)
308 + (numToAllocate
- 1) * sizeof(WNetProvider
));
312 int entireNetworkLen
;
313 LPCWSTR stringresource
;
315 entireNetworkLen
= LoadStringW(hInstDll
,
316 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
317 providerTable
->entireNetwork
= HeapAlloc(
318 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
320 if (providerTable
->entireNetwork
)
322 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
323 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
325 providerTable
->numAllocated
= numToAllocate
;
326 for (ptr
= providers
; ptr
; )
329 ptr
= wcschr(ptr
, ',');
332 _tryLoadProvider(ptrPrev
);
336 HeapFree(GetProcessHeap(), 0, providers
);
349 for (i
= 0; i
< providerTable
->numProviders
; i
++)
351 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
352 FreeModule(providerTable
->table
[i
].hLib
);
354 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
355 HeapFree(GetProcessHeap(), 0, providerTable
);
356 providerTable
= NULL
;
360 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
362 DWORD ret
= BAD_PROVIDER_INDEX
;
364 if (providerTable
&& providerTable
->numProviders
)
368 for (i
= 0; i
< providerTable
->numProviders
&&
369 ret
== BAD_PROVIDER_INDEX
; i
++)
370 if (!lstrcmpW(lpProvider
, providerTable
->table
[i
].name
))
380 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
386 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
392 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
393 if (lpNet
->lpRemoteName
)
395 len
= lstrlenW(lpNet
->lpRemoteName
) + 1;
396 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
397 if (ret
->lpRemoteName
)
398 lstrcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
407 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
411 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
412 HeapFree(GetProcessHeap(), 0, lpNet
);
416 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
417 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
419 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
420 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
424 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
425 ret
->dwScope
= dwScope
;
426 ret
->dwType
= dwType
;
427 ret
->dwUsage
= dwUsage
;
428 ret
->specific
.net
= _copyNetResourceForEnumW(lpNet
);
433 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
434 DWORD dwUsage
, DWORD index
, HANDLE handle
)
438 if (!providerTable
|| index
>= providerTable
->numProviders
)
442 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
445 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
446 ret
->providerIndex
= index
;
447 ret
->dwScope
= dwScope
;
448 ret
->dwType
= dwType
;
449 ret
->dwUsage
= dwUsage
;
450 ret
->handle
= handle
;
456 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
459 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
460 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
464 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
465 ret
->dwScope
= dwScope
;
466 ret
->dwType
= dwType
;
467 ret
->dwUsage
= dwUsage
;
472 static PWNetEnumerator
_createConnectedEnumerator(DWORD dwScope
, DWORD dwType
,
475 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
478 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONNECTED
;
479 ret
->dwScope
= dwScope
;
480 ret
->dwType
= dwType
;
481 ret
->dwUsage
= dwUsage
;
482 ret
->specific
.handles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HANDLE
) * providerTable
->numProviders
);
483 if (!ret
->specific
.handles
)
485 HeapFree(GetProcessHeap(), 0, ret
);
492 static PWNetEnumerator
_createRememberedEnumerator(DWORD dwScope
, DWORD dwType
,
495 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
498 ret
->enumType
= WNET_ENUMERATOR_TYPE_REMEMBERED
;
499 ret
->dwScope
= dwScope
;
500 ret
->dwType
= dwType
;
501 ret
->specific
.remembered
.registry
= remembered
;
506 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
507 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
508 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
509 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
510 * if not all members of the array could be thunked, and something else on
513 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
514 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
516 DWORD i
, numToThunk
, totalBytes
, ret
;
520 return WN_BAD_POINTER
;
522 return WN_BAD_POINTER
;
526 return WN_BAD_POINTER
;
528 return WN_BAD_POINTER
;
530 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
532 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
534 totalBytes
+= sizeof(NETRESOURCEA
);
535 if (lpNet
->lpLocalName
)
536 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
537 -1, NULL
, 0, NULL
, NULL
);
538 if (lpNet
->lpRemoteName
)
539 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
540 -1, NULL
, 0, NULL
, NULL
);
541 if (lpNet
->lpComment
)
542 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
543 -1, NULL
, 0, NULL
, NULL
);
544 if (lpNet
->lpProvider
)
545 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
546 -1, NULL
, 0, NULL
, NULL
);
547 if (totalBytes
< *lpBufferSize
)
550 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
551 for (i
= 0; i
< numToThunk
; i
++)
553 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
554 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
556 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
557 /* lie about string lengths, we already verified how many
558 * we have space for above
560 if (lpNetIn
->lpLocalName
)
562 lpNetOut
->lpLocalName
= strNext
;
563 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
564 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
566 if (lpNetIn
->lpRemoteName
)
568 lpNetOut
->lpRemoteName
= strNext
;
569 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
570 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
572 if (lpNetIn
->lpComment
)
574 lpNetOut
->lpComment
= strNext
;
575 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
576 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
578 if (lpNetIn
->lpProvider
)
580 lpNetOut
->lpProvider
= strNext
;
581 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
582 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
585 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
586 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
591 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
592 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
593 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
594 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
595 * if not all members of the array could be thunked, and something else on
598 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
599 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
601 DWORD i
, numToThunk
, totalBytes
, ret
;
605 return WN_BAD_POINTER
;
607 return WN_BAD_POINTER
;
611 return WN_BAD_POINTER
;
613 return WN_BAD_POINTER
;
615 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
617 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
619 totalBytes
+= sizeof(NETRESOURCEW
);
620 if (lpNet
->lpLocalName
)
621 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
622 -1, NULL
, 0) * sizeof(WCHAR
);
623 if (lpNet
->lpRemoteName
)
624 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
625 -1, NULL
, 0) * sizeof(WCHAR
);
626 if (lpNet
->lpComment
)
627 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
628 -1, NULL
, 0) * sizeof(WCHAR
);
629 if (lpNet
->lpProvider
)
630 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
631 -1, NULL
, 0) * sizeof(WCHAR
);
632 if (totalBytes
< *lpBufferSize
)
635 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
636 for (i
= 0; i
< numToThunk
; i
++)
638 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
639 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
641 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
642 /* lie about string lengths, we already verified how many
643 * we have space for above
645 if (lpNetIn
->lpLocalName
)
647 lpNetOut
->lpLocalName
= strNext
;
648 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
649 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
651 if (lpNetIn
->lpRemoteName
)
653 lpNetOut
->lpRemoteName
= strNext
;
654 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
655 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
657 if (lpNetIn
->lpComment
)
659 lpNetOut
->lpComment
= strNext
;
660 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
661 -1, lpNetOut
->lpComment
, *lpBufferSize
);
663 if (lpNetIn
->lpProvider
)
665 lpNetOut
->lpProvider
= strNext
;
666 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
667 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
670 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
671 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
676 /*********************************************************************
677 * WNetOpenEnumA [MPR.@]
679 * See comments for WNetOpenEnumW.
681 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
682 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
686 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
687 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
690 ret
= WN_BAD_POINTER
;
691 else if (!providerTable
|| providerTable
->numProviders
== 0)
700 LPNETRESOURCEW lpNetWide
= NULL
;
702 DWORD size
= sizeof(buf
), count
= 1;
703 BOOL allocated
= FALSE
;
705 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
706 if (ret
== WN_MORE_DATA
)
708 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
712 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
717 ret
= WN_OUT_OF_MEMORY
;
719 else if (ret
== WN_SUCCESS
)
720 lpNetWide
= (LPNETRESOURCEW
)buf
;
721 if (ret
== WN_SUCCESS
)
722 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
725 HeapFree(GetProcessHeap(), 0, lpNetWide
);
728 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
732 TRACE("Returning %d\n", ret
);
736 /*********************************************************************
737 * WNetOpenEnumW [MPR.@]
739 * Network enumeration has way too many parameters, so I'm not positive I got
740 * them right. What I've got so far:
742 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
743 * all the network providers should be enumerated.
745 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
746 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
747 * lpProvider is set, all the network providers should be enumerated.
748 * (This means the enumeration is a list of network providers, not that the
749 * enumeration is passed on to the providers.)
751 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
752 * resource matches the "Entire Network" resource (no remote name, no
753 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
754 * enumeration is done on every network provider.
756 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
757 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
758 * only to the given network provider.
760 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
761 * no lpProvider is set, enumeration will be tried on every network provider,
762 * in the order in which they're loaded.
764 * - The LPNETRESOURCE should be disregarded for scopes besides
765 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
766 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
768 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
769 * resource in the enumerated list, as well as any machines in your
770 * workgroup. The machines in your workgroup come from doing a
771 * RESOURCE_CONTEXT enumeration of every Network Provider.
773 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
774 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
778 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
779 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
782 ret
= WN_BAD_POINTER
;
783 else if (!providerTable
|| providerTable
->numProviders
== 0)
792 case RESOURCE_GLOBALNET
:
795 if (lpNet
->lpProvider
)
797 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
799 if (index
!= BAD_PROVIDER_INDEX
)
801 if (providerTable
->table
[index
].openEnum
&&
802 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
805 PWSTR RemoteName
= lpNet
->lpRemoteName
;
807 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
808 RemoteName
&& !lstrcmpW(RemoteName
, lpNet
->lpProvider
))
809 lpNet
->lpRemoteName
= NULL
;
811 ret
= providerTable
->table
[index
].openEnum(
812 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
813 if (ret
== WN_SUCCESS
)
815 *lphEnum
= _createProviderEnumerator(
816 dwScope
, dwType
, dwUsage
, index
, handle
);
817 ret
= *lphEnum
? WN_SUCCESS
:
821 lpNet
->lpRemoteName
= RemoteName
;
824 ret
= WN_NOT_SUPPORTED
;
827 ret
= WN_BAD_PROVIDER
;
829 else if (lpNet
->lpRemoteName
)
831 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
832 dwType
, dwUsage
, lpNet
);
833 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
837 if (lpNet
->lpComment
&& !lstrcmpW(lpNet
->lpComment
,
838 providerTable
->entireNetwork
))
840 /* comment matches the "Entire Network", enumerate
841 * global scope of every provider
843 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
844 dwType
, dwUsage
, lpNet
);
848 /* this is the same as not having passed lpNet */
849 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
850 dwType
, dwUsage
, NULL
);
852 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
857 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
859 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
862 case RESOURCE_CONTEXT
:
863 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
864 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
866 case RESOURCE_CONNECTED
:
867 *lphEnum
= _createConnectedEnumerator(dwScope
, dwType
, dwUsage
);
868 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
870 case RESOURCE_REMEMBERED
:
872 HKEY remembered
, user_profile
;
874 ret
= WN_OUT_OF_MEMORY
;
875 if (RegOpenCurrentUser(KEY_READ
, &user_profile
) == ERROR_SUCCESS
)
877 WCHAR subkey
[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
879 if (RegOpenKeyExW(user_profile
, subkey
, 0, KEY_READ
, &remembered
) == ERROR_SUCCESS
)
881 *lphEnum
= _createRememberedEnumerator(dwScope
, dwType
, remembered
);
882 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
885 RegCloseKey(user_profile
);
890 WARN("unknown scope 0x%08x\n", dwScope
);
896 TRACE("Returning %d\n", ret
);
900 /*********************************************************************
901 * WNetEnumResourceA [MPR.@]
903 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
904 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
908 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
911 ret
= WN_BAD_POINTER
;
913 ret
= WN_BAD_POINTER
;
915 ret
= WN_BAD_POINTER
;
916 else if (!lpBufferSize
)
917 ret
= WN_BAD_POINTER
;
918 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
920 *lpBufferSize
= sizeof(NETRESOURCEA
);
925 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
926 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
930 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
932 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
934 /* FIXME: this isn't necessarily going to work in the case of
935 * WN_MORE_DATA, because our enumerator may have moved on to
936 * the next provider. MSDN states that a large (16KB) buffer
937 * size is the appropriate usage of this function, so
938 * hopefully it won't be an issue.
940 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
941 lpBuffer
, lpBufferSize
);
942 *lpcCount
= localCount
;
944 HeapFree(GetProcessHeap(), 0, localBuffer
);
947 ret
= WN_OUT_OF_MEMORY
;
951 TRACE("Returning %d\n", ret
);
955 static DWORD
_countProviderBytesW(PWNetProvider provider
)
961 ret
= sizeof(NETRESOURCEW
);
962 ret
+= 2 * (lstrlenW(provider
->name
) + 1) * sizeof(WCHAR
);
969 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
970 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
975 return WN_BAD_POINTER
;
976 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
979 return WN_BAD_POINTER
;
981 return WN_BAD_POINTER
;
983 return WN_BAD_POINTER
;
984 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
987 if (!providerTable
|| enumerator
->providerIndex
>=
988 providerTable
->numProviders
)
989 ret
= WN_NO_MORE_ENTRIES
;
992 DWORD bytes
= 0, count
= 0, countLimit
, i
;
993 LPNETRESOURCEW resource
;
996 countLimit
= *lpcCount
== -1 ?
997 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
998 while (count
< countLimit
&& bytes
< *lpBufferSize
)
1000 DWORD bytesNext
= _countProviderBytesW(
1001 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
1003 if (bytes
+ bytesNext
< *lpBufferSize
)
1009 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
1010 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
1012 resource
->dwScope
= RESOURCE_GLOBALNET
;
1013 resource
->dwType
= RESOURCETYPE_ANY
;
1014 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
1015 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
1016 RESOURCEUSAGE_RESERVED
;
1017 resource
->lpLocalName
= NULL
;
1018 resource
->lpRemoteName
= strNext
;
1019 lstrcpyW(resource
->lpRemoteName
,
1020 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1021 strNext
+= lstrlenW(resource
->lpRemoteName
) + 1;
1022 resource
->lpComment
= NULL
;
1023 resource
->lpProvider
= strNext
;
1024 lstrcpyW(resource
->lpProvider
,
1025 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1026 strNext
+= lstrlenW(resource
->lpProvider
) + 1;
1028 enumerator
->providerIndex
+= count
;
1030 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
1032 TRACE("Returning %d\n", ret
);
1036 /* Advances the enumerator (assumed to be a global enumerator) to the next
1037 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1038 * not open a handle with the next provider.
1039 * If the existing handle is NULL, may leave the enumerator unchanged, since
1040 * the current provider may support the desired scope.
1041 * If the existing handle is not NULL, closes it before moving on.
1042 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1043 * provider, and another error on failure.
1045 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
1048 return WN_BAD_POINTER
;
1049 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1050 return WN_BAD_VALUE
;
1051 if (!providerTable
|| enumerator
->providerIndex
>=
1052 providerTable
->numProviders
)
1053 return WN_NO_MORE_ENTRIES
;
1055 if (enumerator
->providerDone
)
1058 enumerator
->providerDone
= FALSE
;
1059 if (enumerator
->handle
)
1061 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1062 enumerator
->handle
);
1063 enumerator
->handle
= NULL
;
1064 enumerator
->providerIndex
++;
1066 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1067 dwEnum
= WNNC_ENUM_LOCAL
;
1068 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1069 dwEnum
= WNNC_ENUM_GLOBAL
;
1070 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1071 dwEnum
= WNNC_ENUM_CONTEXT
;
1072 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1073 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1074 & dwEnum
); enumerator
->providerIndex
++)
1077 return enumerator
->providerIndex
< providerTable
->numProviders
?
1078 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1081 /* "Passes through" call to the next provider that supports the enumeration
1083 * FIXME: if one call to a provider's enumerator succeeds while there's still
1084 * space in lpBuffer, I don't call to the next provider. The caller may not
1085 * expect that it should call EnumResourceW again with a return value of
1086 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1087 * may have to be moved around a bit, ick.
1089 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1090 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1095 return WN_BAD_POINTER
;
1096 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1097 return WN_BAD_VALUE
;
1099 return WN_BAD_POINTER
;
1101 return WN_BAD_POINTER
;
1103 return WN_BAD_POINTER
;
1104 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1105 return WN_MORE_DATA
;
1107 ret
= _globalEnumeratorAdvance(enumerator
);
1108 if (ret
== WN_SUCCESS
)
1110 ret
= providerTable
->table
[enumerator
->providerIndex
].
1111 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1112 enumerator
->dwUsage
, enumerator
->specific
.net
,
1113 &enumerator
->handle
);
1114 if (ret
== WN_SUCCESS
)
1116 ret
= providerTable
->table
[enumerator
->providerIndex
].
1117 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1119 if (ret
!= WN_MORE_DATA
)
1120 enumerator
->providerDone
= TRUE
;
1123 TRACE("Returning %d\n", ret
);
1127 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1128 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1133 return WN_BAD_POINTER
;
1134 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1135 return WN_BAD_VALUE
;
1137 return WN_BAD_POINTER
;
1139 return WN_BAD_POINTER
;
1141 return WN_BAD_POINTER
;
1142 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1143 return WN_MORE_DATA
;
1145 return WN_NO_NETWORK
;
1147 switch (enumerator
->dwScope
)
1149 case RESOURCE_GLOBALNET
:
1150 if (enumerator
->specific
.net
)
1151 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1152 lpBuffer
, lpBufferSize
);
1154 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1157 case RESOURCE_CONTEXT
:
1158 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1162 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1163 ret
= WN_NO_MORE_ENTRIES
;
1165 TRACE("Returning %d\n", ret
);
1169 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1170 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1173 return WN_BAD_POINTER
;
1174 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1175 return WN_BAD_VALUE
;
1176 if (!enumerator
->handle
)
1177 return WN_BAD_VALUE
;
1179 return WN_BAD_POINTER
;
1181 return WN_BAD_POINTER
;
1183 return WN_BAD_POINTER
;
1185 return WN_NO_NETWORK
;
1186 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1187 return WN_NO_MORE_ENTRIES
;
1188 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1189 return WN_BAD_VALUE
;
1190 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1191 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1194 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1195 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1198 size_t cchEntireNetworkLen
, bytesNeeded
;
1201 return WN_BAD_POINTER
;
1202 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1203 return WN_BAD_VALUE
;
1205 return WN_BAD_POINTER
;
1207 return WN_BAD_POINTER
;
1209 return WN_BAD_POINTER
;
1211 return WN_NO_NETWORK
;
1213 cchEntireNetworkLen
= lstrlenW(providerTable
->entireNetwork
) + 1;
1214 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1215 if (*lpBufferSize
< bytesNeeded
)
1217 *lpBufferSize
= bytesNeeded
;
1222 LPNETRESOURCEW lpNet
= lpBuffer
;
1224 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1225 lpNet
->dwType
= enumerator
->dwType
;
1226 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1227 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1228 lpNet
->lpLocalName
= NULL
;
1229 lpNet
->lpRemoteName
= NULL
;
1230 lpNet
->lpProvider
= NULL
;
1231 /* odd, but correct: put comment at end of buffer, so it won't get
1232 * overwritten by subsequent calls to a provider's enumResource
1234 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1235 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1236 lstrcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1239 if (ret
== WN_SUCCESS
)
1241 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1243 /* "Entire Network" entry enumerated--morph this into a global
1244 * enumerator. enumerator->lpNet continues to be NULL, since it has
1245 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1247 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1248 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1249 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1250 if (ret
== WN_SUCCESS
)
1252 /* reflect the fact that we already enumerated "Entire Network" */
1254 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1258 /* the provider enumeration failed, but we already succeeded in
1259 * enumerating "Entire Network"--leave type as global to allow a
1260 * retry, but indicate success with a count of one.
1264 *lpBufferSize
= bytesNeeded
;
1267 TRACE("Returning %d\n", ret
);
1271 static DWORD
_copyStringToEnumW(const WCHAR
*source
, DWORD
* left
, void** end
)
1274 WCHAR
* local
= *end
;
1276 len
= lstrlenW(source
) + 1;
1277 len
*= sizeof(WCHAR
);
1279 return WN_MORE_DATA
;
1281 local
-= (len
/ sizeof(WCHAR
));
1282 memcpy(local
, source
, len
);
1289 static DWORD
_enumerateConnectedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1290 void* user_buffer
, DWORD
* user_size
)
1292 DWORD ret
, index
, count
, total_count
, size
, i
, left
;
1294 NETRESOURCEW
* curr
, * buffer
;
1298 return WN_BAD_POINTER
;
1299 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONNECTED
)
1300 return WN_BAD_VALUE
;
1301 if (!user_count
|| !user_buffer
|| !user_size
)
1302 return WN_BAD_POINTER
;
1304 return WN_NO_NETWORK
;
1306 handles
= enumerator
->specific
.handles
;
1309 buffer
= HeapAlloc(GetProcessHeap(), 0, *user_size
);
1311 return WN_NO_NETWORK
;
1314 end
= (char *)user_buffer
+ size
;
1315 count
= *user_count
;
1318 ret
= WN_NO_MORE_ENTRIES
;
1319 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1321 if (providerTable
->table
[index
].dwEnumScopes
)
1323 if (handles
[index
] == 0)
1325 ret
= providerTable
->table
[index
].openEnum(enumerator
->dwScope
,
1327 enumerator
->dwUsage
,
1328 NULL
, &handles
[index
]);
1329 if (ret
!= WN_SUCCESS
)
1333 ret
= providerTable
->table
[index
].enumResource(handles
[index
],
1336 total_count
+= count
;
1337 if (ret
== WN_MORE_DATA
)
1340 if (ret
== WN_SUCCESS
)
1342 for (i
= 0; i
< count
; ++i
)
1344 if (left
< sizeof(NETRESOURCEW
))
1350 memcpy(curr
, &buffer
[i
], sizeof(NETRESOURCEW
));
1351 left
-= sizeof(NETRESOURCEW
);
1353 ret
= _copyStringToEnumW(buffer
[i
].lpLocalName
, &left
, &end
);
1354 if (ret
== WN_MORE_DATA
)
1356 curr
->lpLocalName
= end
;
1358 ret
= _copyStringToEnumW(buffer
[i
].lpRemoteName
, &left
, &end
);
1359 if (ret
== WN_MORE_DATA
)
1361 curr
->lpRemoteName
= end
;
1363 ret
= _copyStringToEnumW(buffer
[i
].lpProvider
, &left
, &end
);
1364 if (ret
== WN_MORE_DATA
)
1366 curr
->lpProvider
= end
;
1374 if (*user_count
!= -1)
1375 count
= *user_count
- total_count
;
1377 count
= *user_count
;
1381 if (total_count
== 0)
1382 ret
= WN_NO_MORE_ENTRIES
;
1384 *user_count
= total_count
;
1385 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1388 HeapFree(GetProcessHeap(), 0, buffer
);
1390 TRACE("Returning %d\n", ret
);
1394 static const WCHAR connectionType
[] = { 'C','o','n','n','e','c','t','i','o','n','T','y','p','e',0 };
1395 static const WCHAR providerName
[] = { 'P','r','o','v','i','d','e','r','N','a','m','e',0 };
1396 static const WCHAR remotePath
[] = { 'R','e','m','o','t','e','P','a','t','h',0 };
1398 static WCHAR
*get_reg_str(HKEY hkey
, const WCHAR
*value
, DWORD
*len
)
1403 if (!RegQueryValueExW(hkey
, value
, NULL
, &type
, NULL
, len
) && type
== REG_SZ
)
1405 if (!(ret
= HeapAlloc(GetProcessHeap(), 0, *len
))) return NULL
;
1406 RegQueryValueExW(hkey
, value
, 0, 0, (BYTE
*)ret
, len
);
1412 static DWORD
_enumeratorRememberedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1413 void* user_buffer
, DWORD
* user_size
)
1415 HKEY registry
, connection
;
1418 DWORD index
, ret
, type
, len
, size
, registry_size
, full_size
= 0, total_count
;
1419 NETRESOURCEW
* net_buffer
= user_buffer
;
1420 WCHAR
* str
, * registry_string
;
1422 /* we will do the work in a single loop, so here is some things:
1423 * we write netresource at the begin of the user buffer
1424 * we write strings at the end of the user buffer
1426 size_left
= *user_size
;
1428 type
= enumerator
->dwType
;
1429 registry
= enumerator
->specific
.remembered
.registry
;
1430 str
= (WCHAR
*)((ULONG_PTR
)user_buffer
+ *user_size
- sizeof(WCHAR
));
1431 for (index
= enumerator
->specific
.remembered
.index
; ; ++index
)
1433 enumerator
->specific
.remembered
.index
= index
;
1435 if (*user_count
!= -1 && total_count
== *user_count
)
1441 len
= ARRAY_SIZE(buffer
);
1442 ret
= RegEnumKeyExW(registry
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
);
1443 if (ret
!= ERROR_SUCCESS
)
1445 if (ret
== ERROR_NO_MORE_ITEMS
) ret
= WN_SUCCESS
;
1449 if (RegOpenKeyExW(registry
, buffer
, 0, KEY_READ
, &connection
) != ERROR_SUCCESS
)
1454 full_size
= sizeof(NETRESOURCEW
);
1455 size_left
-= sizeof(NETRESOURCEW
);
1459 size
= sizeof(DWORD
);
1460 RegQueryValueExW(connection
, connectionType
, NULL
, NULL
, (BYTE
*)&net_buffer
->dwType
, &size
);
1461 if (type
!= RESOURCETYPE_ANY
&& net_buffer
->dwType
!= type
)
1463 size_left
+= sizeof(NETRESOURCEW
);
1464 RegCloseKey(connection
);
1468 net_buffer
->dwScope
= RESOURCE_REMEMBERED
;
1469 net_buffer
->dwDisplayType
= RESOURCEDISPLAYTYPE_GENERIC
;
1470 net_buffer
->dwUsage
= RESOURCEUSAGE_CONNECTABLE
;
1475 /* FIXME: this only supports drive letters */
1476 full_size
+= 3 * sizeof(WCHAR
);
1477 size_left
-= 3 * sizeof(WCHAR
);
1484 net_buffer
->lpLocalName
= str
;
1488 registry_string
= get_reg_str(connection
, providerName
, ®istry_size
);
1489 if (registry_string
)
1491 full_size
+= registry_size
;
1492 size_left
-= registry_size
;
1496 str
-= (registry_size
/ sizeof(WCHAR
));
1497 lstrcpyW(str
, registry_string
);
1498 net_buffer
->lpProvider
= str
;
1503 HeapFree(GetProcessHeap(), 0, registry_string
);
1507 registry_string
= get_reg_str(connection
, remotePath
, ®istry_size
);
1508 if (registry_string
)
1510 full_size
+= registry_size
;
1511 size_left
-= registry_size
;
1515 str
-= (registry_size
/ sizeof(WCHAR
));
1516 lstrcpyW(str
, registry_string
);
1517 net_buffer
->lpRemoteName
= str
;
1522 HeapFree(GetProcessHeap(), 0, registry_string
);
1525 RegCloseKey(connection
);
1527 net_buffer
->lpComment
= NULL
;
1536 if (total_count
== 0)
1537 ret
= WN_NO_MORE_ENTRIES
;
1539 *user_count
= total_count
;
1541 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1544 if (ret
== WN_MORE_DATA
)
1545 *user_size
= *user_size
+ full_size
;
1550 /*********************************************************************
1551 * WNetEnumResourceW [MPR.@]
1553 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1554 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1558 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1561 ret
= WN_BAD_POINTER
;
1563 ret
= WN_BAD_POINTER
;
1565 ret
= WN_BAD_POINTER
;
1566 else if (!lpBufferSize
)
1567 ret
= WN_BAD_POINTER
;
1568 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1570 *lpBufferSize
= sizeof(NETRESOURCEW
);
1575 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1577 switch (enumerator
->enumType
)
1579 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1580 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1583 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1584 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1587 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1588 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1591 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1592 ret
= _enumerateConnectedW(enumerator
, lpcCount
, lpBuffer
,
1595 case WNET_ENUMERATOR_TYPE_REMEMBERED
:
1596 ret
= _enumeratorRememberedW(enumerator
, lpcCount
, lpBuffer
,
1600 WARN("bogus enumerator type!\n");
1601 ret
= WN_NO_NETWORK
;
1606 TRACE("Returning %d\n", ret
);
1610 /*********************************************************************
1611 * WNetCloseEnum [MPR.@]
1613 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1618 TRACE( "(%p)\n", hEnum
);
1622 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1624 switch (enumerator
->enumType
)
1626 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1627 if (enumerator
->specific
.net
)
1628 _freeEnumNetResource(enumerator
->specific
.net
);
1629 if (enumerator
->handle
)
1630 providerTable
->table
[enumerator
->providerIndex
].
1631 closeEnum(enumerator
->handle
);
1634 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1635 if (enumerator
->handle
)
1636 providerTable
->table
[enumerator
->providerIndex
].
1637 closeEnum(enumerator
->handle
);
1640 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1641 handles
= enumerator
->specific
.handles
;
1642 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1644 if (providerTable
->table
[index
].dwEnumScopes
&& handles
[index
])
1645 providerTable
->table
[index
].closeEnum(handles
[index
]);
1647 HeapFree(GetProcessHeap(), 0, handles
);
1650 case WNET_ENUMERATOR_TYPE_REMEMBERED
:
1651 RegCloseKey(enumerator
->specific
.remembered
.registry
);
1655 WARN("bogus enumerator type!\n");
1656 ret
= WN_BAD_HANDLE
;
1658 HeapFree(GetProcessHeap(), 0, hEnum
);
1661 ret
= WN_BAD_HANDLE
;
1664 TRACE("Returning %d\n", ret
);
1668 /*********************************************************************
1669 * WNetGetResourceInformationA [MPR.@]
1671 * See WNetGetResourceInformationW
1673 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1674 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1679 TRACE( "(%p, %p, %p, %p)\n",
1680 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1682 if (!providerTable
|| providerTable
->numProviders
== 0)
1683 ret
= WN_NO_NETWORK
;
1684 else if (lpNetResource
)
1686 LPNETRESOURCEW lpNetResourceW
= NULL
;
1687 DWORD size
= 1024, count
= 1;
1690 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1691 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1692 if (ret
== WN_MORE_DATA
)
1694 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1695 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1697 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1698 &count
, lpNetResourceW
, &size
);
1700 ret
= WN_OUT_OF_MEMORY
;
1702 if (ret
== WN_SUCCESS
)
1704 LPWSTR lpSystemW
= NULL
;
1707 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1710 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1711 lpBufferW
, &size
, &lpSystemW
);
1712 if (ret
== WN_MORE_DATA
)
1714 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1715 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1717 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1718 lpBufferW
, &size
, &lpSystemW
);
1720 ret
= WN_OUT_OF_MEMORY
;
1722 if (ret
== WN_SUCCESS
)
1724 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1725 &count
, lpBuffer
, cbBuffer
);
1726 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1727 lpNetResourceW
= lpBufferW
;
1728 size
= sizeof(NETRESOURCEA
);
1729 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1730 -1, NULL
, 0, NULL
, NULL
);
1731 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1732 -1, NULL
, 0, NULL
, NULL
);
1734 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1735 -1, NULL
, 0, NULL
, NULL
);
1736 if ((len
) && ( size
+ len
< *cbBuffer
))
1738 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1739 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1740 *lplpSystem
, len
, NULL
, NULL
);
1747 ret
= WN_OUT_OF_MEMORY
;
1748 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1751 ret
= WN_OUT_OF_MEMORY
;
1752 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1754 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1757 ret
= WN_NO_NETWORK
;
1761 TRACE("Returning %d\n", ret
);
1765 /*********************************************************************
1766 * WNetGetResourceInformationW [MPR.@]
1768 * WNetGetResourceInformationW function identifies the network provider
1769 * that owns the resource and gets information about the type of the resource.
1772 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1773 * defines a network resource.
1774 * lpBuffer [ O] the pointer to buffer, containing result. It
1775 * contains NETRESOURCEW structure and strings to
1776 * which the members of the NETRESOURCEW structure
1778 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1780 * lplpSystem [ O] the pointer to string in the output buffer,
1781 * containing the part of the resource name without
1782 * names of the server and share.
1785 * NO_ERROR if the function succeeds. System error code if the function fails.
1788 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1789 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1790 LPWSTR
*lplpSystem
)
1792 DWORD ret
= WN_NO_NETWORK
;
1795 TRACE( "(%p, %p, %p, %p)\n",
1796 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1799 ret
= WN_OUT_OF_MEMORY
;
1800 else if (providerTable
!= NULL
)
1802 /* FIXME: For function value of a variable is indifferent, it does
1803 * search of all providers in a network.
1805 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1807 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1808 WNNC_DLG_GETRESOURCEINFORMATION
)
1810 if (providerTable
->table
[index
].getResourceInformation
)
1811 ret
= providerTable
->table
[index
].getResourceInformation(
1812 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1814 ret
= WN_NO_NETWORK
;
1815 if (ret
== WN_SUCCESS
)
1825 /*********************************************************************
1826 * WNetGetResourceParentA [MPR.@]
1828 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1829 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1831 FIXME( "(%p, %p, %p): stub\n",
1832 lpNetResource
, lpBuffer
, lpBufferSize
);
1834 SetLastError(WN_NO_NETWORK
);
1835 return WN_NO_NETWORK
;
1838 /*********************************************************************
1839 * WNetGetResourceParentW [MPR.@]
1841 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1842 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1844 FIXME( "(%p, %p, %p): stub\n",
1845 lpNetResource
, lpBuffer
, lpBufferSize
);
1847 SetLastError(WN_NO_NETWORK
);
1848 return WN_NO_NETWORK
;
1854 * Connection Functions
1857 /*********************************************************************
1858 * WNetAddConnectionA [MPR.@]
1860 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1861 LPCSTR lpLocalName
)
1863 NETRESOURCEA resourcesA
;
1865 memset(&resourcesA
, 0, sizeof(resourcesA
));
1866 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
1867 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
1868 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1871 /*********************************************************************
1872 * WNetAddConnectionW [MPR.@]
1874 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1875 LPCWSTR lpLocalName
)
1877 NETRESOURCEW resourcesW
;
1879 memset(&resourcesW
, 0, sizeof(resourcesW
));
1880 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
1881 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
1882 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1885 /*********************************************************************
1886 * WNetAddConnection2A [MPR.@]
1888 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1889 LPCSTR lpPassword
, LPCSTR lpUserID
,
1892 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1896 /*********************************************************************
1897 * WNetAddConnection2W [MPR.@]
1899 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1900 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1903 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1907 /*********************************************************************
1908 * WNetAddConnection3A [MPR.@]
1910 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1911 LPCSTR lpPassword
, LPCSTR lpUserID
,
1914 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1915 dwFlags
, NULL
, 0, NULL
);
1918 /*********************************************************************
1919 * WNetAddConnection3W [MPR.@]
1921 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1922 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1925 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1926 dwFlags
, NULL
, 0, NULL
);
1929 struct use_connection_context
1932 NETRESOURCEW
*resource
;
1933 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
1940 DWORD (*pre_set_accessname
)(struct use_connection_context
*, WCHAR
*);
1941 void (*set_accessname
)(struct use_connection_context
*, WCHAR
*);
1944 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1946 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1951 len
= lstrlenW(local_name
);
1953 len
= lstrlenW(ctxt
->resource
->lpRemoteName
);
1955 if (++len
> *ctxt
->buffer_size
)
1957 *ctxt
->buffer_size
= len
;
1958 return ERROR_MORE_DATA
;
1962 ctxt
->accessname
= NULL
;
1964 return ERROR_SUCCESS
;
1967 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1969 WCHAR
*accessname
= ctxt
->accessname
;
1972 lstrcpyW(accessname
, local_name
);
1974 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1977 lstrcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
1980 static DWORD
wnet_use_provider( struct use_connection_context
*ctxt
, NETRESOURCEW
* netres
, WNetProvider
*provider
, BOOLEAN redirect
)
1984 caps
= provider
->getCaps(WNNC_CONNECTION
);
1985 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
1986 return ERROR_BAD_PROVIDER
;
1988 ret
= WN_ACCESS_DENIED
;
1991 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
1992 ret
= provider
->addConnection3(ctxt
->hwndOwner
, netres
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
1993 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
1994 ret
= provider
->addConnection(netres
, ctxt
->password
, ctxt
->userid
);
1996 if (ret
== WN_ALREADY_CONNECTED
&& redirect
)
1997 netres
->lpLocalName
[0] -= 1;
1998 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& netres
->lpLocalName
[0] >= 'C');
2000 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
2001 ctxt
->set_accessname(ctxt
, netres
->lpLocalName
);
2006 static const WCHAR providerType
[] = { 'P','r','o','v','i','d','e','r','T','y','p','e',0 };
2007 static const WCHAR userName
[] = { 'U','s','e','r','N','a','m','e',0 };
2009 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
2011 WNetProvider
*provider
= NULL
;
2012 DWORD index
, ret
= WN_NO_NETWORK
;
2013 BOOL redirect
= FALSE
;
2014 WCHAR letter
[3] = {'Z', ':', 0};
2015 NETRESOURCEW netres
;
2017 if (!providerTable
|| providerTable
->numProviders
== 0)
2018 return WN_NO_NETWORK
;
2020 if (!ctxt
->resource
)
2021 return ERROR_INVALID_PARAMETER
;
2022 netres
= *ctxt
->resource
;
2024 if (!netres
.lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
2026 if (netres
.dwType
!= RESOURCETYPE_DISK
&& netres
.dwType
!= RESOURCETYPE_PRINT
)
2027 return ERROR_BAD_DEV_TYPE
;
2029 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2031 FIXME("Local device selection is not implemented for printers.\n");
2032 return WN_NO_NETWORK
;
2036 netres
.lpLocalName
= letter
;
2039 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
2040 return ERROR_BAD_NET_NAME
;
2042 if ((ret
= ctxt
->pre_set_accessname(ctxt
, netres
.lpLocalName
)))
2045 if (netres
.lpProvider
)
2047 index
= _findProviderIndexW(netres
.lpProvider
);
2048 if (index
== BAD_PROVIDER_INDEX
)
2049 return ERROR_BAD_PROVIDER
;
2051 provider
= &providerTable
->table
[index
];
2052 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2056 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2058 provider
= &providerTable
->table
[index
];
2059 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2060 if (ret
== WN_SUCCESS
|| ret
== WN_ALREADY_CONNECTED
)
2065 if (ret
== WN_SUCCESS
&& ctxt
->flags
& CONNECT_UPDATE_PROFILE
)
2069 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2071 FIXME("Persistent connection are not supported for printers\n");
2075 if (RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2078 WCHAR subkey
[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres
.lpLocalName
[0], 0};
2080 if (RegCreateKeyExW(user_profile
, subkey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2081 KEY_ALL_ACCESS
, NULL
, &network
, NULL
) == ERROR_SUCCESS
)
2083 DWORD dword_arg
= RESOURCETYPE_DISK
;
2084 DWORD len
= (lstrlenW(provider
->name
) + 1) * sizeof(WCHAR
);
2085 static const WCHAR empty
[1] = {0};
2087 RegSetValueExW(network
, connectionType
, 0, REG_DWORD
, (const BYTE
*)&dword_arg
, sizeof(DWORD
));
2088 RegSetValueExW(network
, providerName
, 0, REG_SZ
, (const BYTE
*)provider
->name
, len
);
2089 RegSetValueExW(network
, providerType
, 0, REG_DWORD
, (const BYTE
*)&provider
->dwNetType
, sizeof(DWORD
));
2090 len
= (lstrlenW(netres
.lpRemoteName
) + 1) * sizeof(WCHAR
);
2091 RegSetValueExW(network
, remotePath
, 0, REG_SZ
, (const BYTE
*)netres
.lpRemoteName
, len
);
2092 len
= sizeof(empty
);
2093 RegSetValueExW(network
, userName
, 0, REG_SZ
, (const BYTE
*)empty
, len
);
2094 RegCloseKey(network
);
2097 RegCloseKey(user_profile
);
2104 /*****************************************************************
2105 * WNetUseConnectionW [MPR.@]
2107 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
2108 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
2110 struct use_connection_context ctxt
;
2112 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
2113 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
2114 accessname
, buffer_size
, result
);
2116 ctxt
.hwndOwner
= hwndOwner
;
2117 ctxt
.resource
= resource
;
2118 ctxt
.resourceA
= NULL
;
2119 ctxt
.password
= (WCHAR
*)password
;
2120 ctxt
.userid
= (WCHAR
*)userid
;
2122 ctxt
.accessname
= accessname
;
2123 ctxt
.buffer_size
= buffer_size
;
2124 ctxt
.result
= result
;
2125 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
2126 ctxt
.set_accessname
= use_connection_set_accessnameW
;
2128 return wnet_use_connection(&ctxt
);
2131 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2133 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
2138 len
= WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, NULL
, 0, NULL
, NULL
) - 1;
2140 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
2142 if (++len
> *ctxt
->buffer_size
)
2144 *ctxt
->buffer_size
= len
;
2145 return ERROR_MORE_DATA
;
2149 ctxt
->accessname
= NULL
;
2151 return ERROR_SUCCESS
;
2154 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2156 char *accessname
= ctxt
->accessname
;
2159 WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, accessname
, *ctxt
->buffer_size
, NULL
, NULL
);
2161 *ctxt
->result
= CONNECT_LOCALDRIVE
;
2164 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
2167 static LPWSTR
strdupAtoW( LPCSTR str
)
2172 if (!str
) return NULL
;
2173 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
2174 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2175 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
2179 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
2181 resourceW
->dwScope
= resourceA
->dwScope
;
2182 resourceW
->dwType
= resourceA
->dwType
;
2183 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
2184 resourceW
->dwUsage
= resourceA
->dwUsage
;
2185 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
2186 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
2187 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
2188 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
2191 static void free_netresourceW( NETRESOURCEW
*resource
)
2193 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
2194 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
2195 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
2196 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
2199 /*****************************************************************
2200 * WNetUseConnectionA [MPR.@]
2202 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
2203 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
2204 DWORD
*buffer_size
, DWORD
*result
)
2206 struct use_connection_context ctxt
;
2207 NETRESOURCEW resourceW
;
2210 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
2211 accessname
, buffer_size
, result
);
2213 netresource_a_to_w(resource
, &resourceW
);
2215 ctxt
.hwndOwner
= hwndOwner
;
2216 ctxt
.resource
= &resourceW
;
2217 ctxt
.resourceA
= resource
;
2218 ctxt
.password
= strdupAtoW(password
);
2219 ctxt
.userid
= strdupAtoW(userid
);
2221 ctxt
.accessname
= accessname
;
2222 ctxt
.buffer_size
= buffer_size
;
2223 ctxt
.result
= result
;
2224 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
2225 ctxt
.set_accessname
= use_connection_set_accessnameA
;
2227 ret
= wnet_use_connection(&ctxt
);
2229 free_netresourceW(&resourceW
);
2230 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
2231 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
2236 /*********************************************************************
2237 * WNetCancelConnectionA [MPR.@]
2239 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
2241 return WNetCancelConnection2A(lpName
, 0, fForce
);
2244 /*********************************************************************
2245 * WNetCancelConnectionW [MPR.@]
2247 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
2249 return WNetCancelConnection2W(lpName
, 0, fForce
);
2252 /*********************************************************************
2253 * WNetCancelConnection2A [MPR.@]
2255 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2258 WCHAR
* name
= strdupAtoW(lpName
);
2260 return ERROR_NOT_CONNECTED
;
2262 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
2263 HeapFree(GetProcessHeap(), 0, name
);
2268 /*********************************************************************
2269 * WNetCancelConnection2W [MPR.@]
2271 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2273 DWORD ret
= WN_NO_NETWORK
;
2276 if (providerTable
!= NULL
)
2278 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2280 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2281 WNNC_CON_CANCELCONNECTION
)
2283 if (providerTable
->table
[index
].cancelConnection
)
2284 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
2286 ret
= WN_NO_NETWORK
;
2287 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
2293 if (ret
== WN_SUCCESS
&& dwFlags
& CONNECT_UPDATE_PROFILE
)
2297 /* FIXME: Only remove it if that's a drive letter */
2298 if (iswalpha(lpName
[0]) && lpName
[1] == ':' &&
2299 RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2301 WCHAR subkey
[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', lpName
[0], 0};
2303 RegDeleteKeyW(user_profile
, subkey
);
2305 RegCloseKey(user_profile
);
2312 /*****************************************************************
2313 * WNetRestoreConnectionA [MPR.@]
2315 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
2317 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
2319 SetLastError(WN_NO_NETWORK
);
2320 return WN_NO_NETWORK
;
2323 /*****************************************************************
2324 * WNetRestoreConnectionW [MPR.@]
2326 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
2328 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
2330 SetLastError(WN_NO_NETWORK
);
2331 return WN_NO_NETWORK
;
2334 /**************************************************************************
2335 * WNetGetConnectionA [MPR.@]
2338 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2339 * - WN_NOT_CONNECTED drive is a local drive
2340 * - WN_MORE_DATA buffer isn't big enough
2341 * - WN_SUCCESS success (net path in buffer)
2343 * FIXME: need to test return values under different errors
2345 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
2346 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
2351 ret
= WN_BAD_POINTER
;
2352 else if (!lpBufferSize
)
2353 ret
= WN_BAD_POINTER
;
2354 else if (!lpRemoteName
&& *lpBufferSize
)
2355 ret
= WN_BAD_POINTER
;
2358 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
2362 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2366 WCHAR wideRemoteStatic
[MAX_PATH
];
2367 DWORD wideRemoteSize
= ARRAY_SIZE(wideRemoteStatic
);
2369 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
2371 /* try once without memory allocation */
2372 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
2374 if (ret
== WN_SUCCESS
)
2376 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2377 -1, NULL
, 0, NULL
, NULL
);
2379 if (len
<= *lpBufferSize
)
2381 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
2382 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2387 *lpBufferSize
= len
;
2391 else if (ret
== WN_MORE_DATA
)
2393 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2394 wideRemoteSize
* sizeof(WCHAR
));
2398 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2400 if (ret
== WN_SUCCESS
)
2402 if (len
<= *lpBufferSize
)
2404 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2405 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2410 *lpBufferSize
= len
;
2414 HeapFree(GetProcessHeap(), 0, wideRemote
);
2417 ret
= WN_OUT_OF_MEMORY
;
2419 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2422 ret
= WN_OUT_OF_MEMORY
;
2425 ret
= WN_BAD_LOCALNAME
;
2429 TRACE("Returning %d\n", ret
);
2433 /* find the network connection for a given drive; helper for WNetGetConnection */
2434 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2437 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2439 DWORD ret
= WN_NOT_CONNECTED
;
2440 DWORD bytes_returned
;
2442 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2443 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2444 0, 0 )) == INVALID_HANDLE_VALUE
)
2446 ERR( "failed to open mount manager err %u\n", GetLastError() );
2449 memset( data
, 0, sizeof(*data
) );
2450 data
->letter
= letter
;
2451 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2452 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2454 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2457 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2460 mount_point
[0] = '\\';
2461 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2463 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2471 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2480 /**************************************************************************
2481 * WNetGetConnectionW [MPR.@]
2483 * FIXME: need to test return values under different errors
2485 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2486 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2490 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2494 ret
= WN_BAD_POINTER
;
2495 else if (!lpBufferSize
)
2496 ret
= WN_BAD_POINTER
;
2497 else if (!lpRemoteName
&& *lpBufferSize
)
2498 ret
= WN_BAD_POINTER
;
2499 else if (!lpLocalName
[0])
2500 ret
= WN_BAD_LOCALNAME
;
2503 if (lpLocalName
[1] == ':')
2505 switch(GetDriveTypeW(lpLocalName
))
2508 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2510 case DRIVE_REMOVABLE
:
2513 TRACE("file is local\n");
2514 ret
= WN_NOT_CONNECTED
;
2517 ret
= WN_BAD_LOCALNAME
;
2521 ret
= WN_BAD_LOCALNAME
;
2525 TRACE("Returning %d\n", ret
);
2529 /**************************************************************************
2530 * WNetSetConnectionA [MPR.@]
2532 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2535 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2537 SetLastError(WN_NO_NETWORK
);
2538 return WN_NO_NETWORK
;
2541 /**************************************************************************
2542 * WNetSetConnectionW [MPR.@]
2544 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2547 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2549 SetLastError(WN_NO_NETWORK
);
2550 return WN_NO_NETWORK
;
2553 /*****************************************************************
2554 * WNetGetUniversalNameA [MPR.@]
2556 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2557 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2561 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2562 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2564 switch (dwInfoLevel
)
2566 case UNIVERSAL_NAME_INFO_LEVEL
:
2568 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2570 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2572 err
= ERROR_NOT_CONNECTED
;
2576 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2577 if (*lpBufferSize
< size
)
2582 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2583 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2587 case REMOTE_NAME_INFO_LEVEL
:
2588 err
= WN_NOT_CONNECTED
;
2600 /*****************************************************************
2601 * WNetGetUniversalNameW [MPR.@]
2603 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2604 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2608 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2609 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2611 switch (dwInfoLevel
)
2613 case UNIVERSAL_NAME_INFO_LEVEL
:
2615 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2617 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2619 err
= ERROR_NOT_CONNECTED
;
2623 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2624 if (*lpBufferSize
< size
)
2626 *lpBufferSize
= size
;
2630 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2631 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2635 case REMOTE_NAME_INFO_LEVEL
:
2636 err
= WN_NO_NETWORK
;
2644 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2648 /*****************************************************************
2649 * WNetClearConnections [MPR.@]
2651 DWORD WINAPI
WNetClearConnections ( HWND owner
)
2655 DWORD ret
, size
, count
;
2656 NETRESOURCEW
* resources
, * iter
;
2658 ret
= WNetOpenEnumW(RESOURCE_CONNECTED
, RESOURCETYPE_ANY
, 0, NULL
, &connected
);
2659 if (ret
!= WN_SUCCESS
)
2661 if (ret
!= WN_NO_NETWORK
)
2666 /* Means no provider, then, clearing is OK */
2671 resources
= HeapAlloc(GetProcessHeap(), 0, size
);
2674 WNetCloseEnum(connected
);
2675 return WN_OUT_OF_MEMORY
;
2683 memset(resources
, 0, size
);
2684 ret
= WNetEnumResourceW(connected
, &count
, resources
, &size
);
2685 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2687 for (iter
= resources
; count
; count
--, iter
++)
2689 if (iter
->lpLocalName
&& iter
->lpLocalName
[0])
2690 connection
= iter
->lpLocalName
;
2692 connection
= iter
->lpRemoteName
;
2694 WNetCancelConnection2W(connection
, 0, TRUE
);
2701 HeapFree(GetProcessHeap(), 0, resources
);
2702 WNetCloseEnum(connected
);
2712 /**************************************************************************
2713 * WNetGetUserA [MPR.@]
2715 * FIXME: we should not return ourselves, but the owner of the drive lpName
2717 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2719 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2720 return GetLastError();
2723 /*****************************************************************
2724 * WNetGetUserW [MPR.@]
2726 * FIXME: we should not return ourselves, but the owner of the drive lpName
2728 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2730 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2731 return GetLastError();
2734 /*********************************************************************
2735 * WNetConnectionDialog [MPR.@]
2737 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2739 CONNECTDLGSTRUCTW conn_dlg
;
2740 NETRESOURCEW net_res
;
2742 ZeroMemory(&conn_dlg
, sizeof(conn_dlg
));
2743 ZeroMemory(&net_res
, sizeof(net_res
));
2745 conn_dlg
.cbStructure
= sizeof(conn_dlg
);
2746 conn_dlg
.lpConnRes
= &net_res
;
2747 conn_dlg
.hwndOwner
= hwnd
;
2748 net_res
.dwType
= dwType
;
2750 return WNetConnectionDialog1W(&conn_dlg
);
2753 /*********************************************************************
2754 * WNetConnectionDialog1A [MPR.@]
2756 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2758 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2760 SetLastError(WN_NO_NETWORK
);
2761 return WN_NO_NETWORK
;
2764 /*********************************************************************
2765 * WNetConnectionDialog1W [MPR.@]
2767 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2769 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2771 SetLastError(WN_NO_NETWORK
);
2772 return WN_NO_NETWORK
;
2775 /*********************************************************************
2776 * WNetDisconnectDialog [MPR.@]
2778 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2780 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2782 SetLastError(WN_NO_NETWORK
);
2783 return WN_NO_NETWORK
;
2786 /*********************************************************************
2787 * WNetDisconnectDialog1A [MPR.@]
2789 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2791 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2793 SetLastError(WN_NO_NETWORK
);
2794 return WN_NO_NETWORK
;
2797 /*********************************************************************
2798 * WNetDisconnectDialog1W [MPR.@]
2800 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2802 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2804 SetLastError(WN_NO_NETWORK
);
2805 return WN_NO_NETWORK
;
2808 /*********************************************************************
2809 * WNetGetLastErrorA [MPR.@]
2811 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2812 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2813 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2815 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2816 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2818 SetLastError(WN_NO_NETWORK
);
2819 return WN_NO_NETWORK
;
2822 /*********************************************************************
2823 * WNetGetLastErrorW [MPR.@]
2825 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2826 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2827 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2829 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2830 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2832 SetLastError(WN_NO_NETWORK
);
2833 return WN_NO_NETWORK
;
2836 /*********************************************************************
2837 * WNetGetNetworkInformationA [MPR.@]
2839 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2840 LPNETINFOSTRUCT lpNetInfoStruct
)
2844 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2847 ret
= WN_BAD_POINTER
;
2852 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2855 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2859 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2861 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2862 HeapFree(GetProcessHeap(), 0, wideProvider
);
2865 ret
= WN_OUT_OF_MEMORY
;
2868 ret
= GetLastError();
2872 TRACE("Returning %d\n", ret
);
2876 /*********************************************************************
2877 * WNetGetNetworkInformationW [MPR.@]
2879 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2880 LPNETINFOSTRUCT lpNetInfoStruct
)
2884 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2887 ret
= WN_BAD_POINTER
;
2888 else if (!lpNetInfoStruct
)
2889 ret
= WN_BAD_POINTER
;
2890 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2894 if (providerTable
&& providerTable
->numProviders
)
2896 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2898 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2900 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2901 lpNetInfoStruct
->dwProviderVersion
=
2902 providerTable
->table
[providerIndex
].dwSpecVersion
;
2903 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2904 lpNetInfoStruct
->dwCharacteristics
= 0;
2905 lpNetInfoStruct
->dwHandle
= 0;
2906 lpNetInfoStruct
->wNetType
=
2907 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2908 lpNetInfoStruct
->dwPrinters
= -1;
2909 lpNetInfoStruct
->dwDrives
= -1;
2913 ret
= WN_BAD_PROVIDER
;
2916 ret
= WN_NO_NETWORK
;
2920 TRACE("Returning %d\n", ret
);
2924 /*****************************************************************
2925 * WNetGetProviderNameA [MPR.@]
2927 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2928 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2932 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2936 ret
= WN_BAD_POINTER
;
2937 else if (!lpBufferSize
)
2938 ret
= WN_BAD_POINTER
;
2945 ret
= WN_NO_NETWORK
;
2946 for (i
= 0; i
< providerTable
->numProviders
&&
2947 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2950 if (i
< providerTable
->numProviders
)
2952 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2953 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2955 if (*lpBufferSize
< sizeNeeded
)
2957 *lpBufferSize
= sizeNeeded
;
2962 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2963 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2965 /* FIXME: is *lpBufferSize set to the number of characters
2971 ret
= WN_NO_NETWORK
;
2975 TRACE("Returning %d\n", ret
);
2979 /*****************************************************************
2980 * WNetGetProviderNameW [MPR.@]
2982 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2983 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2987 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2991 ret
= WN_BAD_POINTER
;
2992 else if (!lpBufferSize
)
2993 ret
= WN_BAD_POINTER
;
3000 ret
= WN_NO_NETWORK
;
3001 for (i
= 0; i
< providerTable
->numProviders
&&
3002 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
3005 if (i
< providerTable
->numProviders
)
3007 DWORD sizeNeeded
= lstrlenW(providerTable
->table
[i
].name
) + 1;
3009 if (*lpBufferSize
< sizeNeeded
)
3011 *lpBufferSize
= sizeNeeded
;
3016 lstrcpyW(lpProvider
, providerTable
->table
[i
].name
);
3018 /* FIXME: is *lpBufferSize set to the number of characters
3024 ret
= WN_NO_NETWORK
;
3028 TRACE("Returning %d\n", ret
);