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"
36 #include "wine/unicode.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(mpr
);
42 /* Data structures representing network service providers. Assumes only one
43 * thread creates them, and that they are constant for the life of the process
44 * (and therefore doesn't synchronize access).
45 * FIXME: only basic provider data and enumeration-related data are implemented
46 * so far, need to implement the rest too.
48 typedef struct _WNetProvider
56 PF_NPOpenEnum openEnum
;
57 PF_NPEnumResource enumResource
;
58 PF_NPCloseEnum closeEnum
;
59 PF_NPGetResourceInformation getResourceInformation
;
60 PF_NPAddConnection addConnection
;
61 PF_NPAddConnection3 addConnection3
;
62 PF_NPCancelConnection cancelConnection
;
64 PF_NPGetConnection getConnection
;
66 } WNetProvider
, *PWNetProvider
;
68 typedef struct _WNetProviderTable
73 WNetProvider table
[1];
74 } WNetProviderTable
, *PWNetProviderTable
;
76 #define WNET_ENUMERATOR_TYPE_GLOBAL 0
77 #define WNET_ENUMERATOR_TYPE_PROVIDER 1
78 #define WNET_ENUMERATOR_TYPE_CONTEXT 2
79 #define WNET_ENUMERATOR_TYPE_CONNECTED 3
80 #define WNET_ENUMERATOR_TYPE_REMEMBERED 4
82 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
83 * the enumeration; it represents one of the following types:
84 * - a global enumeration, one that's executed across all providers
85 * - a provider-specific enumeration, one that's only executed by a single
87 * - a context enumeration. I know this contradicts what I just said about
88 * there being no correspondence between the scope and the type, but it's
89 * necessary for the special case that a "Entire Network" entry needs to
90 * be enumerated in an enumeration of the context scope. Thus an enumeration
91 * of the context scope results in a context type enumerator, which morphs
92 * into a global enumeration (so the enumeration continues across all
94 * - a remembered enumeration, not related to providers themselves, but it
95 * is a registry enumeration for saved connections
97 typedef struct _WNetEnumerator
116 } WNetEnumerator
, *PWNetEnumerator
;
118 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
120 /* Returns an index (into the global WNetProviderTable) of the provider with
121 * the given name, or BAD_PROVIDER_INDEX if not found.
123 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
125 static PWNetProviderTable providerTable
;
128 * Global provider table functions
131 static void _tryLoadProvider(PCWSTR provider
)
133 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
134 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
135 'S','e','r','v','i','c','e','s','\\',0 };
136 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
137 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
138 WCHAR serviceName
[MAX_PATH
];
141 TRACE("%s\n", debugstr_w(provider
));
142 snprintfW(serviceName
, ARRAY_SIZE(serviceName
), serviceFmt
, servicePrefix
, provider
);
143 serviceName
[ARRAY_SIZE(serviceName
) - 1] = '\0';
144 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
147 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
149 WCHAR providerPath
[MAX_PATH
];
150 DWORD type
, size
= sizeof(providerPath
);
152 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
153 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
155 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
158 if (type
== REG_EXPAND_SZ
)
160 WCHAR path
[MAX_PATH
];
161 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
165 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
168 name
= HeapAlloc(GetProcessHeap(), 0, size
);
169 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
170 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
172 HeapFree(GetProcessHeap(), 0, name
);
178 HMODULE hLib
= LoadLibraryW(providerPath
);
182 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
184 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
186 TRACE("loaded lib %p\n", hLib
);
190 PWNetProvider provider
=
191 &providerTable
->table
[providerTable
->numProviders
];
193 provider
->hLib
= hLib
;
194 provider
->name
= name
;
195 TRACE("name is %s\n", debugstr_w(name
));
196 provider
->getCaps
= getCaps
;
197 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
198 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
199 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
200 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
201 if (provider
->dwEnumScopes
)
203 TRACE("supports enumeration\n");
204 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
205 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
206 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
207 TRACE("NPEnumResource %p\n", provider
->enumResource
);
208 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
209 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
210 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
211 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
212 if (!provider
->openEnum
||
213 !provider
->enumResource
||
214 !provider
->closeEnum
)
216 provider
->openEnum
= NULL
;
217 provider
->enumResource
= NULL
;
218 provider
->closeEnum
= NULL
;
219 provider
->dwEnumScopes
= 0;
220 WARN("Couldn't load enumeration functions\n");
223 connectCap
= getCaps(WNNC_CONNECTION
);
224 if (connectCap
& WNNC_CON_ADDCONNECTION
)
225 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
226 if (connectCap
& WNNC_CON_ADDCONNECTION3
)
227 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
228 if (connectCap
& WNNC_CON_CANCELCONNECTION
)
229 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
231 if (connectCap
& WNNC_CON_GETCONNECTIONS
)
232 provider
->getConnection
= MPR_GETPROC(NPGetConnection
);
234 TRACE("NPAddConnection %p\n", provider
->addConnection
);
235 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
236 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
237 providerTable
->numProviders
++;
241 WARN("Provider %s didn't export NPGetCaps\n",
242 debugstr_w(provider
));
243 HeapFree(GetProcessHeap(), 0, name
);
251 WARN("Couldn't load library %s for provider %s\n",
252 debugstr_w(providerPath
), debugstr_w(provider
));
253 HeapFree(GetProcessHeap(), 0, name
);
258 WARN("Couldn't get provider name for provider %s\n",
259 debugstr_w(provider
));
263 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
267 WARN("Couldn't open service key for provider %s\n",
268 debugstr_w(provider
));
271 void wnetInit(HINSTANCE hInstDll
)
273 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
274 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
275 'C','o','n','t','r','o','l','\\',
276 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
277 'O','r','d','e','r',0 };
278 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
279 'O','r','d','e','r',0 };
282 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
287 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
290 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
296 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
297 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
302 TRACE("provider order is %s\n", debugstr_w(providers
));
303 /* first count commas as a heuristic for how many to
304 * allocate space for */
305 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
307 ptr
= strchrW(ptr
, ',');
314 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
315 sizeof(WNetProviderTable
)
316 + (numToAllocate
- 1) * sizeof(WNetProvider
));
320 int entireNetworkLen
;
321 LPCWSTR stringresource
;
323 entireNetworkLen
= LoadStringW(hInstDll
,
324 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
325 providerTable
->entireNetwork
= HeapAlloc(
326 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
328 if (providerTable
->entireNetwork
)
330 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
331 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
333 providerTable
->numAllocated
= numToAllocate
;
334 for (ptr
= providers
; ptr
; )
337 ptr
= strchrW(ptr
, ',');
340 _tryLoadProvider(ptrPrev
);
344 HeapFree(GetProcessHeap(), 0, providers
);
357 for (i
= 0; i
< providerTable
->numProviders
; i
++)
359 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
360 FreeModule(providerTable
->table
[i
].hLib
);
362 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
363 HeapFree(GetProcessHeap(), 0, providerTable
);
364 providerTable
= NULL
;
368 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
370 DWORD ret
= BAD_PROVIDER_INDEX
;
372 if (providerTable
&& providerTable
->numProviders
)
376 for (i
= 0; i
< providerTable
->numProviders
&&
377 ret
== BAD_PROVIDER_INDEX
; i
++)
378 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
388 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
394 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
400 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
401 if (lpNet
->lpRemoteName
)
403 len
= strlenW(lpNet
->lpRemoteName
) + 1;
404 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
405 if (ret
->lpRemoteName
)
406 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
415 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
419 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
420 HeapFree(GetProcessHeap(), 0, lpNet
);
424 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
425 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
427 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
428 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
432 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
433 ret
->dwScope
= dwScope
;
434 ret
->dwType
= dwType
;
435 ret
->dwUsage
= dwUsage
;
436 ret
->specific
.net
= _copyNetResourceForEnumW(lpNet
);
441 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
442 DWORD dwUsage
, DWORD index
, HANDLE handle
)
446 if (!providerTable
|| index
>= providerTable
->numProviders
)
450 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
453 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
454 ret
->providerIndex
= index
;
455 ret
->dwScope
= dwScope
;
456 ret
->dwType
= dwType
;
457 ret
->dwUsage
= dwUsage
;
458 ret
->handle
= handle
;
464 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
467 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
468 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
472 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
473 ret
->dwScope
= dwScope
;
474 ret
->dwType
= dwType
;
475 ret
->dwUsage
= dwUsage
;
480 static PWNetEnumerator
_createConnectedEnumerator(DWORD dwScope
, DWORD dwType
,
483 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
486 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONNECTED
;
487 ret
->dwScope
= dwScope
;
488 ret
->dwType
= dwType
;
489 ret
->dwUsage
= dwUsage
;
490 ret
->specific
.handles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HANDLE
) * providerTable
->numProviders
);
491 if (!ret
->specific
.handles
)
493 HeapFree(GetProcessHeap(), 0, ret
);
500 static PWNetEnumerator
_createRememberedEnumerator(DWORD dwScope
, DWORD dwType
,
503 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
506 ret
->enumType
= WNET_ENUMERATOR_TYPE_REMEMBERED
;
507 ret
->dwScope
= dwScope
;
508 ret
->dwType
= dwType
;
509 ret
->specific
.remembered
.registry
= remembered
;
514 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
515 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
516 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
517 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
518 * if not all members of the array could be thunked, and something else on
521 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
522 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
524 DWORD i
, numToThunk
, totalBytes
, ret
;
528 return WN_BAD_POINTER
;
530 return WN_BAD_POINTER
;
534 return WN_BAD_POINTER
;
536 return WN_BAD_POINTER
;
538 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
540 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
542 totalBytes
+= sizeof(NETRESOURCEA
);
543 if (lpNet
->lpLocalName
)
544 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
545 -1, NULL
, 0, NULL
, NULL
);
546 if (lpNet
->lpRemoteName
)
547 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
548 -1, NULL
, 0, NULL
, NULL
);
549 if (lpNet
->lpComment
)
550 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
551 -1, NULL
, 0, NULL
, NULL
);
552 if (lpNet
->lpProvider
)
553 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
554 -1, NULL
, 0, NULL
, NULL
);
555 if (totalBytes
< *lpBufferSize
)
558 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
559 for (i
= 0; i
< numToThunk
; i
++)
561 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
562 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
564 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
565 /* lie about string lengths, we already verified how many
566 * we have space for above
568 if (lpNetIn
->lpLocalName
)
570 lpNetOut
->lpLocalName
= strNext
;
571 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
572 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
574 if (lpNetIn
->lpRemoteName
)
576 lpNetOut
->lpRemoteName
= strNext
;
577 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
578 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
580 if (lpNetIn
->lpComment
)
582 lpNetOut
->lpComment
= strNext
;
583 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
584 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
586 if (lpNetIn
->lpProvider
)
588 lpNetOut
->lpProvider
= strNext
;
589 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
590 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
593 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
594 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
599 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
600 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
601 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
602 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
603 * if not all members of the array could be thunked, and something else on
606 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
607 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
609 DWORD i
, numToThunk
, totalBytes
, ret
;
613 return WN_BAD_POINTER
;
615 return WN_BAD_POINTER
;
619 return WN_BAD_POINTER
;
621 return WN_BAD_POINTER
;
623 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
625 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
627 totalBytes
+= sizeof(NETRESOURCEW
);
628 if (lpNet
->lpLocalName
)
629 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
630 -1, NULL
, 0) * sizeof(WCHAR
);
631 if (lpNet
->lpRemoteName
)
632 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
633 -1, NULL
, 0) * sizeof(WCHAR
);
634 if (lpNet
->lpComment
)
635 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
636 -1, NULL
, 0) * sizeof(WCHAR
);
637 if (lpNet
->lpProvider
)
638 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
639 -1, NULL
, 0) * sizeof(WCHAR
);
640 if (totalBytes
< *lpBufferSize
)
643 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
644 for (i
= 0; i
< numToThunk
; i
++)
646 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
647 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
649 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
650 /* lie about string lengths, we already verified how many
651 * we have space for above
653 if (lpNetIn
->lpLocalName
)
655 lpNetOut
->lpLocalName
= strNext
;
656 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
657 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
659 if (lpNetIn
->lpRemoteName
)
661 lpNetOut
->lpRemoteName
= strNext
;
662 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
663 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
665 if (lpNetIn
->lpComment
)
667 lpNetOut
->lpComment
= strNext
;
668 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
669 -1, lpNetOut
->lpComment
, *lpBufferSize
);
671 if (lpNetIn
->lpProvider
)
673 lpNetOut
->lpProvider
= strNext
;
674 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
675 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
678 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
679 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
684 /*********************************************************************
685 * WNetOpenEnumA [MPR.@]
687 * See comments for WNetOpenEnumW.
689 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
690 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
694 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
695 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
698 ret
= WN_BAD_POINTER
;
699 else if (!providerTable
|| providerTable
->numProviders
== 0)
708 LPNETRESOURCEW lpNetWide
= NULL
;
710 DWORD size
= sizeof(buf
), count
= 1;
711 BOOL allocated
= FALSE
;
713 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
714 if (ret
== WN_MORE_DATA
)
716 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
720 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
725 ret
= WN_OUT_OF_MEMORY
;
727 else if (ret
== WN_SUCCESS
)
728 lpNetWide
= (LPNETRESOURCEW
)buf
;
729 if (ret
== WN_SUCCESS
)
730 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
733 HeapFree(GetProcessHeap(), 0, lpNetWide
);
736 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
740 TRACE("Returning %d\n", ret
);
744 /*********************************************************************
745 * WNetOpenEnumW [MPR.@]
747 * Network enumeration has way too many parameters, so I'm not positive I got
748 * them right. What I've got so far:
750 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
751 * all the network providers should be enumerated.
753 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
754 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
755 * lpProvider is set, all the network providers should be enumerated.
756 * (This means the enumeration is a list of network providers, not that the
757 * enumeration is passed on to the providers.)
759 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
760 * resource matches the "Entire Network" resource (no remote name, no
761 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
762 * enumeration is done on every network provider.
764 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
765 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
766 * only to the given network provider.
768 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
769 * no lpProvider is set, enumeration will be tried on every network provider,
770 * in the order in which they're loaded.
772 * - The LPNETRESOURCE should be disregarded for scopes besides
773 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
774 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
776 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
777 * resource in the enumerated list, as well as any machines in your
778 * workgroup. The machines in your workgroup come from doing a
779 * RESOURCE_CONTEXT enumeration of every Network Provider.
781 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
782 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
786 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
787 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
790 ret
= WN_BAD_POINTER
;
791 else if (!providerTable
|| providerTable
->numProviders
== 0)
800 case RESOURCE_GLOBALNET
:
803 if (lpNet
->lpProvider
)
805 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
807 if (index
!= BAD_PROVIDER_INDEX
)
809 if (providerTable
->table
[index
].openEnum
&&
810 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
813 PWSTR RemoteName
= lpNet
->lpRemoteName
;
815 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
816 RemoteName
&& !strcmpW(RemoteName
, lpNet
->lpProvider
))
817 lpNet
->lpRemoteName
= NULL
;
819 ret
= providerTable
->table
[index
].openEnum(
820 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
821 if (ret
== WN_SUCCESS
)
823 *lphEnum
= _createProviderEnumerator(
824 dwScope
, dwType
, dwUsage
, index
, handle
);
825 ret
= *lphEnum
? WN_SUCCESS
:
829 lpNet
->lpRemoteName
= RemoteName
;
832 ret
= WN_NOT_SUPPORTED
;
835 ret
= WN_BAD_PROVIDER
;
837 else if (lpNet
->lpRemoteName
)
839 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
840 dwType
, dwUsage
, lpNet
);
841 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
845 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
846 providerTable
->entireNetwork
))
848 /* comment matches the "Entire Network", enumerate
849 * global scope of every provider
851 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
852 dwType
, dwUsage
, lpNet
);
856 /* this is the same as not having passed lpNet */
857 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
858 dwType
, dwUsage
, NULL
);
860 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
865 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
867 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
870 case RESOURCE_CONTEXT
:
871 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
872 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
874 case RESOURCE_CONNECTED
:
875 *lphEnum
= _createConnectedEnumerator(dwScope
, dwType
, dwUsage
);
876 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
878 case RESOURCE_REMEMBERED
:
880 HKEY remembered
, user_profile
;
882 ret
= WN_OUT_OF_MEMORY
;
883 if (RegOpenCurrentUser(KEY_READ
, &user_profile
) == ERROR_SUCCESS
)
885 WCHAR subkey
[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
887 if (RegOpenKeyExW(user_profile
, subkey
, 0, KEY_READ
, &remembered
) == ERROR_SUCCESS
)
889 *lphEnum
= _createRememberedEnumerator(dwScope
, dwType
, remembered
);
890 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
893 RegCloseKey(user_profile
);
898 WARN("unknown scope 0x%08x\n", dwScope
);
904 TRACE("Returning %d\n", ret
);
908 /*********************************************************************
909 * WNetEnumResourceA [MPR.@]
911 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
912 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
916 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
919 ret
= WN_BAD_POINTER
;
921 ret
= WN_BAD_POINTER
;
923 ret
= WN_BAD_POINTER
;
924 else if (!lpBufferSize
)
925 ret
= WN_BAD_POINTER
;
926 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
928 *lpBufferSize
= sizeof(NETRESOURCEA
);
933 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
934 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
938 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
940 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
942 /* FIXME: this isn't necessarily going to work in the case of
943 * WN_MORE_DATA, because our enumerator may have moved on to
944 * the next provider. MSDN states that a large (16KB) buffer
945 * size is the appropriate usage of this function, so
946 * hopefully it won't be an issue.
948 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
949 lpBuffer
, lpBufferSize
);
950 *lpcCount
= localCount
;
952 HeapFree(GetProcessHeap(), 0, localBuffer
);
955 ret
= WN_OUT_OF_MEMORY
;
959 TRACE("Returning %d\n", ret
);
963 static DWORD
_countProviderBytesW(PWNetProvider provider
)
969 ret
= sizeof(NETRESOURCEW
);
970 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
977 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
978 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
983 return WN_BAD_POINTER
;
984 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
987 return WN_BAD_POINTER
;
989 return WN_BAD_POINTER
;
991 return WN_BAD_POINTER
;
992 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
995 if (!providerTable
|| enumerator
->providerIndex
>=
996 providerTable
->numProviders
)
997 ret
= WN_NO_MORE_ENTRIES
;
1000 DWORD bytes
= 0, count
= 0, countLimit
, i
;
1001 LPNETRESOURCEW resource
;
1004 countLimit
= *lpcCount
== -1 ?
1005 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
1006 while (count
< countLimit
&& bytes
< *lpBufferSize
)
1008 DWORD bytesNext
= _countProviderBytesW(
1009 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
1011 if (bytes
+ bytesNext
< *lpBufferSize
)
1017 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
1018 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
1020 resource
->dwScope
= RESOURCE_GLOBALNET
;
1021 resource
->dwType
= RESOURCETYPE_ANY
;
1022 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
1023 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
1024 RESOURCEUSAGE_RESERVED
;
1025 resource
->lpLocalName
= NULL
;
1026 resource
->lpRemoteName
= strNext
;
1027 strcpyW(resource
->lpRemoteName
,
1028 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1029 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
1030 resource
->lpComment
= NULL
;
1031 resource
->lpProvider
= strNext
;
1032 strcpyW(resource
->lpProvider
,
1033 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1034 strNext
+= strlenW(resource
->lpProvider
) + 1;
1036 enumerator
->providerIndex
+= count
;
1038 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
1040 TRACE("Returning %d\n", ret
);
1044 /* Advances the enumerator (assumed to be a global enumerator) to the next
1045 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1046 * not open a handle with the next provider.
1047 * If the existing handle is NULL, may leave the enumerator unchanged, since
1048 * the current provider may support the desired scope.
1049 * If the existing handle is not NULL, closes it before moving on.
1050 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1051 * provider, and another error on failure.
1053 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
1056 return WN_BAD_POINTER
;
1057 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1058 return WN_BAD_VALUE
;
1059 if (!providerTable
|| enumerator
->providerIndex
>=
1060 providerTable
->numProviders
)
1061 return WN_NO_MORE_ENTRIES
;
1063 if (enumerator
->providerDone
)
1066 enumerator
->providerDone
= FALSE
;
1067 if (enumerator
->handle
)
1069 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1070 enumerator
->handle
);
1071 enumerator
->handle
= NULL
;
1072 enumerator
->providerIndex
++;
1074 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1075 dwEnum
= WNNC_ENUM_LOCAL
;
1076 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1077 dwEnum
= WNNC_ENUM_GLOBAL
;
1078 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1079 dwEnum
= WNNC_ENUM_CONTEXT
;
1080 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1081 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1082 & dwEnum
); enumerator
->providerIndex
++)
1085 return enumerator
->providerIndex
< providerTable
->numProviders
?
1086 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1089 /* "Passes through" call to the next provider that supports the enumeration
1091 * FIXME: if one call to a provider's enumerator succeeds while there's still
1092 * space in lpBuffer, I don't call to the next provider. The caller may not
1093 * expect that it should call EnumResourceW again with a return value of
1094 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1095 * may have to be moved around a bit, ick.
1097 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1098 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1103 return WN_BAD_POINTER
;
1104 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1105 return WN_BAD_VALUE
;
1107 return WN_BAD_POINTER
;
1109 return WN_BAD_POINTER
;
1111 return WN_BAD_POINTER
;
1112 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1113 return WN_MORE_DATA
;
1115 ret
= _globalEnumeratorAdvance(enumerator
);
1116 if (ret
== WN_SUCCESS
)
1118 ret
= providerTable
->table
[enumerator
->providerIndex
].
1119 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1120 enumerator
->dwUsage
, enumerator
->specific
.net
,
1121 &enumerator
->handle
);
1122 if (ret
== WN_SUCCESS
)
1124 ret
= providerTable
->table
[enumerator
->providerIndex
].
1125 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1127 if (ret
!= WN_MORE_DATA
)
1128 enumerator
->providerDone
= TRUE
;
1131 TRACE("Returning %d\n", ret
);
1135 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1136 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1141 return WN_BAD_POINTER
;
1142 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1143 return WN_BAD_VALUE
;
1145 return WN_BAD_POINTER
;
1147 return WN_BAD_POINTER
;
1149 return WN_BAD_POINTER
;
1150 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1151 return WN_MORE_DATA
;
1153 return WN_NO_NETWORK
;
1155 switch (enumerator
->dwScope
)
1157 case RESOURCE_GLOBALNET
:
1158 if (enumerator
->specific
.net
)
1159 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1160 lpBuffer
, lpBufferSize
);
1162 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1165 case RESOURCE_CONTEXT
:
1166 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1170 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1171 ret
= WN_NO_MORE_ENTRIES
;
1173 TRACE("Returning %d\n", ret
);
1177 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1178 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1181 return WN_BAD_POINTER
;
1182 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1183 return WN_BAD_VALUE
;
1184 if (!enumerator
->handle
)
1185 return WN_BAD_VALUE
;
1187 return WN_BAD_POINTER
;
1189 return WN_BAD_POINTER
;
1191 return WN_BAD_POINTER
;
1193 return WN_NO_NETWORK
;
1194 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1195 return WN_NO_MORE_ENTRIES
;
1196 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1197 return WN_BAD_VALUE
;
1198 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1199 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1202 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1203 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1206 size_t cchEntireNetworkLen
, bytesNeeded
;
1209 return WN_BAD_POINTER
;
1210 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1211 return WN_BAD_VALUE
;
1213 return WN_BAD_POINTER
;
1215 return WN_BAD_POINTER
;
1217 return WN_BAD_POINTER
;
1219 return WN_NO_NETWORK
;
1221 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1222 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1223 if (*lpBufferSize
< bytesNeeded
)
1225 *lpBufferSize
= bytesNeeded
;
1230 LPNETRESOURCEW lpNet
= lpBuffer
;
1232 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1233 lpNet
->dwType
= enumerator
->dwType
;
1234 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1235 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1236 lpNet
->lpLocalName
= NULL
;
1237 lpNet
->lpRemoteName
= NULL
;
1238 lpNet
->lpProvider
= NULL
;
1239 /* odd, but correct: put comment at end of buffer, so it won't get
1240 * overwritten by subsequent calls to a provider's enumResource
1242 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1243 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1244 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1247 if (ret
== WN_SUCCESS
)
1249 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1251 /* "Entire Network" entry enumerated--morph this into a global
1252 * enumerator. enumerator->lpNet continues to be NULL, since it has
1253 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1255 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1256 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1257 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1258 if (ret
== WN_SUCCESS
)
1260 /* reflect the fact that we already enumerated "Entire Network" */
1262 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1266 /* the provider enumeration failed, but we already succeeded in
1267 * enumerating "Entire Network"--leave type as global to allow a
1268 * retry, but indicate success with a count of one.
1272 *lpBufferSize
= bytesNeeded
;
1275 TRACE("Returning %d\n", ret
);
1279 static DWORD
_copyStringToEnumW(const WCHAR
*source
, DWORD
* left
, void** end
)
1282 WCHAR
* local
= *end
;
1284 len
= strlenW(source
) + 1;
1285 len
*= sizeof(WCHAR
);
1287 return WN_MORE_DATA
;
1289 local
-= (len
/ sizeof(WCHAR
));
1290 memcpy(local
, source
, len
);
1297 static DWORD
_enumerateConnectedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1298 void* user_buffer
, DWORD
* user_size
)
1300 DWORD ret
, index
, count
, total_count
, size
, i
, left
;
1302 NETRESOURCEW
* curr
, * buffer
;
1306 return WN_BAD_POINTER
;
1307 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONNECTED
)
1308 return WN_BAD_VALUE
;
1309 if (!user_count
|| !user_buffer
|| !user_size
)
1310 return WN_BAD_POINTER
;
1312 return WN_NO_NETWORK
;
1314 handles
= enumerator
->specific
.handles
;
1317 buffer
= HeapAlloc(GetProcessHeap(), 0, *user_size
);
1319 return WN_NO_NETWORK
;
1322 end
= (char *)user_buffer
+ size
;
1323 count
= *user_count
;
1326 ret
= WN_NO_MORE_ENTRIES
;
1327 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1329 if (providerTable
->table
[index
].dwEnumScopes
)
1331 if (handles
[index
] == 0)
1333 ret
= providerTable
->table
[index
].openEnum(enumerator
->dwScope
,
1335 enumerator
->dwUsage
,
1336 NULL
, &handles
[index
]);
1337 if (ret
!= WN_SUCCESS
)
1341 ret
= providerTable
->table
[index
].enumResource(handles
[index
],
1344 total_count
+= count
;
1345 if (ret
== WN_MORE_DATA
)
1348 if (ret
== WN_SUCCESS
)
1350 for (i
= 0; i
< count
; ++i
)
1352 if (left
< sizeof(NETRESOURCEW
))
1358 memcpy(curr
, &buffer
[i
], sizeof(NETRESOURCEW
));
1359 left
-= sizeof(NETRESOURCEW
);
1361 ret
= _copyStringToEnumW(buffer
[i
].lpLocalName
, &left
, &end
);
1362 if (ret
== WN_MORE_DATA
)
1364 curr
->lpLocalName
= end
;
1366 ret
= _copyStringToEnumW(buffer
[i
].lpRemoteName
, &left
, &end
);
1367 if (ret
== WN_MORE_DATA
)
1369 curr
->lpRemoteName
= end
;
1371 ret
= _copyStringToEnumW(buffer
[i
].lpProvider
, &left
, &end
);
1372 if (ret
== WN_MORE_DATA
)
1374 curr
->lpProvider
= end
;
1382 if (*user_count
!= -1)
1383 count
= *user_count
- total_count
;
1385 count
= *user_count
;
1389 if (total_count
== 0)
1390 ret
= WN_NO_MORE_ENTRIES
;
1392 *user_count
= total_count
;
1393 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1396 HeapFree(GetProcessHeap(), 0, buffer
);
1398 TRACE("Returning %d\n", ret
);
1402 static const WCHAR connectionType
[] = { 'C','o','n','n','e','c','t','i','o','n','T','y','p','e',0 };
1403 static const WCHAR providerName
[] = { 'P','r','o','v','i','d','e','r','N','a','m','e',0 };
1404 static const WCHAR remotePath
[] = { 'R','e','m','o','t','e','P','a','t','h',0 };
1406 static WCHAR
*get_reg_str(HKEY hkey
, const WCHAR
*value
, DWORD
*len
)
1411 if (!RegQueryValueExW(hkey
, value
, NULL
, &type
, NULL
, len
) && type
== REG_SZ
)
1413 if (!(ret
= HeapAlloc(GetProcessHeap(), 0, *len
))) return NULL
;
1414 RegQueryValueExW(hkey
, value
, 0, 0, (BYTE
*)ret
, len
);
1420 static DWORD
_enumeratorRememberedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1421 void* user_buffer
, DWORD
* user_size
)
1423 HKEY registry
, connection
;
1426 DWORD index
, ret
, type
, len
, size
, registry_size
, full_size
= 0, total_count
;
1427 NETRESOURCEW
* net_buffer
= user_buffer
;
1428 WCHAR
* str
, * registry_string
;
1430 /* we will do the work in a single loop, so here is some things:
1431 * we write netresource at the begin of the user buffer
1432 * we write strings at the end of the user buffer
1434 size_left
= *user_size
;
1436 type
= enumerator
->dwType
;
1437 registry
= enumerator
->specific
.remembered
.registry
;
1438 str
= (WCHAR
*)((ULONG_PTR
)user_buffer
+ *user_size
- sizeof(WCHAR
));
1439 for (index
= enumerator
->specific
.remembered
.index
; ; ++index
)
1441 enumerator
->specific
.remembered
.index
= index
;
1443 if (*user_count
!= -1 && total_count
== *user_count
)
1449 len
= ARRAY_SIZE(buffer
);
1450 ret
= RegEnumKeyExW(registry
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
);
1451 if (ret
!= ERROR_SUCCESS
)
1453 if (ret
== ERROR_NO_MORE_ITEMS
) ret
= WN_SUCCESS
;
1457 if (RegOpenKeyExW(registry
, buffer
, 0, KEY_READ
, &connection
) != ERROR_SUCCESS
)
1462 full_size
= sizeof(NETRESOURCEW
);
1463 size_left
-= sizeof(NETRESOURCEW
);
1467 size
= sizeof(DWORD
);
1468 RegQueryValueExW(connection
, connectionType
, NULL
, NULL
, (BYTE
*)&net_buffer
->dwType
, &size
);
1469 if (type
!= RESOURCETYPE_ANY
&& net_buffer
->dwType
!= type
)
1471 size_left
+= sizeof(NETRESOURCEW
);
1472 RegCloseKey(connection
);
1476 net_buffer
->dwScope
= RESOURCE_REMEMBERED
;
1477 net_buffer
->dwDisplayType
= RESOURCEDISPLAYTYPE_GENERIC
;
1478 net_buffer
->dwUsage
= RESOURCEUSAGE_CONNECTABLE
;
1483 /* FIXME: this only supports drive letters */
1484 full_size
+= 3 * sizeof(WCHAR
);
1485 size_left
-= 3 * sizeof(WCHAR
);
1492 net_buffer
->lpLocalName
= str
;
1496 registry_string
= get_reg_str(connection
, providerName
, ®istry_size
);
1497 if (registry_string
)
1499 full_size
+= registry_size
;
1500 size_left
-= registry_size
;
1504 str
-= (registry_size
/ sizeof(WCHAR
));
1505 lstrcpyW(str
, registry_string
);
1506 net_buffer
->lpProvider
= str
;
1511 HeapFree(GetProcessHeap(), 0, registry_string
);
1515 registry_string
= get_reg_str(connection
, remotePath
, ®istry_size
);
1516 if (registry_string
)
1518 full_size
+= registry_size
;
1519 size_left
-= registry_size
;
1523 str
-= (registry_size
/ sizeof(WCHAR
));
1524 lstrcpyW(str
, registry_string
);
1525 net_buffer
->lpRemoteName
= str
;
1530 HeapFree(GetProcessHeap(), 0, registry_string
);
1533 RegCloseKey(connection
);
1535 net_buffer
->lpComment
= NULL
;
1544 if (total_count
== 0)
1545 ret
= WN_NO_MORE_ENTRIES
;
1547 *user_count
= total_count
;
1549 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1552 if (ret
== WN_MORE_DATA
)
1553 *user_size
= *user_size
+ full_size
;
1558 /*********************************************************************
1559 * WNetEnumResourceW [MPR.@]
1561 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1562 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1566 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1569 ret
= WN_BAD_POINTER
;
1571 ret
= WN_BAD_POINTER
;
1573 ret
= WN_BAD_POINTER
;
1574 else if (!lpBufferSize
)
1575 ret
= WN_BAD_POINTER
;
1576 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1578 *lpBufferSize
= sizeof(NETRESOURCEW
);
1583 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1585 switch (enumerator
->enumType
)
1587 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1588 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1591 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1592 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1595 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1596 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1599 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1600 ret
= _enumerateConnectedW(enumerator
, lpcCount
, lpBuffer
,
1603 case WNET_ENUMERATOR_TYPE_REMEMBERED
:
1604 ret
= _enumeratorRememberedW(enumerator
, lpcCount
, lpBuffer
,
1608 WARN("bogus enumerator type!\n");
1609 ret
= WN_NO_NETWORK
;
1614 TRACE("Returning %d\n", ret
);
1618 /*********************************************************************
1619 * WNetCloseEnum [MPR.@]
1621 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1626 TRACE( "(%p)\n", hEnum
);
1630 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1632 switch (enumerator
->enumType
)
1634 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1635 if (enumerator
->specific
.net
)
1636 _freeEnumNetResource(enumerator
->specific
.net
);
1637 if (enumerator
->handle
)
1638 providerTable
->table
[enumerator
->providerIndex
].
1639 closeEnum(enumerator
->handle
);
1642 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1643 if (enumerator
->handle
)
1644 providerTable
->table
[enumerator
->providerIndex
].
1645 closeEnum(enumerator
->handle
);
1648 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1649 handles
= enumerator
->specific
.handles
;
1650 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1652 if (providerTable
->table
[index
].dwEnumScopes
&& handles
[index
])
1653 providerTable
->table
[index
].closeEnum(handles
[index
]);
1655 HeapFree(GetProcessHeap(), 0, handles
);
1658 case WNET_ENUMERATOR_TYPE_REMEMBERED
:
1659 RegCloseKey(enumerator
->specific
.remembered
.registry
);
1663 WARN("bogus enumerator type!\n");
1664 ret
= WN_BAD_HANDLE
;
1666 HeapFree(GetProcessHeap(), 0, hEnum
);
1669 ret
= WN_BAD_HANDLE
;
1672 TRACE("Returning %d\n", ret
);
1676 /*********************************************************************
1677 * WNetGetResourceInformationA [MPR.@]
1679 * See WNetGetResourceInformationW
1681 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1682 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1687 TRACE( "(%p, %p, %p, %p)\n",
1688 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1690 if (!providerTable
|| providerTable
->numProviders
== 0)
1691 ret
= WN_NO_NETWORK
;
1692 else if (lpNetResource
)
1694 LPNETRESOURCEW lpNetResourceW
= NULL
;
1695 DWORD size
= 1024, count
= 1;
1698 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1699 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1700 if (ret
== WN_MORE_DATA
)
1702 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1703 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1705 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1706 &count
, lpNetResourceW
, &size
);
1708 ret
= WN_OUT_OF_MEMORY
;
1710 if (ret
== WN_SUCCESS
)
1712 LPWSTR lpSystemW
= NULL
;
1715 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1718 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1719 lpBufferW
, &size
, &lpSystemW
);
1720 if (ret
== WN_MORE_DATA
)
1722 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1723 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1725 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1726 lpBufferW
, &size
, &lpSystemW
);
1728 ret
= WN_OUT_OF_MEMORY
;
1730 if (ret
== WN_SUCCESS
)
1732 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1733 &count
, lpBuffer
, cbBuffer
);
1734 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1735 lpNetResourceW
= lpBufferW
;
1736 size
= sizeof(NETRESOURCEA
);
1737 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1738 -1, NULL
, 0, NULL
, NULL
);
1739 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1740 -1, NULL
, 0, NULL
, NULL
);
1742 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1743 -1, NULL
, 0, NULL
, NULL
);
1744 if ((len
) && ( size
+ len
< *cbBuffer
))
1746 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1747 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1748 *lplpSystem
, len
, NULL
, NULL
);
1755 ret
= WN_OUT_OF_MEMORY
;
1756 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1759 ret
= WN_OUT_OF_MEMORY
;
1760 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1762 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1765 ret
= WN_NO_NETWORK
;
1769 TRACE("Returning %d\n", ret
);
1773 /*********************************************************************
1774 * WNetGetResourceInformationW [MPR.@]
1776 * WNetGetResourceInformationW function identifies the network provider
1777 * that owns the resource and gets information about the type of the resource.
1780 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1781 * defines a network resource.
1782 * lpBuffer [ O] the pointer to buffer, containing result. It
1783 * contains NETRESOURCEW structure and strings to
1784 * which the members of the NETRESOURCEW structure
1786 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1788 * lplpSystem [ O] the pointer to string in the output buffer,
1789 * containing the part of the resource name without
1790 * names of the server and share.
1793 * NO_ERROR if the function succeeds. System error code if the function fails.
1796 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1797 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1798 LPWSTR
*lplpSystem
)
1800 DWORD ret
= WN_NO_NETWORK
;
1803 TRACE( "(%p, %p, %p, %p)\n",
1804 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1807 ret
= WN_OUT_OF_MEMORY
;
1808 else if (providerTable
!= NULL
)
1810 /* FIXME: For function value of a variable is indifferent, it does
1811 * search of all providers in a network.
1813 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1815 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1816 WNNC_DLG_GETRESOURCEINFORMATION
)
1818 if (providerTable
->table
[index
].getResourceInformation
)
1819 ret
= providerTable
->table
[index
].getResourceInformation(
1820 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1822 ret
= WN_NO_NETWORK
;
1823 if (ret
== WN_SUCCESS
)
1833 /*********************************************************************
1834 * WNetGetResourceParentA [MPR.@]
1836 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1837 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1839 FIXME( "(%p, %p, %p): stub\n",
1840 lpNetResource
, lpBuffer
, lpBufferSize
);
1842 SetLastError(WN_NO_NETWORK
);
1843 return WN_NO_NETWORK
;
1846 /*********************************************************************
1847 * WNetGetResourceParentW [MPR.@]
1849 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1850 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1852 FIXME( "(%p, %p, %p): stub\n",
1853 lpNetResource
, lpBuffer
, lpBufferSize
);
1855 SetLastError(WN_NO_NETWORK
);
1856 return WN_NO_NETWORK
;
1862 * Connection Functions
1865 /*********************************************************************
1866 * WNetAddConnectionA [MPR.@]
1868 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1869 LPCSTR lpLocalName
)
1871 NETRESOURCEA resourcesA
;
1873 memset(&resourcesA
, 0, sizeof(resourcesA
));
1874 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
1875 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
1876 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1879 /*********************************************************************
1880 * WNetAddConnectionW [MPR.@]
1882 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1883 LPCWSTR lpLocalName
)
1885 NETRESOURCEW resourcesW
;
1887 memset(&resourcesW
, 0, sizeof(resourcesW
));
1888 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
1889 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
1890 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1893 /*********************************************************************
1894 * WNetAddConnection2A [MPR.@]
1896 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1897 LPCSTR lpPassword
, LPCSTR lpUserID
,
1900 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1904 /*********************************************************************
1905 * WNetAddConnection2W [MPR.@]
1907 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1908 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1911 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1915 /*********************************************************************
1916 * WNetAddConnection3A [MPR.@]
1918 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1919 LPCSTR lpPassword
, LPCSTR lpUserID
,
1922 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1923 dwFlags
, NULL
, 0, NULL
);
1926 /*********************************************************************
1927 * WNetAddConnection3W [MPR.@]
1929 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1930 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1933 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1934 dwFlags
, NULL
, 0, NULL
);
1937 struct use_connection_context
1940 NETRESOURCEW
*resource
;
1941 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
1948 DWORD (*pre_set_accessname
)(struct use_connection_context
*, WCHAR
*);
1949 void (*set_accessname
)(struct use_connection_context
*, WCHAR
*);
1952 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1954 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1959 len
= strlenW(local_name
);
1961 len
= strlenW(ctxt
->resource
->lpRemoteName
);
1963 if (++len
> *ctxt
->buffer_size
)
1965 *ctxt
->buffer_size
= len
;
1966 return ERROR_MORE_DATA
;
1970 ctxt
->accessname
= NULL
;
1972 return ERROR_SUCCESS
;
1975 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1977 WCHAR
*accessname
= ctxt
->accessname
;
1980 strcpyW(accessname
, local_name
);
1982 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1985 strcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
1988 static DWORD
wnet_use_provider( struct use_connection_context
*ctxt
, NETRESOURCEW
* netres
, WNetProvider
*provider
, BOOLEAN redirect
)
1992 caps
= provider
->getCaps(WNNC_CONNECTION
);
1993 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
1994 return ERROR_BAD_PROVIDER
;
1996 ret
= WN_ACCESS_DENIED
;
1999 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
2000 ret
= provider
->addConnection3(ctxt
->hwndOwner
, netres
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
2001 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
2002 ret
= provider
->addConnection(netres
, ctxt
->password
, ctxt
->userid
);
2004 if (ret
== WN_ALREADY_CONNECTED
&& redirect
)
2005 netres
->lpLocalName
[0] -= 1;
2006 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& netres
->lpLocalName
[0] >= 'C');
2008 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
2009 ctxt
->set_accessname(ctxt
, netres
->lpLocalName
);
2014 static const WCHAR providerType
[] = { 'P','r','o','v','i','d','e','r','T','y','p','e',0 };
2015 static const WCHAR userName
[] = { 'U','s','e','r','N','a','m','e',0 };
2017 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
2019 WNetProvider
*provider
;
2020 DWORD index
, ret
= WN_NO_NETWORK
;
2021 BOOL redirect
= FALSE
;
2022 WCHAR letter
[3] = {'Z', ':', 0};
2023 NETRESOURCEW netres
;
2025 if (!providerTable
|| providerTable
->numProviders
== 0)
2026 return WN_NO_NETWORK
;
2028 if (!ctxt
->resource
)
2029 return ERROR_INVALID_PARAMETER
;
2030 netres
= *ctxt
->resource
;
2032 if (!netres
.lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
2034 if (netres
.dwType
!= RESOURCETYPE_DISK
&& netres
.dwType
!= RESOURCETYPE_PRINT
)
2035 return ERROR_BAD_DEV_TYPE
;
2037 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2039 FIXME("Local device selection is not implemented for printers.\n");
2040 return WN_NO_NETWORK
;
2044 netres
.lpLocalName
= letter
;
2047 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
2048 return ERROR_BAD_NET_NAME
;
2050 if ((ret
= ctxt
->pre_set_accessname(ctxt
, netres
.lpLocalName
)))
2053 if (netres
.lpProvider
)
2055 index
= _findProviderIndexW(netres
.lpProvider
);
2056 if (index
== BAD_PROVIDER_INDEX
)
2057 return ERROR_BAD_PROVIDER
;
2059 provider
= &providerTable
->table
[index
];
2060 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2064 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2066 provider
= &providerTable
->table
[index
];
2067 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2068 if (ret
== WN_SUCCESS
|| ret
== WN_ALREADY_CONNECTED
)
2073 if (ret
== WN_SUCCESS
&& ctxt
->flags
& CONNECT_UPDATE_PROFILE
)
2077 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2079 FIXME("Persistent connection are not supported for printers\n");
2083 if (RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2086 WCHAR subkey
[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres
.lpLocalName
[0], 0};
2088 if (RegCreateKeyExW(user_profile
, subkey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2089 KEY_ALL_ACCESS
, NULL
, &network
, NULL
) == ERROR_SUCCESS
)
2091 DWORD dword_arg
= RESOURCETYPE_DISK
;
2092 DWORD len
= (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
2093 static const WCHAR empty
[1] = {0};
2095 RegSetValueExW(network
, connectionType
, 0, REG_DWORD
, (const BYTE
*)&dword_arg
, sizeof(DWORD
));
2096 RegSetValueExW(network
, providerName
, 0, REG_SZ
, (const BYTE
*)provider
->name
, len
);
2097 RegSetValueExW(network
, providerType
, 0, REG_DWORD
, (const BYTE
*)&provider
->dwNetType
, sizeof(DWORD
));
2098 len
= (strlenW(netres
.lpRemoteName
) + 1) * sizeof(WCHAR
);
2099 RegSetValueExW(network
, remotePath
, 0, REG_SZ
, (const BYTE
*)netres
.lpRemoteName
, len
);
2100 len
= sizeof(empty
);
2101 RegSetValueExW(network
, userName
, 0, REG_SZ
, (const BYTE
*)empty
, len
);
2102 RegCloseKey(network
);
2105 RegCloseKey(user_profile
);
2112 /*****************************************************************
2113 * WNetUseConnectionW [MPR.@]
2115 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
2116 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
2118 struct use_connection_context ctxt
;
2120 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
2121 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
2122 accessname
, buffer_size
, result
);
2124 ctxt
.hwndOwner
= hwndOwner
;
2125 ctxt
.resource
= resource
;
2126 ctxt
.resourceA
= NULL
;
2127 ctxt
.password
= (WCHAR
*)password
;
2128 ctxt
.userid
= (WCHAR
*)userid
;
2130 ctxt
.accessname
= accessname
;
2131 ctxt
.buffer_size
= buffer_size
;
2132 ctxt
.result
= result
;
2133 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
2134 ctxt
.set_accessname
= use_connection_set_accessnameW
;
2136 return wnet_use_connection(&ctxt
);
2139 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2141 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
2146 len
= WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, NULL
, 0, NULL
, NULL
) - 1;
2148 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
2150 if (++len
> *ctxt
->buffer_size
)
2152 *ctxt
->buffer_size
= len
;
2153 return ERROR_MORE_DATA
;
2157 ctxt
->accessname
= NULL
;
2159 return ERROR_SUCCESS
;
2162 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2164 char *accessname
= ctxt
->accessname
;
2167 WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, accessname
, *ctxt
->buffer_size
, NULL
, NULL
);
2169 *ctxt
->result
= CONNECT_LOCALDRIVE
;
2172 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
2175 static LPWSTR
strdupAtoW( LPCSTR str
)
2180 if (!str
) return NULL
;
2181 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
2182 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2183 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
2187 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
2189 resourceW
->dwScope
= resourceA
->dwScope
;
2190 resourceW
->dwType
= resourceA
->dwType
;
2191 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
2192 resourceW
->dwUsage
= resourceA
->dwUsage
;
2193 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
2194 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
2195 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
2196 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
2199 static void free_netresourceW( NETRESOURCEW
*resource
)
2201 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
2202 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
2203 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
2204 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
2207 /*****************************************************************
2208 * WNetUseConnectionA [MPR.@]
2210 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
2211 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
2212 DWORD
*buffer_size
, DWORD
*result
)
2214 struct use_connection_context ctxt
;
2215 NETRESOURCEW resourceW
;
2218 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
2219 accessname
, buffer_size
, result
);
2221 netresource_a_to_w(resource
, &resourceW
);
2223 ctxt
.hwndOwner
= hwndOwner
;
2224 ctxt
.resource
= &resourceW
;
2225 ctxt
.resourceA
= resource
;
2226 ctxt
.password
= strdupAtoW(password
);
2227 ctxt
.userid
= strdupAtoW(userid
);
2229 ctxt
.accessname
= accessname
;
2230 ctxt
.buffer_size
= buffer_size
;
2231 ctxt
.result
= result
;
2232 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
2233 ctxt
.set_accessname
= use_connection_set_accessnameA
;
2235 ret
= wnet_use_connection(&ctxt
);
2237 free_netresourceW(&resourceW
);
2238 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
2239 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
2244 /*********************************************************************
2245 * WNetCancelConnectionA [MPR.@]
2247 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
2249 return WNetCancelConnection2A(lpName
, 0, fForce
);
2252 /*********************************************************************
2253 * WNetCancelConnectionW [MPR.@]
2255 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
2257 return WNetCancelConnection2W(lpName
, 0, fForce
);
2260 /*********************************************************************
2261 * WNetCancelConnection2A [MPR.@]
2263 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2266 WCHAR
* name
= strdupAtoW(lpName
);
2268 return ERROR_NOT_CONNECTED
;
2270 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
2271 HeapFree(GetProcessHeap(), 0, name
);
2276 /*********************************************************************
2277 * WNetCancelConnection2W [MPR.@]
2279 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2281 DWORD ret
= WN_NO_NETWORK
;
2284 if (providerTable
!= NULL
)
2286 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2288 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2289 WNNC_CON_CANCELCONNECTION
)
2291 if (providerTable
->table
[index
].cancelConnection
)
2292 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
2294 ret
= WN_NO_NETWORK
;
2295 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
2301 if (ret
== WN_SUCCESS
&& dwFlags
& CONNECT_UPDATE_PROFILE
)
2305 /* FIXME: Only remove it if that's a drive letter */
2306 if (isalphaW(lpName
[0]) && lpName
[1] == ':' &&
2307 RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2309 WCHAR subkey
[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', lpName
[0], 0};
2311 RegDeleteKeyW(user_profile
, subkey
);
2313 RegCloseKey(user_profile
);
2320 /*****************************************************************
2321 * WNetRestoreConnectionA [MPR.@]
2323 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
2325 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
2327 SetLastError(WN_NO_NETWORK
);
2328 return WN_NO_NETWORK
;
2331 /*****************************************************************
2332 * WNetRestoreConnectionW [MPR.@]
2334 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
2336 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
2338 SetLastError(WN_NO_NETWORK
);
2339 return WN_NO_NETWORK
;
2342 /**************************************************************************
2343 * WNetGetConnectionA [MPR.@]
2346 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2347 * - WN_NOT_CONNECTED drive is a local drive
2348 * - WN_MORE_DATA buffer isn't big enough
2349 * - WN_SUCCESS success (net path in buffer)
2351 * FIXME: need to test return values under different errors
2353 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
2354 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
2359 ret
= WN_BAD_POINTER
;
2360 else if (!lpBufferSize
)
2361 ret
= WN_BAD_POINTER
;
2362 else if (!lpRemoteName
&& *lpBufferSize
)
2363 ret
= WN_BAD_POINTER
;
2366 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
2370 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2374 WCHAR wideRemoteStatic
[MAX_PATH
];
2375 DWORD wideRemoteSize
= ARRAY_SIZE(wideRemoteStatic
);
2377 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
2379 /* try once without memory allocation */
2380 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
2382 if (ret
== WN_SUCCESS
)
2384 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2385 -1, NULL
, 0, NULL
, NULL
);
2387 if (len
<= *lpBufferSize
)
2389 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
2390 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2395 *lpBufferSize
= len
;
2399 else if (ret
== WN_MORE_DATA
)
2401 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2402 wideRemoteSize
* sizeof(WCHAR
));
2406 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2408 if (ret
== WN_SUCCESS
)
2410 if (len
<= *lpBufferSize
)
2412 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2413 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2418 *lpBufferSize
= len
;
2422 HeapFree(GetProcessHeap(), 0, wideRemote
);
2425 ret
= WN_OUT_OF_MEMORY
;
2427 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2430 ret
= WN_OUT_OF_MEMORY
;
2433 ret
= WN_BAD_LOCALNAME
;
2437 TRACE("Returning %d\n", ret
);
2441 /* find the network connection for a given drive; helper for WNetGetConnection */
2442 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2446 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2448 DWORD ret
= WN_NOT_CONNECTED
;
2449 DWORD bytes_returned
;
2451 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2452 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2453 0, 0 )) == INVALID_HANDLE_VALUE
)
2455 ERR( "failed to open mount manager err %u\n", GetLastError() );
2458 memset( data
, 0, sizeof(*data
) );
2459 data
->letter
= letter
;
2460 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2461 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2463 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2466 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2469 mount_point
[0] = '\\';
2470 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2472 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2480 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2488 DWORD ret
= WN_NO_NETWORK
;
2490 WCHAR local
[3] = {letter
, ':', 0};
2492 if (providerTable
!= NULL
)
2494 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2496 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2497 WNNC_CON_GETCONNECTIONS
)
2499 if (providerTable
->table
[index
].getConnection
)
2500 ret
= providerTable
->table
[index
].getConnection(
2501 local
, remote
, size
);
2503 ret
= WN_NO_NETWORK
;
2504 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2515 /**************************************************************************
2516 * WNetGetConnectionW [MPR.@]
2518 * FIXME: need to test return values under different errors
2520 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2521 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2525 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2529 ret
= WN_BAD_POINTER
;
2530 else if (!lpBufferSize
)
2531 ret
= WN_BAD_POINTER
;
2532 else if (!lpRemoteName
&& *lpBufferSize
)
2533 ret
= WN_BAD_POINTER
;
2534 else if (!lpLocalName
[0])
2535 ret
= WN_BAD_LOCALNAME
;
2538 if (lpLocalName
[1] == ':')
2540 switch(GetDriveTypeW(lpLocalName
))
2543 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2545 case DRIVE_REMOVABLE
:
2548 TRACE("file is local\n");
2549 ret
= WN_NOT_CONNECTED
;
2552 ret
= WN_BAD_LOCALNAME
;
2556 ret
= WN_BAD_LOCALNAME
;
2560 TRACE("Returning %d\n", ret
);
2564 /**************************************************************************
2565 * WNetSetConnectionA [MPR.@]
2567 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2570 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2572 SetLastError(WN_NO_NETWORK
);
2573 return WN_NO_NETWORK
;
2576 /**************************************************************************
2577 * WNetSetConnectionW [MPR.@]
2579 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2582 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2584 SetLastError(WN_NO_NETWORK
);
2585 return WN_NO_NETWORK
;
2588 /*****************************************************************
2589 * WNetGetUniversalNameA [MPR.@]
2591 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2592 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2596 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2597 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2599 switch (dwInfoLevel
)
2601 case UNIVERSAL_NAME_INFO_LEVEL
:
2603 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2605 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2607 err
= ERROR_NOT_CONNECTED
;
2611 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2612 if (*lpBufferSize
< size
)
2617 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2618 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2622 case REMOTE_NAME_INFO_LEVEL
:
2623 err
= WN_NOT_CONNECTED
;
2635 /*****************************************************************
2636 * WNetGetUniversalNameW [MPR.@]
2638 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2639 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2643 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2644 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2646 switch (dwInfoLevel
)
2648 case UNIVERSAL_NAME_INFO_LEVEL
:
2650 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2652 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2654 err
= ERROR_NOT_CONNECTED
;
2658 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2659 if (*lpBufferSize
< size
)
2661 *lpBufferSize
= size
;
2665 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2666 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2670 case REMOTE_NAME_INFO_LEVEL
:
2671 err
= WN_NO_NETWORK
;
2679 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2683 /*****************************************************************
2684 * WNetClearConnections [MPR.@]
2686 DWORD WINAPI
WNetClearConnections ( HWND owner
)
2690 DWORD ret
, size
, count
;
2691 NETRESOURCEW
* resources
, * iter
;
2693 ret
= WNetOpenEnumW(RESOURCE_CONNECTED
, RESOURCETYPE_ANY
, 0, NULL
, &connected
);
2694 if (ret
!= WN_SUCCESS
)
2696 if (ret
!= WN_NO_NETWORK
)
2701 /* Means no provider, then, clearing is OK */
2706 resources
= HeapAlloc(GetProcessHeap(), 0, size
);
2709 WNetCloseEnum(connected
);
2710 return WN_OUT_OF_MEMORY
;
2718 memset(resources
, 0, size
);
2719 ret
= WNetEnumResourceW(connected
, &count
, resources
, &size
);
2720 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2722 for (iter
= resources
; count
; count
--, iter
++)
2724 if (iter
->lpLocalName
&& iter
->lpLocalName
[0])
2725 connection
= iter
->lpLocalName
;
2727 connection
= iter
->lpRemoteName
;
2729 WNetCancelConnection2W(connection
, 0, TRUE
);
2736 HeapFree(GetProcessHeap(), 0, resources
);
2737 WNetCloseEnum(connected
);
2747 /**************************************************************************
2748 * WNetGetUserA [MPR.@]
2750 * FIXME: we should not return ourselves, but the owner of the drive lpName
2752 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2754 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2755 return GetLastError();
2758 /*****************************************************************
2759 * WNetGetUserW [MPR.@]
2761 * FIXME: we should not return ourselves, but the owner of the drive lpName
2763 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2765 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2766 return GetLastError();
2769 /*********************************************************************
2770 * WNetConnectionDialog [MPR.@]
2772 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2774 CONNECTDLGSTRUCTW conn_dlg
;
2775 NETRESOURCEW net_res
;
2777 ZeroMemory(&conn_dlg
, sizeof(conn_dlg
));
2778 ZeroMemory(&net_res
, sizeof(net_res
));
2780 conn_dlg
.cbStructure
= sizeof(conn_dlg
);
2781 conn_dlg
.lpConnRes
= &net_res
;
2782 conn_dlg
.hwndOwner
= hwnd
;
2783 net_res
.dwType
= dwType
;
2785 return WNetConnectionDialog1W(&conn_dlg
);
2788 /*********************************************************************
2789 * WNetConnectionDialog1A [MPR.@]
2791 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2793 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2795 SetLastError(WN_NO_NETWORK
);
2796 return WN_NO_NETWORK
;
2799 /*********************************************************************
2800 * WNetConnectionDialog1W [MPR.@]
2802 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2804 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2806 SetLastError(WN_NO_NETWORK
);
2807 return WN_NO_NETWORK
;
2810 /*********************************************************************
2811 * WNetDisconnectDialog [MPR.@]
2813 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2817 HMODULE hDll
= LoadLibraryW(L
"netplwiz.dll");
2818 static BOOL (WINAPI
*pSHDisconnectNetDrives
)(PVOID
);
2819 pSHDisconnectNetDrives
= (VOID
*) GetProcAddress(hDll
, "SHDisconnectNetDrives");
2821 dwRet
= pSHDisconnectNetDrives(NULL
);
2826 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2828 SetLastError(WN_NO_NETWORK
);
2829 return WN_NO_NETWORK
;
2833 /*********************************************************************
2834 * WNetDisconnectDialog1A [MPR.@]
2836 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2838 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2840 SetLastError(WN_NO_NETWORK
);
2841 return WN_NO_NETWORK
;
2844 /*********************************************************************
2845 * WNetDisconnectDialog1W [MPR.@]
2847 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2849 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2851 SetLastError(WN_NO_NETWORK
);
2852 return WN_NO_NETWORK
;
2855 /*********************************************************************
2856 * WNetGetLastErrorA [MPR.@]
2858 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2859 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2860 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2862 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2863 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2865 SetLastError(WN_NO_NETWORK
);
2866 return WN_NO_NETWORK
;
2869 /*********************************************************************
2870 * WNetGetLastErrorW [MPR.@]
2872 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2873 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2874 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2876 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2877 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2879 SetLastError(WN_NO_NETWORK
);
2880 return WN_NO_NETWORK
;
2883 /*********************************************************************
2884 * WNetGetNetworkInformationA [MPR.@]
2886 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2887 LPNETINFOSTRUCT lpNetInfoStruct
)
2891 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2894 ret
= WN_BAD_POINTER
;
2899 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2902 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2906 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2908 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2909 HeapFree(GetProcessHeap(), 0, wideProvider
);
2912 ret
= WN_OUT_OF_MEMORY
;
2915 ret
= GetLastError();
2919 TRACE("Returning %d\n", ret
);
2923 /*********************************************************************
2924 * WNetGetNetworkInformationW [MPR.@]
2926 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2927 LPNETINFOSTRUCT lpNetInfoStruct
)
2931 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2934 ret
= WN_BAD_POINTER
;
2935 else if (!lpNetInfoStruct
)
2936 ret
= WN_BAD_POINTER
;
2937 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2941 if (providerTable
&& providerTable
->numProviders
)
2943 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2945 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2947 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2948 lpNetInfoStruct
->dwProviderVersion
=
2949 providerTable
->table
[providerIndex
].dwSpecVersion
;
2950 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2951 lpNetInfoStruct
->dwCharacteristics
= 0;
2952 lpNetInfoStruct
->dwHandle
= 0;
2953 lpNetInfoStruct
->wNetType
=
2954 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2955 lpNetInfoStruct
->dwPrinters
= -1;
2956 lpNetInfoStruct
->dwDrives
= -1;
2960 ret
= WN_BAD_PROVIDER
;
2963 ret
= WN_NO_NETWORK
;
2967 TRACE("Returning %d\n", ret
);
2971 /*****************************************************************
2972 * WNetGetProviderNameA [MPR.@]
2974 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2975 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2979 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2983 ret
= WN_BAD_POINTER
;
2984 else if (!lpBufferSize
)
2985 ret
= WN_BAD_POINTER
;
2992 ret
= WN_NO_NETWORK
;
2993 for (i
= 0; i
< providerTable
->numProviders
&&
2994 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2997 if (i
< providerTable
->numProviders
)
2999 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
3000 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
3002 if (*lpBufferSize
< sizeNeeded
)
3004 *lpBufferSize
= sizeNeeded
;
3009 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
3010 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
3012 /* FIXME: is *lpBufferSize set to the number of characters
3018 ret
= WN_NO_NETWORK
;
3022 TRACE("Returning %d\n", ret
);
3026 /*****************************************************************
3027 * WNetGetProviderNameW [MPR.@]
3029 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
3030 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
3034 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
3038 ret
= WN_BAD_POINTER
;
3039 else if (!lpBufferSize
)
3040 ret
= WN_BAD_POINTER
;
3047 ret
= WN_NO_NETWORK
;
3048 for (i
= 0; i
< providerTable
->numProviders
&&
3049 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
3052 if (i
< providerTable
->numProviders
)
3054 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
3056 if (*lpBufferSize
< sizeNeeded
)
3058 *lpBufferSize
= sizeNeeded
;
3063 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
3065 /* FIXME: is *lpBufferSize set to the number of characters
3071 ret
= WN_NO_NETWORK
;
3075 TRACE("Returning %d\n", ret
);