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
;
63 } WNetProvider
, *PWNetProvider
;
65 typedef struct _WNetProviderTable
70 WNetProvider table
[1];
71 } WNetProviderTable
, *PWNetProviderTable
;
73 #define WNET_ENUMERATOR_TYPE_GLOBAL 0
74 #define WNET_ENUMERATOR_TYPE_PROVIDER 1
75 #define WNET_ENUMERATOR_TYPE_CONTEXT 2
76 #define WNET_ENUMERATOR_TYPE_CONNECTED 3
77 #define WNET_ENUMERATOR_TYPE_REMEMBERED 4
79 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
80 * the enumeration; it represents one of the following types:
81 * - a global enumeration, one that's executed across all providers
82 * - a provider-specific enumeration, one that's only executed by a single
84 * - a context enumeration. I know this contradicts what I just said about
85 * there being no correspondence between the scope and the type, but it's
86 * necessary for the special case that a "Entire Network" entry needs to
87 * be enumerated in an enumeration of the context scope. Thus an enumeration
88 * of the context scope results in a context type enumerator, which morphs
89 * into a global enumeration (so the enumeration continues across all
91 * - a remembered enumeration, not related to providers themselves, but it
92 * is a registry enumeration for saved connections
94 typedef struct _WNetEnumerator
113 } WNetEnumerator
, *PWNetEnumerator
;
115 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
117 /* Returns an index (into the global WNetProviderTable) of the provider with
118 * the given name, or BAD_PROVIDER_INDEX if not found.
120 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
122 static PWNetProviderTable providerTable
;
125 * Global provider table functions
128 static void _tryLoadProvider(PCWSTR provider
)
130 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
131 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'S','e','r','v','i','c','e','s','\\',0 };
133 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
134 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
135 WCHAR serviceName
[MAX_PATH
];
138 TRACE("%s\n", debugstr_w(provider
));
139 snprintfW(serviceName
, ARRAY_SIZE(serviceName
), serviceFmt
, servicePrefix
, provider
);
140 serviceName
[ARRAY_SIZE(serviceName
) - 1] = '\0';
141 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
144 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
146 WCHAR providerPath
[MAX_PATH
];
147 DWORD type
, size
= sizeof(providerPath
);
149 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
150 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
152 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
155 if (type
== REG_EXPAND_SZ
)
157 WCHAR path
[MAX_PATH
];
158 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
162 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
165 name
= HeapAlloc(GetProcessHeap(), 0, size
);
166 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
167 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
169 HeapFree(GetProcessHeap(), 0, name
);
175 HMODULE hLib
= LoadLibraryW(providerPath
);
179 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
181 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
183 TRACE("loaded lib %p\n", hLib
);
187 PWNetProvider provider
=
188 &providerTable
->table
[providerTable
->numProviders
];
190 provider
->hLib
= hLib
;
191 provider
->name
= name
;
192 TRACE("name is %s\n", debugstr_w(name
));
193 provider
->getCaps
= getCaps
;
194 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
195 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
196 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
197 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
198 if (provider
->dwEnumScopes
)
200 TRACE("supports enumeration\n");
201 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
202 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
203 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
204 TRACE("NPEnumResource %p\n", provider
->enumResource
);
205 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
206 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
207 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
208 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
209 if (!provider
->openEnum
||
210 !provider
->enumResource
||
211 !provider
->closeEnum
)
213 provider
->openEnum
= NULL
;
214 provider
->enumResource
= NULL
;
215 provider
->closeEnum
= NULL
;
216 provider
->dwEnumScopes
= 0;
217 WARN("Couldn't load enumeration functions\n");
220 connectCap
= getCaps(WNNC_CONNECTION
);
221 if (connectCap
& WNNC_CON_ADDCONNECTION
)
222 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
223 if (connectCap
& WNNC_CON_ADDCONNECTION3
)
224 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
225 if (connectCap
& WNNC_CON_CANCELCONNECTION
)
226 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
227 TRACE("NPAddConnection %p\n", provider
->addConnection
);
228 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
229 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
230 providerTable
->numProviders
++;
234 WARN("Provider %s didn't export NPGetCaps\n",
235 debugstr_w(provider
));
236 HeapFree(GetProcessHeap(), 0, name
);
244 WARN("Couldn't load library %s for provider %s\n",
245 debugstr_w(providerPath
), debugstr_w(provider
));
246 HeapFree(GetProcessHeap(), 0, name
);
251 WARN("Couldn't get provider name for provider %s\n",
252 debugstr_w(provider
));
256 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
260 WARN("Couldn't open service key for provider %s\n",
261 debugstr_w(provider
));
264 void wnetInit(HINSTANCE hInstDll
)
266 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
267 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
268 'C','o','n','t','r','o','l','\\',
269 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
270 'O','r','d','e','r',0 };
271 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
272 'O','r','d','e','r',0 };
275 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
280 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
283 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
289 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
290 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
295 TRACE("provider order is %s\n", debugstr_w(providers
));
296 /* first count commas as a heuristic for how many to
297 * allocate space for */
298 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
300 ptr
= strchrW(ptr
, ',');
307 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
308 sizeof(WNetProviderTable
)
309 + (numToAllocate
- 1) * sizeof(WNetProvider
));
313 int entireNetworkLen
;
314 LPCWSTR stringresource
;
316 entireNetworkLen
= LoadStringW(hInstDll
,
317 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
318 providerTable
->entireNetwork
= HeapAlloc(
319 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
321 if (providerTable
->entireNetwork
)
323 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
324 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
326 providerTable
->numAllocated
= numToAllocate
;
327 for (ptr
= providers
; ptr
; )
330 ptr
= strchrW(ptr
, ',');
333 _tryLoadProvider(ptrPrev
);
337 HeapFree(GetProcessHeap(), 0, providers
);
350 for (i
= 0; i
< providerTable
->numProviders
; i
++)
352 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
353 FreeModule(providerTable
->table
[i
].hLib
);
355 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
356 HeapFree(GetProcessHeap(), 0, providerTable
);
357 providerTable
= NULL
;
361 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
363 DWORD ret
= BAD_PROVIDER_INDEX
;
365 if (providerTable
&& providerTable
->numProviders
)
369 for (i
= 0; i
< providerTable
->numProviders
&&
370 ret
== BAD_PROVIDER_INDEX
; i
++)
371 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
381 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
387 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
393 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
394 if (lpNet
->lpRemoteName
)
396 len
= strlenW(lpNet
->lpRemoteName
) + 1;
397 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
398 if (ret
->lpRemoteName
)
399 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
408 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
412 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
413 HeapFree(GetProcessHeap(), 0, lpNet
);
417 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
418 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
420 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
421 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
425 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
426 ret
->dwScope
= dwScope
;
427 ret
->dwType
= dwType
;
428 ret
->dwUsage
= dwUsage
;
429 ret
->specific
.net
= _copyNetResourceForEnumW(lpNet
);
434 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
435 DWORD dwUsage
, DWORD index
, HANDLE handle
)
439 if (!providerTable
|| index
>= providerTable
->numProviders
)
443 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
446 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
447 ret
->providerIndex
= index
;
448 ret
->dwScope
= dwScope
;
449 ret
->dwType
= dwType
;
450 ret
->dwUsage
= dwUsage
;
451 ret
->handle
= handle
;
457 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
460 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
461 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
465 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
466 ret
->dwScope
= dwScope
;
467 ret
->dwType
= dwType
;
468 ret
->dwUsage
= dwUsage
;
473 static PWNetEnumerator
_createConnectedEnumerator(DWORD dwScope
, DWORD dwType
,
476 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
479 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONNECTED
;
480 ret
->dwScope
= dwScope
;
481 ret
->dwType
= dwType
;
482 ret
->dwUsage
= dwUsage
;
483 ret
->specific
.handles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HANDLE
) * providerTable
->numProviders
);
484 if (!ret
->specific
.handles
)
486 HeapFree(GetProcessHeap(), 0, ret
);
493 static PWNetEnumerator
_createRememberedEnumerator(DWORD dwScope
, DWORD dwType
,
496 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
499 ret
->enumType
= WNET_ENUMERATOR_TYPE_REMEMBERED
;
500 ret
->dwScope
= dwScope
;
501 ret
->dwType
= dwType
;
502 ret
->specific
.remembered
.registry
= remembered
;
507 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
508 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
509 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
510 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
511 * if not all members of the array could be thunked, and something else on
514 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
515 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
517 DWORD i
, numToThunk
, totalBytes
, ret
;
521 return WN_BAD_POINTER
;
523 return WN_BAD_POINTER
;
527 return WN_BAD_POINTER
;
529 return WN_BAD_POINTER
;
531 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
533 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
535 totalBytes
+= sizeof(NETRESOURCEA
);
536 if (lpNet
->lpLocalName
)
537 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
538 -1, NULL
, 0, NULL
, NULL
);
539 if (lpNet
->lpRemoteName
)
540 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
541 -1, NULL
, 0, NULL
, NULL
);
542 if (lpNet
->lpComment
)
543 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
544 -1, NULL
, 0, NULL
, NULL
);
545 if (lpNet
->lpProvider
)
546 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
547 -1, NULL
, 0, NULL
, NULL
);
548 if (totalBytes
< *lpBufferSize
)
551 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
552 for (i
= 0; i
< numToThunk
; i
++)
554 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
555 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
557 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
558 /* lie about string lengths, we already verified how many
559 * we have space for above
561 if (lpNetIn
->lpLocalName
)
563 lpNetOut
->lpLocalName
= strNext
;
564 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
565 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
567 if (lpNetIn
->lpRemoteName
)
569 lpNetOut
->lpRemoteName
= strNext
;
570 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
571 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
573 if (lpNetIn
->lpComment
)
575 lpNetOut
->lpComment
= strNext
;
576 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
577 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
579 if (lpNetIn
->lpProvider
)
581 lpNetOut
->lpProvider
= strNext
;
582 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
583 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
586 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
587 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
592 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
593 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
594 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
595 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
596 * if not all members of the array could be thunked, and something else on
599 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
600 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
602 DWORD i
, numToThunk
, totalBytes
, ret
;
606 return WN_BAD_POINTER
;
608 return WN_BAD_POINTER
;
612 return WN_BAD_POINTER
;
614 return WN_BAD_POINTER
;
616 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
618 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
620 totalBytes
+= sizeof(NETRESOURCEW
);
621 if (lpNet
->lpLocalName
)
622 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
623 -1, NULL
, 0) * sizeof(WCHAR
);
624 if (lpNet
->lpRemoteName
)
625 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
626 -1, NULL
, 0) * sizeof(WCHAR
);
627 if (lpNet
->lpComment
)
628 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
629 -1, NULL
, 0) * sizeof(WCHAR
);
630 if (lpNet
->lpProvider
)
631 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
632 -1, NULL
, 0) * sizeof(WCHAR
);
633 if (totalBytes
< *lpBufferSize
)
636 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
637 for (i
= 0; i
< numToThunk
; i
++)
639 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
640 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
642 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
643 /* lie about string lengths, we already verified how many
644 * we have space for above
646 if (lpNetIn
->lpLocalName
)
648 lpNetOut
->lpLocalName
= strNext
;
649 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
650 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
652 if (lpNetIn
->lpRemoteName
)
654 lpNetOut
->lpRemoteName
= strNext
;
655 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
656 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
658 if (lpNetIn
->lpComment
)
660 lpNetOut
->lpComment
= strNext
;
661 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
662 -1, lpNetOut
->lpComment
, *lpBufferSize
);
664 if (lpNetIn
->lpProvider
)
666 lpNetOut
->lpProvider
= strNext
;
667 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
668 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
671 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
672 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
677 /*********************************************************************
678 * WNetOpenEnumA [MPR.@]
680 * See comments for WNetOpenEnumW.
682 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
683 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
687 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
688 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
691 ret
= WN_BAD_POINTER
;
692 else if (!providerTable
|| providerTable
->numProviders
== 0)
701 LPNETRESOURCEW lpNetWide
= NULL
;
703 DWORD size
= sizeof(buf
), count
= 1;
704 BOOL allocated
= FALSE
;
706 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
707 if (ret
== WN_MORE_DATA
)
709 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
713 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
718 ret
= WN_OUT_OF_MEMORY
;
720 else if (ret
== WN_SUCCESS
)
721 lpNetWide
= (LPNETRESOURCEW
)buf
;
722 if (ret
== WN_SUCCESS
)
723 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
726 HeapFree(GetProcessHeap(), 0, lpNetWide
);
729 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
733 TRACE("Returning %d\n", ret
);
737 /*********************************************************************
738 * WNetOpenEnumW [MPR.@]
740 * Network enumeration has way too many parameters, so I'm not positive I got
741 * them right. What I've got so far:
743 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
744 * all the network providers should be enumerated.
746 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
747 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
748 * lpProvider is set, all the network providers should be enumerated.
749 * (This means the enumeration is a list of network providers, not that the
750 * enumeration is passed on to the providers.)
752 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
753 * resource matches the "Entire Network" resource (no remote name, no
754 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
755 * enumeration is done on every network provider.
757 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
758 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
759 * only to the given network provider.
761 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
762 * no lpProvider is set, enumeration will be tried on every network provider,
763 * in the order in which they're loaded.
765 * - The LPNETRESOURCE should be disregarded for scopes besides
766 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
767 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
769 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
770 * resource in the enumerated list, as well as any machines in your
771 * workgroup. The machines in your workgroup come from doing a
772 * RESOURCE_CONTEXT enumeration of every Network Provider.
774 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
775 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
779 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
780 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
783 ret
= WN_BAD_POINTER
;
784 else if (!providerTable
|| providerTable
->numProviders
== 0)
793 case RESOURCE_GLOBALNET
:
796 if (lpNet
->lpProvider
)
798 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
800 if (index
!= BAD_PROVIDER_INDEX
)
802 if (providerTable
->table
[index
].openEnum
&&
803 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
806 PWSTR RemoteName
= lpNet
->lpRemoteName
;
808 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
809 RemoteName
&& !strcmpW(RemoteName
, lpNet
->lpProvider
))
810 lpNet
->lpRemoteName
= NULL
;
812 ret
= providerTable
->table
[index
].openEnum(
813 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
814 if (ret
== WN_SUCCESS
)
816 *lphEnum
= _createProviderEnumerator(
817 dwScope
, dwType
, dwUsage
, index
, handle
);
818 ret
= *lphEnum
? WN_SUCCESS
:
822 lpNet
->lpRemoteName
= RemoteName
;
825 ret
= WN_NOT_SUPPORTED
;
828 ret
= WN_BAD_PROVIDER
;
830 else if (lpNet
->lpRemoteName
)
832 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
833 dwType
, dwUsage
, lpNet
);
834 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
838 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
839 providerTable
->entireNetwork
))
841 /* comment matches the "Entire Network", enumerate
842 * global scope of every provider
844 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
845 dwType
, dwUsage
, lpNet
);
849 /* this is the same as not having passed lpNet */
850 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
851 dwType
, dwUsage
, NULL
);
853 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
858 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
860 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
863 case RESOURCE_CONTEXT
:
864 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
865 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
867 case RESOURCE_CONNECTED
:
868 *lphEnum
= _createConnectedEnumerator(dwScope
, dwType
, dwUsage
);
869 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
871 case RESOURCE_REMEMBERED
:
873 HKEY remembered
, user_profile
;
875 ret
= WN_OUT_OF_MEMORY
;
876 if (RegOpenCurrentUser(KEY_READ
, &user_profile
) == ERROR_SUCCESS
)
878 WCHAR subkey
[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
880 if (RegOpenKeyExW(user_profile
, subkey
, 0, KEY_READ
, &remembered
) == ERROR_SUCCESS
)
882 *lphEnum
= _createRememberedEnumerator(dwScope
, dwType
, remembered
);
883 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
886 RegCloseKey(user_profile
);
891 WARN("unknown scope 0x%08x\n", dwScope
);
897 TRACE("Returning %d\n", ret
);
901 /*********************************************************************
902 * WNetEnumResourceA [MPR.@]
904 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
905 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
909 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
912 ret
= WN_BAD_POINTER
;
914 ret
= WN_BAD_POINTER
;
916 ret
= WN_BAD_POINTER
;
917 else if (!lpBufferSize
)
918 ret
= WN_BAD_POINTER
;
919 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
921 *lpBufferSize
= sizeof(NETRESOURCEA
);
926 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
927 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
931 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
933 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
935 /* FIXME: this isn't necessarily going to work in the case of
936 * WN_MORE_DATA, because our enumerator may have moved on to
937 * the next provider. MSDN states that a large (16KB) buffer
938 * size is the appropriate usage of this function, so
939 * hopefully it won't be an issue.
941 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
942 lpBuffer
, lpBufferSize
);
943 *lpcCount
= localCount
;
945 HeapFree(GetProcessHeap(), 0, localBuffer
);
948 ret
= WN_OUT_OF_MEMORY
;
952 TRACE("Returning %d\n", ret
);
956 static DWORD
_countProviderBytesW(PWNetProvider provider
)
962 ret
= sizeof(NETRESOURCEW
);
963 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
970 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
971 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
976 return WN_BAD_POINTER
;
977 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
980 return WN_BAD_POINTER
;
982 return WN_BAD_POINTER
;
984 return WN_BAD_POINTER
;
985 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
988 if (!providerTable
|| enumerator
->providerIndex
>=
989 providerTable
->numProviders
)
990 ret
= WN_NO_MORE_ENTRIES
;
993 DWORD bytes
= 0, count
= 0, countLimit
, i
;
994 LPNETRESOURCEW resource
;
997 countLimit
= *lpcCount
== -1 ?
998 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
999 while (count
< countLimit
&& bytes
< *lpBufferSize
)
1001 DWORD bytesNext
= _countProviderBytesW(
1002 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
1004 if (bytes
+ bytesNext
< *lpBufferSize
)
1010 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
1011 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
1013 resource
->dwScope
= RESOURCE_GLOBALNET
;
1014 resource
->dwType
= RESOURCETYPE_ANY
;
1015 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
1016 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
1017 RESOURCEUSAGE_RESERVED
;
1018 resource
->lpLocalName
= NULL
;
1019 resource
->lpRemoteName
= strNext
;
1020 strcpyW(resource
->lpRemoteName
,
1021 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1022 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
1023 resource
->lpComment
= NULL
;
1024 resource
->lpProvider
= strNext
;
1025 strcpyW(resource
->lpProvider
,
1026 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1027 strNext
+= strlenW(resource
->lpProvider
) + 1;
1029 enumerator
->providerIndex
+= count
;
1031 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
1033 TRACE("Returning %d\n", ret
);
1037 /* Advances the enumerator (assumed to be a global enumerator) to the next
1038 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1039 * not open a handle with the next provider.
1040 * If the existing handle is NULL, may leave the enumerator unchanged, since
1041 * the current provider may support the desired scope.
1042 * If the existing handle is not NULL, closes it before moving on.
1043 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1044 * provider, and another error on failure.
1046 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
1049 return WN_BAD_POINTER
;
1050 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1051 return WN_BAD_VALUE
;
1052 if (!providerTable
|| enumerator
->providerIndex
>=
1053 providerTable
->numProviders
)
1054 return WN_NO_MORE_ENTRIES
;
1056 if (enumerator
->providerDone
)
1059 enumerator
->providerDone
= FALSE
;
1060 if (enumerator
->handle
)
1062 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1063 enumerator
->handle
);
1064 enumerator
->handle
= NULL
;
1065 enumerator
->providerIndex
++;
1067 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1068 dwEnum
= WNNC_ENUM_LOCAL
;
1069 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1070 dwEnum
= WNNC_ENUM_GLOBAL
;
1071 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1072 dwEnum
= WNNC_ENUM_CONTEXT
;
1073 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1074 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1075 & dwEnum
); enumerator
->providerIndex
++)
1078 return enumerator
->providerIndex
< providerTable
->numProviders
?
1079 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1082 /* "Passes through" call to the next provider that supports the enumeration
1084 * FIXME: if one call to a provider's enumerator succeeds while there's still
1085 * space in lpBuffer, I don't call to the next provider. The caller may not
1086 * expect that it should call EnumResourceW again with a return value of
1087 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1088 * may have to be moved around a bit, ick.
1090 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1091 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1096 return WN_BAD_POINTER
;
1097 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1098 return WN_BAD_VALUE
;
1100 return WN_BAD_POINTER
;
1102 return WN_BAD_POINTER
;
1104 return WN_BAD_POINTER
;
1105 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1106 return WN_MORE_DATA
;
1108 ret
= _globalEnumeratorAdvance(enumerator
);
1109 if (ret
== WN_SUCCESS
)
1111 ret
= providerTable
->table
[enumerator
->providerIndex
].
1112 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1113 enumerator
->dwUsage
, enumerator
->specific
.net
,
1114 &enumerator
->handle
);
1115 if (ret
== WN_SUCCESS
)
1117 ret
= providerTable
->table
[enumerator
->providerIndex
].
1118 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1120 if (ret
!= WN_MORE_DATA
)
1121 enumerator
->providerDone
= TRUE
;
1124 TRACE("Returning %d\n", ret
);
1128 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1129 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1134 return WN_BAD_POINTER
;
1135 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1136 return WN_BAD_VALUE
;
1138 return WN_BAD_POINTER
;
1140 return WN_BAD_POINTER
;
1142 return WN_BAD_POINTER
;
1143 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1144 return WN_MORE_DATA
;
1146 return WN_NO_NETWORK
;
1148 switch (enumerator
->dwScope
)
1150 case RESOURCE_GLOBALNET
:
1151 if (enumerator
->specific
.net
)
1152 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1153 lpBuffer
, lpBufferSize
);
1155 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1158 case RESOURCE_CONTEXT
:
1159 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1163 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1164 ret
= WN_NO_MORE_ENTRIES
;
1166 TRACE("Returning %d\n", ret
);
1170 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1171 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1174 return WN_BAD_POINTER
;
1175 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1176 return WN_BAD_VALUE
;
1177 if (!enumerator
->handle
)
1178 return WN_BAD_VALUE
;
1180 return WN_BAD_POINTER
;
1182 return WN_BAD_POINTER
;
1184 return WN_BAD_POINTER
;
1186 return WN_NO_NETWORK
;
1187 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1188 return WN_NO_MORE_ENTRIES
;
1189 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1190 return WN_BAD_VALUE
;
1191 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1192 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1195 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1196 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1199 size_t cchEntireNetworkLen
, bytesNeeded
;
1202 return WN_BAD_POINTER
;
1203 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1204 return WN_BAD_VALUE
;
1206 return WN_BAD_POINTER
;
1208 return WN_BAD_POINTER
;
1210 return WN_BAD_POINTER
;
1212 return WN_NO_NETWORK
;
1214 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1215 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1216 if (*lpBufferSize
< bytesNeeded
)
1218 *lpBufferSize
= bytesNeeded
;
1223 LPNETRESOURCEW lpNet
= lpBuffer
;
1225 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1226 lpNet
->dwType
= enumerator
->dwType
;
1227 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1228 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1229 lpNet
->lpLocalName
= NULL
;
1230 lpNet
->lpRemoteName
= NULL
;
1231 lpNet
->lpProvider
= NULL
;
1232 /* odd, but correct: put comment at end of buffer, so it won't get
1233 * overwritten by subsequent calls to a provider's enumResource
1235 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1236 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1237 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1240 if (ret
== WN_SUCCESS
)
1242 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1244 /* "Entire Network" entry enumerated--morph this into a global
1245 * enumerator. enumerator->lpNet continues to be NULL, since it has
1246 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1248 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1249 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1250 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1251 if (ret
== WN_SUCCESS
)
1253 /* reflect the fact that we already enumerated "Entire Network" */
1255 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1259 /* the provider enumeration failed, but we already succeeded in
1260 * enumerating "Entire Network"--leave type as global to allow a
1261 * retry, but indicate success with a count of one.
1265 *lpBufferSize
= bytesNeeded
;
1268 TRACE("Returning %d\n", ret
);
1272 static DWORD
_copyStringToEnumW(const WCHAR
*source
, DWORD
* left
, void** end
)
1275 WCHAR
* local
= *end
;
1277 len
= strlenW(source
) + 1;
1278 len
*= sizeof(WCHAR
);
1280 return WN_MORE_DATA
;
1282 local
-= (len
/ sizeof(WCHAR
));
1283 memcpy(local
, source
, len
);
1290 static DWORD
_enumerateConnectedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1291 void* user_buffer
, DWORD
* user_size
)
1293 DWORD ret
, index
, count
, total_count
, size
, i
, left
;
1295 NETRESOURCEW
* curr
, * buffer
;
1299 return WN_BAD_POINTER
;
1300 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONNECTED
)
1301 return WN_BAD_VALUE
;
1302 if (!user_count
|| !user_buffer
|| !user_size
)
1303 return WN_BAD_POINTER
;
1305 return WN_NO_NETWORK
;
1307 handles
= enumerator
->specific
.handles
;
1310 buffer
= HeapAlloc(GetProcessHeap(), 0, *user_size
);
1312 return WN_NO_NETWORK
;
1315 end
= (char *)user_buffer
+ size
;
1316 count
= *user_count
;
1319 ret
= WN_NO_MORE_ENTRIES
;
1320 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1322 if (providerTable
->table
[index
].dwEnumScopes
)
1324 if (handles
[index
] == 0)
1326 ret
= providerTable
->table
[index
].openEnum(enumerator
->dwScope
,
1328 enumerator
->dwUsage
,
1329 NULL
, &handles
[index
]);
1330 if (ret
!= WN_SUCCESS
)
1334 ret
= providerTable
->table
[index
].enumResource(handles
[index
],
1337 total_count
+= count
;
1338 if (ret
== WN_MORE_DATA
)
1341 if (ret
== WN_SUCCESS
)
1343 for (i
= 0; i
< count
; ++i
)
1345 if (left
< sizeof(NETRESOURCEW
))
1351 memcpy(curr
, &buffer
[i
], sizeof(NETRESOURCEW
));
1352 left
-= sizeof(NETRESOURCEW
);
1354 ret
= _copyStringToEnumW(buffer
[i
].lpLocalName
, &left
, &end
);
1355 if (ret
== WN_MORE_DATA
)
1357 curr
->lpLocalName
= end
;
1359 ret
= _copyStringToEnumW(buffer
[i
].lpRemoteName
, &left
, &end
);
1360 if (ret
== WN_MORE_DATA
)
1362 curr
->lpRemoteName
= end
;
1364 ret
= _copyStringToEnumW(buffer
[i
].lpProvider
, &left
, &end
);
1365 if (ret
== WN_MORE_DATA
)
1367 curr
->lpProvider
= end
;
1375 if (*user_count
!= -1)
1376 count
= *user_count
- total_count
;
1378 count
= *user_count
;
1382 if (total_count
== 0)
1383 ret
= WN_NO_MORE_ENTRIES
;
1385 *user_count
= total_count
;
1386 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1389 HeapFree(GetProcessHeap(), 0, buffer
);
1391 TRACE("Returning %d\n", ret
);
1395 static const WCHAR connectionType
[] = { 'C','o','n','n','e','c','t','i','o','n','T','y','p','e',0 };
1396 static const WCHAR providerName
[] = { 'P','r','o','v','i','d','e','r','N','a','m','e',0 };
1397 static const WCHAR remotePath
[] = { 'R','e','m','o','t','e','P','a','t','h',0 };
1399 static WCHAR
*get_reg_str(HKEY hkey
, const WCHAR
*value
, DWORD
*len
)
1404 if (!RegQueryValueExW(hkey
, value
, NULL
, &type
, NULL
, len
) && type
== REG_SZ
)
1406 if (!(ret
= HeapAlloc(GetProcessHeap(), 0, *len
))) return NULL
;
1407 RegQueryValueExW(hkey
, value
, 0, 0, (BYTE
*)ret
, len
);
1413 static DWORD
_enumeratorRememberedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1414 void* user_buffer
, DWORD
* user_size
)
1416 HKEY registry
, connection
;
1419 DWORD index
, ret
, type
, len
, size
, registry_size
, full_size
= 0, total_count
;
1420 NETRESOURCEW
* net_buffer
= user_buffer
;
1421 WCHAR
* str
, * registry_string
;
1423 /* we will do the work in a single loop, so here is some things:
1424 * we write netresource at the begin of the user buffer
1425 * we write strings at the end of the user buffer
1427 size_left
= *user_size
;
1429 type
= enumerator
->dwType
;
1430 registry
= enumerator
->specific
.remembered
.registry
;
1431 str
= (WCHAR
*)((ULONG_PTR
)user_buffer
+ *user_size
- sizeof(WCHAR
));
1432 for (index
= enumerator
->specific
.remembered
.index
; ; ++index
)
1434 enumerator
->specific
.remembered
.index
= index
;
1436 if (*user_count
!= -1 && total_count
== *user_count
)
1442 len
= ARRAY_SIZE(buffer
);
1443 ret
= RegEnumKeyExW(registry
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
);
1444 if (ret
!= ERROR_SUCCESS
)
1446 if (ret
== ERROR_NO_MORE_ITEMS
) ret
= WN_SUCCESS
;
1450 if (RegOpenKeyExW(registry
, buffer
, 0, KEY_READ
, &connection
) != ERROR_SUCCESS
)
1455 full_size
= sizeof(NETRESOURCEW
);
1456 size_left
-= sizeof(NETRESOURCEW
);
1460 size
= sizeof(DWORD
);
1461 RegQueryValueExW(connection
, connectionType
, NULL
, NULL
, (BYTE
*)&net_buffer
->dwType
, &size
);
1462 if (type
!= RESOURCETYPE_ANY
&& net_buffer
->dwType
!= type
)
1464 size_left
+= sizeof(NETRESOURCEW
);
1465 RegCloseKey(connection
);
1469 net_buffer
->dwScope
= RESOURCE_REMEMBERED
;
1470 net_buffer
->dwDisplayType
= RESOURCEDISPLAYTYPE_GENERIC
;
1471 net_buffer
->dwUsage
= RESOURCEUSAGE_CONNECTABLE
;
1476 /* FIXME: this only supports drive letters */
1477 full_size
+= 3 * sizeof(WCHAR
);
1478 size_left
-= 3 * sizeof(WCHAR
);
1485 net_buffer
->lpLocalName
= str
;
1489 registry_string
= get_reg_str(connection
, providerName
, ®istry_size
);
1490 if (registry_string
)
1492 full_size
+= registry_size
;
1493 size_left
-= registry_size
;
1497 str
-= (registry_size
/ sizeof(WCHAR
));
1498 lstrcpyW(str
, registry_string
);
1499 net_buffer
->lpProvider
= str
;
1504 HeapFree(GetProcessHeap(), 0, registry_string
);
1508 registry_string
= get_reg_str(connection
, remotePath
, ®istry_size
);
1509 if (registry_string
)
1511 full_size
+= registry_size
;
1512 size_left
-= registry_size
;
1516 str
-= (registry_size
/ sizeof(WCHAR
));
1517 lstrcpyW(str
, registry_string
);
1518 net_buffer
->lpRemoteName
= str
;
1523 HeapFree(GetProcessHeap(), 0, registry_string
);
1526 RegCloseKey(connection
);
1528 net_buffer
->lpComment
= NULL
;
1537 if (total_count
== 0)
1538 ret
= WN_NO_MORE_ENTRIES
;
1540 *user_count
= total_count
;
1542 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1545 if (ret
== WN_MORE_DATA
)
1546 *user_size
= *user_size
+ full_size
;
1551 /*********************************************************************
1552 * WNetEnumResourceW [MPR.@]
1554 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1555 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1559 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1562 ret
= WN_BAD_POINTER
;
1564 ret
= WN_BAD_POINTER
;
1566 ret
= WN_BAD_POINTER
;
1567 else if (!lpBufferSize
)
1568 ret
= WN_BAD_POINTER
;
1569 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1571 *lpBufferSize
= sizeof(NETRESOURCEW
);
1576 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1578 switch (enumerator
->enumType
)
1580 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1581 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1584 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1585 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1588 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1589 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1592 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1593 ret
= _enumerateConnectedW(enumerator
, lpcCount
, lpBuffer
,
1596 case WNET_ENUMERATOR_TYPE_REMEMBERED
:
1597 ret
= _enumeratorRememberedW(enumerator
, lpcCount
, lpBuffer
,
1601 WARN("bogus enumerator type!\n");
1602 ret
= WN_NO_NETWORK
;
1607 TRACE("Returning %d\n", ret
);
1611 /*********************************************************************
1612 * WNetCloseEnum [MPR.@]
1614 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1619 TRACE( "(%p)\n", hEnum
);
1623 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1625 switch (enumerator
->enumType
)
1627 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1628 if (enumerator
->specific
.net
)
1629 _freeEnumNetResource(enumerator
->specific
.net
);
1630 if (enumerator
->handle
)
1631 providerTable
->table
[enumerator
->providerIndex
].
1632 closeEnum(enumerator
->handle
);
1635 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1636 if (enumerator
->handle
)
1637 providerTable
->table
[enumerator
->providerIndex
].
1638 closeEnum(enumerator
->handle
);
1641 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1642 handles
= enumerator
->specific
.handles
;
1643 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1645 if (providerTable
->table
[index
].dwEnumScopes
&& handles
[index
])
1646 providerTable
->table
[index
].closeEnum(handles
[index
]);
1648 HeapFree(GetProcessHeap(), 0, handles
);
1651 case WNET_ENUMERATOR_TYPE_REMEMBERED
:
1652 RegCloseKey(enumerator
->specific
.remembered
.registry
);
1656 WARN("bogus enumerator type!\n");
1657 ret
= WN_BAD_HANDLE
;
1659 HeapFree(GetProcessHeap(), 0, hEnum
);
1662 ret
= WN_BAD_HANDLE
;
1665 TRACE("Returning %d\n", ret
);
1669 /*********************************************************************
1670 * WNetGetResourceInformationA [MPR.@]
1672 * See WNetGetResourceInformationW
1674 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1675 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1680 TRACE( "(%p, %p, %p, %p)\n",
1681 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1683 if (!providerTable
|| providerTable
->numProviders
== 0)
1684 ret
= WN_NO_NETWORK
;
1685 else if (lpNetResource
)
1687 LPNETRESOURCEW lpNetResourceW
= NULL
;
1688 DWORD size
= 1024, count
= 1;
1691 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1692 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1693 if (ret
== WN_MORE_DATA
)
1695 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1696 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1698 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1699 &count
, lpNetResourceW
, &size
);
1701 ret
= WN_OUT_OF_MEMORY
;
1703 if (ret
== WN_SUCCESS
)
1705 LPWSTR lpSystemW
= NULL
;
1708 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1711 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1712 lpBufferW
, &size
, &lpSystemW
);
1713 if (ret
== WN_MORE_DATA
)
1715 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1716 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1718 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1719 lpBufferW
, &size
, &lpSystemW
);
1721 ret
= WN_OUT_OF_MEMORY
;
1723 if (ret
== WN_SUCCESS
)
1725 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1726 &count
, lpBuffer
, cbBuffer
);
1727 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1728 lpNetResourceW
= lpBufferW
;
1729 size
= sizeof(NETRESOURCEA
);
1730 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1731 -1, NULL
, 0, NULL
, NULL
);
1732 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1733 -1, NULL
, 0, NULL
, NULL
);
1735 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1736 -1, NULL
, 0, NULL
, NULL
);
1737 if ((len
) && ( size
+ len
< *cbBuffer
))
1739 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1740 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1741 *lplpSystem
, len
, NULL
, NULL
);
1748 ret
= WN_OUT_OF_MEMORY
;
1749 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1752 ret
= WN_OUT_OF_MEMORY
;
1753 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1755 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1758 ret
= WN_NO_NETWORK
;
1762 TRACE("Returning %d\n", ret
);
1766 /*********************************************************************
1767 * WNetGetResourceInformationW [MPR.@]
1769 * WNetGetResourceInformationW function identifies the network provider
1770 * that owns the resource and gets information about the type of the resource.
1773 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1774 * defines a network resource.
1775 * lpBuffer [ O] the pointer to buffer, containing result. It
1776 * contains NETRESOURCEW structure and strings to
1777 * which the members of the NETRESOURCEW structure
1779 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1781 * lplpSystem [ O] the pointer to string in the output buffer,
1782 * containing the part of the resource name without
1783 * names of the server and share.
1786 * NO_ERROR if the function succeeds. System error code if the function fails.
1789 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1790 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1791 LPWSTR
*lplpSystem
)
1793 DWORD ret
= WN_NO_NETWORK
;
1796 TRACE( "(%p, %p, %p, %p)\n",
1797 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1800 ret
= WN_OUT_OF_MEMORY
;
1801 else if (providerTable
!= NULL
)
1803 /* FIXME: For function value of a variable is indifferent, it does
1804 * search of all providers in a network.
1806 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1808 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1809 WNNC_DLG_GETRESOURCEINFORMATION
)
1811 if (providerTable
->table
[index
].getResourceInformation
)
1812 ret
= providerTable
->table
[index
].getResourceInformation(
1813 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1815 ret
= WN_NO_NETWORK
;
1816 if (ret
== WN_SUCCESS
)
1826 /*********************************************************************
1827 * WNetGetResourceParentA [MPR.@]
1829 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1830 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1832 FIXME( "(%p, %p, %p): stub\n",
1833 lpNetResource
, lpBuffer
, lpBufferSize
);
1835 SetLastError(WN_NO_NETWORK
);
1836 return WN_NO_NETWORK
;
1839 /*********************************************************************
1840 * WNetGetResourceParentW [MPR.@]
1842 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1843 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1845 FIXME( "(%p, %p, %p): stub\n",
1846 lpNetResource
, lpBuffer
, lpBufferSize
);
1848 SetLastError(WN_NO_NETWORK
);
1849 return WN_NO_NETWORK
;
1855 * Connection Functions
1858 /*********************************************************************
1859 * WNetAddConnectionA [MPR.@]
1861 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1862 LPCSTR lpLocalName
)
1864 NETRESOURCEA resourcesA
;
1866 memset(&resourcesA
, 0, sizeof(resourcesA
));
1867 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
1868 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
1869 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1872 /*********************************************************************
1873 * WNetAddConnectionW [MPR.@]
1875 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1876 LPCWSTR lpLocalName
)
1878 NETRESOURCEW resourcesW
;
1880 memset(&resourcesW
, 0, sizeof(resourcesW
));
1881 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
1882 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
1883 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1886 /*********************************************************************
1887 * WNetAddConnection2A [MPR.@]
1889 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1890 LPCSTR lpPassword
, LPCSTR lpUserID
,
1893 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1897 /*********************************************************************
1898 * WNetAddConnection2W [MPR.@]
1900 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1901 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1904 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1908 /*********************************************************************
1909 * WNetAddConnection3A [MPR.@]
1911 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1912 LPCSTR lpPassword
, LPCSTR lpUserID
,
1915 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1916 dwFlags
, NULL
, 0, NULL
);
1919 /*********************************************************************
1920 * WNetAddConnection3W [MPR.@]
1922 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1923 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1926 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1927 dwFlags
, NULL
, 0, NULL
);
1930 struct use_connection_context
1933 NETRESOURCEW
*resource
;
1934 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
1941 DWORD (*pre_set_accessname
)(struct use_connection_context
*, WCHAR
*);
1942 void (*set_accessname
)(struct use_connection_context
*, WCHAR
*);
1945 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1947 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1952 len
= strlenW(local_name
);
1954 len
= strlenW(ctxt
->resource
->lpRemoteName
);
1956 if (++len
> *ctxt
->buffer_size
)
1958 *ctxt
->buffer_size
= len
;
1959 return ERROR_MORE_DATA
;
1963 ctxt
->accessname
= NULL
;
1965 return ERROR_SUCCESS
;
1968 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1970 WCHAR
*accessname
= ctxt
->accessname
;
1973 strcpyW(accessname
, local_name
);
1975 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1978 strcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
1981 static DWORD
wnet_use_provider( struct use_connection_context
*ctxt
, NETRESOURCEW
* netres
, WNetProvider
*provider
, BOOLEAN redirect
)
1985 caps
= provider
->getCaps(WNNC_CONNECTION
);
1986 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
1987 return ERROR_BAD_PROVIDER
;
1989 ret
= WN_ACCESS_DENIED
;
1992 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
1993 ret
= provider
->addConnection3(ctxt
->hwndOwner
, netres
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
1994 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
1995 ret
= provider
->addConnection(netres
, ctxt
->password
, ctxt
->userid
);
1997 if (ret
== WN_ALREADY_CONNECTED
&& redirect
)
1998 netres
->lpLocalName
[0] -= 1;
1999 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& netres
->lpLocalName
[0] >= 'C');
2001 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
2002 ctxt
->set_accessname(ctxt
, netres
->lpLocalName
);
2007 static const WCHAR providerType
[] = { 'P','r','o','v','i','d','e','r','T','y','p','e',0 };
2008 static const WCHAR userName
[] = { 'U','s','e','r','N','a','m','e',0 };
2010 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
2012 WNetProvider
*provider
= NULL
;
2013 DWORD index
, ret
= WN_NO_NETWORK
;
2014 BOOL redirect
= FALSE
;
2015 WCHAR letter
[3] = {'Z', ':', 0};
2016 NETRESOURCEW netres
;
2018 if (!providerTable
|| providerTable
->numProviders
== 0)
2019 return WN_NO_NETWORK
;
2021 if (!ctxt
->resource
)
2022 return ERROR_INVALID_PARAMETER
;
2023 netres
= *ctxt
->resource
;
2025 if (!netres
.lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
2027 if (netres
.dwType
!= RESOURCETYPE_DISK
&& netres
.dwType
!= RESOURCETYPE_PRINT
)
2028 return ERROR_BAD_DEV_TYPE
;
2030 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2032 FIXME("Local device selection is not implemented for printers.\n");
2033 return WN_NO_NETWORK
;
2037 netres
.lpLocalName
= letter
;
2040 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
2041 return ERROR_BAD_NET_NAME
;
2043 if ((ret
= ctxt
->pre_set_accessname(ctxt
, netres
.lpLocalName
)))
2046 if (netres
.lpProvider
)
2048 index
= _findProviderIndexW(netres
.lpProvider
);
2049 if (index
== BAD_PROVIDER_INDEX
)
2050 return ERROR_BAD_PROVIDER
;
2052 provider
= &providerTable
->table
[index
];
2053 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2057 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2059 provider
= &providerTable
->table
[index
];
2060 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
2061 if (ret
== WN_SUCCESS
|| ret
== WN_ALREADY_CONNECTED
)
2066 if (ret
== WN_SUCCESS
&& ctxt
->flags
& CONNECT_UPDATE_PROFILE
)
2070 if (netres
.dwType
== RESOURCETYPE_PRINT
)
2072 FIXME("Persistent connection are not supported for printers\n");
2076 if (RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2079 WCHAR subkey
[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres
.lpLocalName
[0], 0};
2081 if (RegCreateKeyExW(user_profile
, subkey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2082 KEY_ALL_ACCESS
, NULL
, &network
, NULL
) == ERROR_SUCCESS
)
2084 DWORD dword_arg
= RESOURCETYPE_DISK
;
2085 DWORD len
= (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
2086 static const WCHAR empty
[1] = {0};
2088 RegSetValueExW(network
, connectionType
, 0, REG_DWORD
, (const BYTE
*)&dword_arg
, sizeof(DWORD
));
2089 RegSetValueExW(network
, providerName
, 0, REG_SZ
, (const BYTE
*)provider
->name
, len
);
2090 RegSetValueExW(network
, providerType
, 0, REG_DWORD
, (const BYTE
*)&provider
->dwNetType
, sizeof(DWORD
));
2091 len
= (strlenW(netres
.lpRemoteName
) + 1) * sizeof(WCHAR
);
2092 RegSetValueExW(network
, remotePath
, 0, REG_SZ
, (const BYTE
*)netres
.lpRemoteName
, len
);
2093 len
= sizeof(empty
);
2094 RegSetValueExW(network
, userName
, 0, REG_SZ
, (const BYTE
*)empty
, len
);
2095 RegCloseKey(network
);
2098 RegCloseKey(user_profile
);
2105 /*****************************************************************
2106 * WNetUseConnectionW [MPR.@]
2108 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
2109 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
2111 struct use_connection_context ctxt
;
2113 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
2114 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
2115 accessname
, buffer_size
, result
);
2117 ctxt
.hwndOwner
= hwndOwner
;
2118 ctxt
.resource
= resource
;
2119 ctxt
.resourceA
= NULL
;
2120 ctxt
.password
= (WCHAR
*)password
;
2121 ctxt
.userid
= (WCHAR
*)userid
;
2123 ctxt
.accessname
= accessname
;
2124 ctxt
.buffer_size
= buffer_size
;
2125 ctxt
.result
= result
;
2126 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
2127 ctxt
.set_accessname
= use_connection_set_accessnameW
;
2129 return wnet_use_connection(&ctxt
);
2132 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2134 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
2139 len
= WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, NULL
, 0, NULL
, NULL
) - 1;
2141 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
2143 if (++len
> *ctxt
->buffer_size
)
2145 *ctxt
->buffer_size
= len
;
2146 return ERROR_MORE_DATA
;
2150 ctxt
->accessname
= NULL
;
2152 return ERROR_SUCCESS
;
2155 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
2157 char *accessname
= ctxt
->accessname
;
2160 WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, accessname
, *ctxt
->buffer_size
, NULL
, NULL
);
2162 *ctxt
->result
= CONNECT_LOCALDRIVE
;
2165 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
2168 static LPWSTR
strdupAtoW( LPCSTR str
)
2173 if (!str
) return NULL
;
2174 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
2175 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2176 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
2180 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
2182 resourceW
->dwScope
= resourceA
->dwScope
;
2183 resourceW
->dwType
= resourceA
->dwType
;
2184 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
2185 resourceW
->dwUsage
= resourceA
->dwUsage
;
2186 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
2187 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
2188 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
2189 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
2192 static void free_netresourceW( NETRESOURCEW
*resource
)
2194 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
2195 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
2196 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
2197 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
2200 /*****************************************************************
2201 * WNetUseConnectionA [MPR.@]
2203 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
2204 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
2205 DWORD
*buffer_size
, DWORD
*result
)
2207 struct use_connection_context ctxt
;
2208 NETRESOURCEW resourceW
;
2211 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
2212 accessname
, buffer_size
, result
);
2214 netresource_a_to_w(resource
, &resourceW
);
2216 ctxt
.hwndOwner
= hwndOwner
;
2217 ctxt
.resource
= &resourceW
;
2218 ctxt
.resourceA
= resource
;
2219 ctxt
.password
= strdupAtoW(password
);
2220 ctxt
.userid
= strdupAtoW(userid
);
2222 ctxt
.accessname
= accessname
;
2223 ctxt
.buffer_size
= buffer_size
;
2224 ctxt
.result
= result
;
2225 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
2226 ctxt
.set_accessname
= use_connection_set_accessnameA
;
2228 ret
= wnet_use_connection(&ctxt
);
2230 free_netresourceW(&resourceW
);
2231 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
2232 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
2237 /*********************************************************************
2238 * WNetCancelConnectionA [MPR.@]
2240 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
2242 return WNetCancelConnection2A(lpName
, 0, fForce
);
2245 /*********************************************************************
2246 * WNetCancelConnectionW [MPR.@]
2248 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
2250 return WNetCancelConnection2W(lpName
, 0, fForce
);
2253 /*********************************************************************
2254 * WNetCancelConnection2A [MPR.@]
2256 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2259 WCHAR
* name
= strdupAtoW(lpName
);
2261 return ERROR_NOT_CONNECTED
;
2263 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
2264 HeapFree(GetProcessHeap(), 0, name
);
2269 /*********************************************************************
2270 * WNetCancelConnection2W [MPR.@]
2272 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2274 DWORD ret
= WN_NO_NETWORK
;
2277 if (providerTable
!= NULL
)
2279 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2281 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2282 WNNC_CON_CANCELCONNECTION
)
2284 if (providerTable
->table
[index
].cancelConnection
)
2285 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
2287 ret
= WN_NO_NETWORK
;
2288 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
2294 if (ret
== WN_SUCCESS
&& dwFlags
& CONNECT_UPDATE_PROFILE
)
2298 /* FIXME: Only remove it if that's a drive letter */
2299 if (isalphaW(lpName
[0]) && lpName
[1] == ':' &&
2300 RegOpenCurrentUser(KEY_ALL_ACCESS
, &user_profile
) == ERROR_SUCCESS
)
2302 WCHAR subkey
[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', lpName
[0], 0};
2304 RegDeleteKeyW(user_profile
, subkey
);
2306 RegCloseKey(user_profile
);
2313 /*****************************************************************
2314 * WNetRestoreConnectionA [MPR.@]
2316 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
2318 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
2320 SetLastError(WN_NO_NETWORK
);
2321 return WN_NO_NETWORK
;
2324 /*****************************************************************
2325 * WNetRestoreConnectionW [MPR.@]
2327 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
2329 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
2331 SetLastError(WN_NO_NETWORK
);
2332 return WN_NO_NETWORK
;
2335 /**************************************************************************
2336 * WNetGetConnectionA [MPR.@]
2339 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2340 * - WN_NOT_CONNECTED drive is a local drive
2341 * - WN_MORE_DATA buffer isn't big enough
2342 * - WN_SUCCESS success (net path in buffer)
2344 * FIXME: need to test return values under different errors
2346 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
2347 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
2352 ret
= WN_BAD_POINTER
;
2353 else if (!lpBufferSize
)
2354 ret
= WN_BAD_POINTER
;
2355 else if (!lpRemoteName
&& *lpBufferSize
)
2356 ret
= WN_BAD_POINTER
;
2359 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
2363 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2367 WCHAR wideRemoteStatic
[MAX_PATH
];
2368 DWORD wideRemoteSize
= ARRAY_SIZE(wideRemoteStatic
);
2370 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
2372 /* try once without memory allocation */
2373 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
2375 if (ret
== WN_SUCCESS
)
2377 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2378 -1, NULL
, 0, NULL
, NULL
);
2380 if (len
<= *lpBufferSize
)
2382 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
2383 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2388 *lpBufferSize
= len
;
2392 else if (ret
== WN_MORE_DATA
)
2394 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2395 wideRemoteSize
* sizeof(WCHAR
));
2399 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2401 if (ret
== WN_SUCCESS
)
2403 if (len
<= *lpBufferSize
)
2405 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2406 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2411 *lpBufferSize
= len
;
2415 HeapFree(GetProcessHeap(), 0, wideRemote
);
2418 ret
= WN_OUT_OF_MEMORY
;
2420 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2423 ret
= WN_OUT_OF_MEMORY
;
2426 ret
= WN_BAD_LOCALNAME
;
2430 TRACE("Returning %d\n", ret
);
2434 /* find the network connection for a given drive; helper for WNetGetConnection */
2435 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2438 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2440 DWORD ret
= WN_NOT_CONNECTED
;
2441 DWORD bytes_returned
;
2443 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2444 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2445 0, 0 )) == INVALID_HANDLE_VALUE
)
2447 ERR( "failed to open mount manager err %u\n", GetLastError() );
2450 memset( data
, 0, sizeof(*data
) );
2451 data
->letter
= letter
;
2452 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2453 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2455 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2458 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2461 mount_point
[0] = '\\';
2462 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2464 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2472 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2481 /**************************************************************************
2482 * WNetGetConnectionW [MPR.@]
2484 * FIXME: need to test return values under different errors
2486 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2487 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2491 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2495 ret
= WN_BAD_POINTER
;
2496 else if (!lpBufferSize
)
2497 ret
= WN_BAD_POINTER
;
2498 else if (!lpRemoteName
&& *lpBufferSize
)
2499 ret
= WN_BAD_POINTER
;
2500 else if (!lpLocalName
[0])
2501 ret
= WN_BAD_LOCALNAME
;
2504 if (lpLocalName
[1] == ':')
2506 switch(GetDriveTypeW(lpLocalName
))
2509 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2511 case DRIVE_REMOVABLE
:
2514 TRACE("file is local\n");
2515 ret
= WN_NOT_CONNECTED
;
2518 ret
= WN_BAD_LOCALNAME
;
2522 ret
= WN_BAD_LOCALNAME
;
2526 TRACE("Returning %d\n", ret
);
2530 /**************************************************************************
2531 * WNetSetConnectionA [MPR.@]
2533 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2536 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2538 SetLastError(WN_NO_NETWORK
);
2539 return WN_NO_NETWORK
;
2542 /**************************************************************************
2543 * WNetSetConnectionW [MPR.@]
2545 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2548 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2550 SetLastError(WN_NO_NETWORK
);
2551 return WN_NO_NETWORK
;
2554 /*****************************************************************
2555 * WNetGetUniversalNameA [MPR.@]
2557 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2558 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2562 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2563 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2565 switch (dwInfoLevel
)
2567 case UNIVERSAL_NAME_INFO_LEVEL
:
2569 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2571 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2573 err
= ERROR_NOT_CONNECTED
;
2577 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2578 if (*lpBufferSize
< size
)
2583 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2584 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2588 case REMOTE_NAME_INFO_LEVEL
:
2589 err
= WN_NOT_CONNECTED
;
2601 /*****************************************************************
2602 * WNetGetUniversalNameW [MPR.@]
2604 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2605 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2609 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2610 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2612 switch (dwInfoLevel
)
2614 case UNIVERSAL_NAME_INFO_LEVEL
:
2616 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2618 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2620 err
= ERROR_NOT_CONNECTED
;
2624 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2625 if (*lpBufferSize
< size
)
2627 *lpBufferSize
= size
;
2631 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2632 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2636 case REMOTE_NAME_INFO_LEVEL
:
2637 err
= WN_NO_NETWORK
;
2645 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2649 /*****************************************************************
2650 * WNetClearConnections [MPR.@]
2652 DWORD WINAPI
WNetClearConnections ( HWND owner
)
2656 DWORD ret
, size
, count
;
2657 NETRESOURCEW
* resources
, * iter
;
2659 ret
= WNetOpenEnumW(RESOURCE_CONNECTED
, RESOURCETYPE_ANY
, 0, NULL
, &connected
);
2660 if (ret
!= WN_SUCCESS
)
2662 if (ret
!= WN_NO_NETWORK
)
2667 /* Means no provider, then, clearing is OK */
2672 resources
= HeapAlloc(GetProcessHeap(), 0, size
);
2675 WNetCloseEnum(connected
);
2676 return WN_OUT_OF_MEMORY
;
2684 memset(resources
, 0, size
);
2685 ret
= WNetEnumResourceW(connected
, &count
, resources
, &size
);
2686 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2688 for (iter
= resources
; count
; count
--, iter
++)
2690 if (iter
->lpLocalName
&& iter
->lpLocalName
[0])
2691 connection
= iter
->lpLocalName
;
2693 connection
= iter
->lpRemoteName
;
2695 WNetCancelConnection2W(connection
, 0, TRUE
);
2702 HeapFree(GetProcessHeap(), 0, resources
);
2703 WNetCloseEnum(connected
);
2713 /**************************************************************************
2714 * WNetGetUserA [MPR.@]
2716 * FIXME: we should not return ourselves, but the owner of the drive lpName
2718 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2720 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2721 return GetLastError();
2724 /*****************************************************************
2725 * WNetGetUserW [MPR.@]
2727 * FIXME: we should not return ourselves, but the owner of the drive lpName
2729 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2731 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2732 return GetLastError();
2735 /*********************************************************************
2736 * WNetConnectionDialog [MPR.@]
2738 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2740 CONNECTDLGSTRUCTW conn_dlg
;
2741 NETRESOURCEW net_res
;
2743 ZeroMemory(&conn_dlg
, sizeof(conn_dlg
));
2744 ZeroMemory(&net_res
, sizeof(net_res
));
2746 conn_dlg
.cbStructure
= sizeof(conn_dlg
);
2747 conn_dlg
.lpConnRes
= &net_res
;
2748 conn_dlg
.hwndOwner
= hwnd
;
2749 net_res
.dwType
= dwType
;
2751 return WNetConnectionDialog1W(&conn_dlg
);
2754 /*********************************************************************
2755 * WNetConnectionDialog1A [MPR.@]
2757 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2759 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2761 SetLastError(WN_NO_NETWORK
);
2762 return WN_NO_NETWORK
;
2765 /*********************************************************************
2766 * WNetConnectionDialog1W [MPR.@]
2768 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2770 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2772 SetLastError(WN_NO_NETWORK
);
2773 return WN_NO_NETWORK
;
2776 /*********************************************************************
2777 * WNetDisconnectDialog [MPR.@]
2779 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2781 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2783 SetLastError(WN_NO_NETWORK
);
2784 return WN_NO_NETWORK
;
2787 /*********************************************************************
2788 * WNetDisconnectDialog1A [MPR.@]
2790 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2792 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2794 SetLastError(WN_NO_NETWORK
);
2795 return WN_NO_NETWORK
;
2798 /*********************************************************************
2799 * WNetDisconnectDialog1W [MPR.@]
2801 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2803 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2805 SetLastError(WN_NO_NETWORK
);
2806 return WN_NO_NETWORK
;
2809 /*********************************************************************
2810 * WNetGetLastErrorA [MPR.@]
2812 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2813 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2814 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2816 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2817 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2819 SetLastError(WN_NO_NETWORK
);
2820 return WN_NO_NETWORK
;
2823 /*********************************************************************
2824 * WNetGetLastErrorW [MPR.@]
2826 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2827 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2828 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2830 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2831 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2833 SetLastError(WN_NO_NETWORK
);
2834 return WN_NO_NETWORK
;
2837 /*********************************************************************
2838 * WNetGetNetworkInformationA [MPR.@]
2840 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2841 LPNETINFOSTRUCT lpNetInfoStruct
)
2845 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2848 ret
= WN_BAD_POINTER
;
2853 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2856 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2860 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2862 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2863 HeapFree(GetProcessHeap(), 0, wideProvider
);
2866 ret
= WN_OUT_OF_MEMORY
;
2869 ret
= GetLastError();
2873 TRACE("Returning %d\n", ret
);
2877 /*********************************************************************
2878 * WNetGetNetworkInformationW [MPR.@]
2880 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2881 LPNETINFOSTRUCT lpNetInfoStruct
)
2885 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2888 ret
= WN_BAD_POINTER
;
2889 else if (!lpNetInfoStruct
)
2890 ret
= WN_BAD_POINTER
;
2891 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2895 if (providerTable
&& providerTable
->numProviders
)
2897 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2899 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2901 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2902 lpNetInfoStruct
->dwProviderVersion
=
2903 providerTable
->table
[providerIndex
].dwSpecVersion
;
2904 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2905 lpNetInfoStruct
->dwCharacteristics
= 0;
2906 lpNetInfoStruct
->dwHandle
= 0;
2907 lpNetInfoStruct
->wNetType
=
2908 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2909 lpNetInfoStruct
->dwPrinters
= -1;
2910 lpNetInfoStruct
->dwDrives
= -1;
2914 ret
= WN_BAD_PROVIDER
;
2917 ret
= WN_NO_NETWORK
;
2921 TRACE("Returning %d\n", ret
);
2925 /*****************************************************************
2926 * WNetGetProviderNameA [MPR.@]
2928 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2929 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2933 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2937 ret
= WN_BAD_POINTER
;
2938 else if (!lpBufferSize
)
2939 ret
= WN_BAD_POINTER
;
2946 ret
= WN_NO_NETWORK
;
2947 for (i
= 0; i
< providerTable
->numProviders
&&
2948 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2951 if (i
< providerTable
->numProviders
)
2953 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2954 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2956 if (*lpBufferSize
< sizeNeeded
)
2958 *lpBufferSize
= sizeNeeded
;
2963 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2964 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2966 /* FIXME: is *lpBufferSize set to the number of characters
2972 ret
= WN_NO_NETWORK
;
2976 TRACE("Returning %d\n", ret
);
2980 /*****************************************************************
2981 * WNetGetProviderNameW [MPR.@]
2983 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2984 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2988 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2992 ret
= WN_BAD_POINTER
;
2993 else if (!lpBufferSize
)
2994 ret
= WN_BAD_POINTER
;
3001 ret
= WN_NO_NETWORK
;
3002 for (i
= 0; i
< providerTable
->numProviders
&&
3003 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
3006 if (i
< providerTable
->numProviders
)
3008 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
3010 if (*lpBufferSize
< sizeNeeded
)
3012 *lpBufferSize
= sizeNeeded
;
3017 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
3019 /* FIXME: is *lpBufferSize set to the number of characters
3025 ret
= WN_NO_NETWORK
;
3029 TRACE("Returning %d\n", ret
);