4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
7 * Copyright 2016 Pierre Schweitzer
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #define WINE_MOUNTMGR_EXTENSIONS
29 #include <ddk/mountmgr.h>
30 #include <wine/unicode.h>
32 /* Data structures representing network service providers. Assumes only one
33 * thread creates them, and that they are constant for the life of the process
34 * (and therefore doesn't synchronize access).
35 * FIXME: only basic provider data and enumeration-related data are implemented
36 * so far, need to implement the rest too.
38 typedef struct _WNetProvider
46 PF_NPOpenEnum openEnum
;
47 PF_NPEnumResource enumResource
;
48 PF_NPCloseEnum closeEnum
;
49 PF_NPGetResourceInformation getResourceInformation
;
50 PF_NPAddConnection addConnection
;
51 PF_NPAddConnection3 addConnection3
;
52 PF_NPCancelConnection cancelConnection
;
54 PF_NPGetConnection getConnection
;
56 } WNetProvider
, *PWNetProvider
;
58 typedef struct _WNetProviderTable
63 WNetProvider table
[1];
64 } WNetProviderTable
, *PWNetProviderTable
;
66 #define WNET_ENUMERATOR_TYPE_NULL 0
67 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
68 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
69 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
70 #define WNET_ENUMERATOR_TYPE_CONNECTED 4
72 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
73 * the enumeration; it represents one of the following types:
74 * - a 'null' enumeration, one that contains no members
75 * - a global enumeration, one that's executed across all providers
76 * - a provider-specific enumeration, one that's only executed by a single
78 * - a context enumeration. I know this contradicts what I just said about
79 * there being no correspondence between the scope and the type, but it's
80 * necessary for the special case that a "Entire Network" entry needs to
81 * be enumerated in an enumeration of the context scope. Thus an enumeration
82 * of the context scope results in a context type enumerator, which morphs
83 * into a global enumeration (so the enumeration continues across all
86 typedef struct _WNetEnumerator
100 } WNetEnumerator
, *PWNetEnumerator
;
102 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
104 /* Returns an index (into the global WNetProviderTable) of the provider with
105 * the given name, or BAD_PROVIDER_INDEX if not found.
107 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
109 static PWNetProviderTable providerTable
;
112 * Global provider table functions
115 static void _tryLoadProvider(PCWSTR provider
)
117 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
118 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
119 'S','e','r','v','i','c','e','s','\\',0 };
120 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
121 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
122 WCHAR serviceName
[MAX_PATH
];
125 TRACE("%s\n", debugstr_w(provider
));
126 snprintfW(serviceName
, sizeof(serviceName
) / sizeof(WCHAR
), serviceFmt
,
127 servicePrefix
, provider
);
128 serviceName
[sizeof(serviceName
) / sizeof(WCHAR
) - 1] = '\0';
129 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
132 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
134 WCHAR providerPath
[MAX_PATH
];
135 DWORD type
, size
= sizeof(providerPath
);
137 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
138 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
140 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
143 if (type
== REG_EXPAND_SZ
)
145 WCHAR path
[MAX_PATH
];
146 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
150 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
153 name
= HeapAlloc(GetProcessHeap(), 0, size
);
154 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
155 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
157 HeapFree(GetProcessHeap(), 0, name
);
163 HMODULE hLib
= LoadLibraryW(providerPath
);
167 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
169 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
171 TRACE("loaded lib %p\n", hLib
);
174 PWNetProvider provider
=
175 &providerTable
->table
[providerTable
->numProviders
];
177 provider
->hLib
= hLib
;
178 provider
->name
= name
;
179 TRACE("name is %s\n", debugstr_w(name
));
180 provider
->getCaps
= getCaps
;
181 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
182 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
183 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
184 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
185 if (provider
->dwEnumScopes
)
187 TRACE("supports enumeration\n");
188 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
189 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
190 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
191 TRACE("NPEnumResource %p\n", provider
->enumResource
);
192 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
193 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
194 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
195 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
196 if (!provider
->openEnum
||
197 !provider
->enumResource
||
198 !provider
->closeEnum
)
200 provider
->openEnum
= NULL
;
201 provider
->enumResource
= NULL
;
202 provider
->closeEnum
= NULL
;
203 provider
->dwEnumScopes
= 0;
204 WARN("Couldn't load enumeration functions\n");
207 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
208 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
209 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
211 provider
->getConnection
= MPR_GETPROC(NPGetConnection
);
213 TRACE("NPAddConnection %p\n", provider
->addConnection
);
214 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
215 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
216 providerTable
->numProviders
++;
220 WARN("Provider %s didn't export NPGetCaps\n",
221 debugstr_w(provider
));
222 HeapFree(GetProcessHeap(), 0, name
);
230 WARN("Couldn't load library %s for provider %s\n",
231 debugstr_w(providerPath
), debugstr_w(provider
));
232 HeapFree(GetProcessHeap(), 0, name
);
237 WARN("Couldn't get provider name for provider %s\n",
238 debugstr_w(provider
));
242 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
246 WARN("Couldn't open service key for provider %s\n",
247 debugstr_w(provider
));
250 void wnetInit(HINSTANCE hInstDll
)
252 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
253 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
254 'C','o','n','t','r','o','l','\\',
255 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
256 'O','r','d','e','r',0 };
257 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
258 'O','r','d','e','r',0 };
261 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
266 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
269 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
275 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
276 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
281 TRACE("provider order is %s\n", debugstr_w(providers
));
282 /* first count commas as a heuristic for how many to
283 * allocate space for */
284 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
286 ptr
= strchrW(ptr
, ',');
293 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
294 sizeof(WNetProviderTable
)
295 + (numToAllocate
- 1) * sizeof(WNetProvider
));
299 int entireNetworkLen
;
300 LPCWSTR stringresource
;
302 entireNetworkLen
= LoadStringW(hInstDll
,
303 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
304 providerTable
->entireNetwork
= HeapAlloc(
305 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
307 if (providerTable
->entireNetwork
)
309 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
310 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
312 providerTable
->numAllocated
= numToAllocate
;
313 for (ptr
= providers
; ptr
; )
316 ptr
= strchrW(ptr
, ',');
319 _tryLoadProvider(ptrPrev
);
323 HeapFree(GetProcessHeap(), 0, providers
);
336 for (i
= 0; i
< providerTable
->numProviders
; i
++)
338 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
339 FreeModule(providerTable
->table
[i
].hLib
);
341 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
342 HeapFree(GetProcessHeap(), 0, providerTable
);
343 providerTable
= NULL
;
347 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
349 DWORD ret
= BAD_PROVIDER_INDEX
;
351 if (providerTable
&& providerTable
->numProviders
)
355 for (i
= 0; i
< providerTable
->numProviders
&&
356 ret
== BAD_PROVIDER_INDEX
; i
++)
357 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
367 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
373 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
379 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
380 if (lpNet
->lpRemoteName
)
382 len
= strlenW(lpNet
->lpRemoteName
) + 1;
383 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
384 if (ret
->lpRemoteName
)
385 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
394 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
398 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
399 HeapFree(GetProcessHeap(), 0, lpNet
);
403 static PWNetEnumerator
_createNullEnumerator(void)
405 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
406 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
409 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
413 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
414 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
416 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
417 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
421 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
422 ret
->dwScope
= dwScope
;
423 ret
->dwType
= dwType
;
424 ret
->dwUsage
= dwUsage
;
425 ret
->specific
.net
= _copyNetResourceForEnumW(lpNet
);
430 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
431 DWORD dwUsage
, DWORD index
, HANDLE handle
)
435 if (!providerTable
|| index
>= providerTable
->numProviders
)
439 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
442 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
443 ret
->providerIndex
= index
;
444 ret
->dwScope
= dwScope
;
445 ret
->dwType
= dwType
;
446 ret
->dwUsage
= dwUsage
;
447 ret
->handle
= handle
;
453 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
456 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
457 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
461 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
462 ret
->dwScope
= dwScope
;
463 ret
->dwType
= dwType
;
464 ret
->dwUsage
= dwUsage
;
469 static PWNetEnumerator
_createConnectedEnumerator(DWORD dwScope
, DWORD dwType
,
472 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
475 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONNECTED
;
476 ret
->dwScope
= dwScope
;
477 ret
->dwType
= dwType
;
478 ret
->dwUsage
= dwUsage
;
479 ret
->specific
.handles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HANDLE
) * providerTable
->numProviders
);
480 if (!ret
->specific
.handles
)
482 HeapFree(GetProcessHeap(), 0, ret
);
489 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
490 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
491 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
492 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
493 * if not all members of the array could be thunked, and something else on
496 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
497 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
499 DWORD i
, numToThunk
, totalBytes
, ret
;
503 return WN_BAD_POINTER
;
505 return WN_BAD_POINTER
;
509 return WN_BAD_POINTER
;
511 return WN_BAD_POINTER
;
513 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
515 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
517 totalBytes
+= sizeof(NETRESOURCEA
);
518 if (lpNet
->lpLocalName
)
519 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
520 -1, NULL
, 0, NULL
, NULL
);
521 if (lpNet
->lpRemoteName
)
522 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
523 -1, NULL
, 0, NULL
, NULL
);
524 if (lpNet
->lpComment
)
525 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
526 -1, NULL
, 0, NULL
, NULL
);
527 if (lpNet
->lpProvider
)
528 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
529 -1, NULL
, 0, NULL
, NULL
);
530 if (totalBytes
< *lpBufferSize
)
533 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
534 for (i
= 0; i
< numToThunk
; i
++)
536 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
537 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
539 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
540 /* lie about string lengths, we already verified how many
541 * we have space for above
543 if (lpNetIn
->lpLocalName
)
545 lpNetOut
->lpLocalName
= strNext
;
546 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
547 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
549 if (lpNetIn
->lpRemoteName
)
551 lpNetOut
->lpRemoteName
= strNext
;
552 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
553 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
555 if (lpNetIn
->lpComment
)
557 lpNetOut
->lpComment
= strNext
;
558 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
559 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
561 if (lpNetIn
->lpProvider
)
563 lpNetOut
->lpProvider
= strNext
;
564 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
565 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
568 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
569 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
574 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
575 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
576 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
577 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
578 * if not all members of the array could be thunked, and something else on
581 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
582 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
584 DWORD i
, numToThunk
, totalBytes
, ret
;
588 return WN_BAD_POINTER
;
590 return WN_BAD_POINTER
;
594 return WN_BAD_POINTER
;
596 return WN_BAD_POINTER
;
598 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
600 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
602 totalBytes
+= sizeof(NETRESOURCEW
);
603 if (lpNet
->lpLocalName
)
604 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
605 -1, NULL
, 0) * sizeof(WCHAR
);
606 if (lpNet
->lpRemoteName
)
607 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
608 -1, NULL
, 0) * sizeof(WCHAR
);
609 if (lpNet
->lpComment
)
610 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
611 -1, NULL
, 0) * sizeof(WCHAR
);
612 if (lpNet
->lpProvider
)
613 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
614 -1, NULL
, 0) * sizeof(WCHAR
);
615 if (totalBytes
< *lpBufferSize
)
618 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
619 for (i
= 0; i
< numToThunk
; i
++)
621 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
622 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
624 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
625 /* lie about string lengths, we already verified how many
626 * we have space for above
628 if (lpNetIn
->lpLocalName
)
630 lpNetOut
->lpLocalName
= strNext
;
631 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
632 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
634 if (lpNetIn
->lpRemoteName
)
636 lpNetOut
->lpRemoteName
= strNext
;
637 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
638 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
640 if (lpNetIn
->lpComment
)
642 lpNetOut
->lpComment
= strNext
;
643 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
644 -1, lpNetOut
->lpComment
, *lpBufferSize
);
646 if (lpNetIn
->lpProvider
)
648 lpNetOut
->lpProvider
= strNext
;
649 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
650 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
653 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
654 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
659 /*********************************************************************
660 * WNetOpenEnumA [MPR.@]
662 * See comments for WNetOpenEnumW.
664 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
665 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
669 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
670 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
673 ret
= WN_BAD_POINTER
;
674 else if (!providerTable
|| providerTable
->numProviders
== 0)
683 LPNETRESOURCEW lpNetWide
= NULL
;
685 DWORD size
= sizeof(buf
), count
= 1;
686 BOOL allocated
= FALSE
;
688 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
689 if (ret
== WN_MORE_DATA
)
691 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
695 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
700 ret
= WN_OUT_OF_MEMORY
;
702 else if (ret
== WN_SUCCESS
)
703 lpNetWide
= (LPNETRESOURCEW
)buf
;
704 if (ret
== WN_SUCCESS
)
705 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
708 HeapFree(GetProcessHeap(), 0, lpNetWide
);
711 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
715 TRACE("Returning %d\n", ret
);
719 /*********************************************************************
720 * WNetOpenEnumW [MPR.@]
722 * Network enumeration has way too many parameters, so I'm not positive I got
723 * them right. What I've got so far:
725 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
726 * all the network providers should be enumerated.
728 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
729 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
730 * lpProvider is set, all the network providers should be enumerated.
731 * (This means the enumeration is a list of network providers, not that the
732 * enumeration is passed on to the providers.)
734 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
735 * resource matches the "Entire Network" resource (no remote name, no
736 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
737 * enumeration is done on every network provider.
739 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
740 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
741 * only to the given network provider.
743 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
744 * no lpProvider is set, enumeration will be tried on every network provider,
745 * in the order in which they're loaded.
747 * - The LPNETRESOURCE should be disregarded for scopes besides
748 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
749 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
751 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
752 * resource in the enumerated list, as well as any machines in your
753 * workgroup. The machines in your workgroup come from doing a
754 * RESOURCE_CONTEXT enumeration of every Network Provider.
756 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
757 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
761 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
762 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
765 ret
= WN_BAD_POINTER
;
766 else if (!providerTable
|| providerTable
->numProviders
== 0)
775 case RESOURCE_GLOBALNET
:
778 if (lpNet
->lpProvider
)
780 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
782 if (index
!= BAD_PROVIDER_INDEX
)
784 if (providerTable
->table
[index
].openEnum
&&
785 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
788 PWSTR RemoteName
= lpNet
->lpRemoteName
;
790 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
791 RemoteName
&& !strcmpW(RemoteName
, lpNet
->lpProvider
))
792 lpNet
->lpRemoteName
= NULL
;
794 ret
= providerTable
->table
[index
].openEnum(
795 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
796 if (ret
== WN_SUCCESS
)
798 *lphEnum
= _createProviderEnumerator(
799 dwScope
, dwType
, dwUsage
, index
, handle
);
800 ret
= *lphEnum
? WN_SUCCESS
:
804 lpNet
->lpRemoteName
= RemoteName
;
807 ret
= WN_NOT_SUPPORTED
;
810 ret
= WN_BAD_PROVIDER
;
812 else if (lpNet
->lpRemoteName
)
814 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
815 dwType
, dwUsage
, lpNet
);
816 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
820 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
821 providerTable
->entireNetwork
))
823 /* comment matches the "Entire Network", enumerate
824 * global scope of every provider
826 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
827 dwType
, dwUsage
, lpNet
);
831 /* this is the same as not having passed lpNet */
832 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
833 dwType
, dwUsage
, NULL
);
835 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
840 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
842 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
845 case RESOURCE_CONTEXT
:
846 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
847 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
849 case RESOURCE_CONNECTED
:
850 *lphEnum
= _createConnectedEnumerator(dwScope
, dwType
, dwUsage
);
851 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
853 case RESOURCE_REMEMBERED
:
854 *lphEnum
= _createNullEnumerator();
855 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
858 WARN("unknown scope 0x%08x\n", dwScope
);
864 TRACE("Returning %d\n", ret
);
868 /*********************************************************************
869 * WNetEnumResourceA [MPR.@]
871 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
872 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
876 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
879 ret
= WN_BAD_POINTER
;
881 ret
= WN_BAD_POINTER
;
883 ret
= WN_BAD_POINTER
;
884 else if (!lpBufferSize
)
885 ret
= WN_BAD_POINTER
;
886 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
888 *lpBufferSize
= sizeof(NETRESOURCEA
);
893 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
894 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
898 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
900 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
902 /* FIXME: this isn't necessarily going to work in the case of
903 * WN_MORE_DATA, because our enumerator may have moved on to
904 * the next provider. MSDN states that a large (16KB) buffer
905 * size is the appropriate usage of this function, so
906 * hopefully it won't be an issue.
908 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
909 lpBuffer
, lpBufferSize
);
910 *lpcCount
= localCount
;
912 HeapFree(GetProcessHeap(), 0, localBuffer
);
915 ret
= WN_OUT_OF_MEMORY
;
919 TRACE("Returning %d\n", ret
);
923 static DWORD
_countProviderBytesW(PWNetProvider provider
)
929 ret
= sizeof(NETRESOURCEW
);
930 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
937 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
938 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
943 return WN_BAD_POINTER
;
944 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
947 return WN_BAD_POINTER
;
949 return WN_BAD_POINTER
;
951 return WN_BAD_POINTER
;
952 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
955 if (!providerTable
|| enumerator
->providerIndex
>=
956 providerTable
->numProviders
)
957 ret
= WN_NO_MORE_ENTRIES
;
960 DWORD bytes
= 0, count
= 0, countLimit
, i
;
961 LPNETRESOURCEW resource
;
964 countLimit
= *lpcCount
== -1 ?
965 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
966 while (count
< countLimit
&& bytes
< *lpBufferSize
)
968 DWORD bytesNext
= _countProviderBytesW(
969 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
971 if (bytes
+ bytesNext
< *lpBufferSize
)
977 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
978 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
980 resource
->dwScope
= RESOURCE_GLOBALNET
;
981 resource
->dwType
= RESOURCETYPE_ANY
;
982 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
983 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
984 RESOURCEUSAGE_RESERVED
;
985 resource
->lpLocalName
= NULL
;
986 resource
->lpRemoteName
= strNext
;
987 strcpyW(resource
->lpRemoteName
,
988 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
989 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
990 resource
->lpComment
= NULL
;
991 resource
->lpProvider
= strNext
;
992 strcpyW(resource
->lpProvider
,
993 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
994 strNext
+= strlenW(resource
->lpProvider
) + 1;
996 enumerator
->providerIndex
+= count
;
998 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
1000 TRACE("Returning %d\n", ret
);
1004 /* Advances the enumerator (assumed to be a global enumerator) to the next
1005 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1006 * not open a handle with the next provider.
1007 * If the existing handle is NULL, may leave the enumerator unchanged, since
1008 * the current provider may support the desired scope.
1009 * If the existing handle is not NULL, closes it before moving on.
1010 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1011 * provider, and another error on failure.
1013 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
1016 return WN_BAD_POINTER
;
1017 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1018 return WN_BAD_VALUE
;
1019 if (!providerTable
|| enumerator
->providerIndex
>=
1020 providerTable
->numProviders
)
1021 return WN_NO_MORE_ENTRIES
;
1023 if (enumerator
->providerDone
)
1026 enumerator
->providerDone
= FALSE
;
1027 if (enumerator
->handle
)
1029 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1030 enumerator
->handle
);
1031 enumerator
->handle
= NULL
;
1032 enumerator
->providerIndex
++;
1034 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1035 dwEnum
= WNNC_ENUM_LOCAL
;
1036 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1037 dwEnum
= WNNC_ENUM_GLOBAL
;
1038 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1039 dwEnum
= WNNC_ENUM_CONTEXT
;
1040 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1041 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1042 & dwEnum
); enumerator
->providerIndex
++)
1045 return enumerator
->providerIndex
< providerTable
->numProviders
?
1046 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1049 /* "Passes through" call to the next provider that supports the enumeration
1051 * FIXME: if one call to a provider's enumerator succeeds while there's still
1052 * space in lpBuffer, I don't call to the next provider. The caller may not
1053 * expect that it should call EnumResourceW again with a return value of
1054 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1055 * may have to be moved around a bit, ick.
1057 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1058 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1063 return WN_BAD_POINTER
;
1064 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1065 return WN_BAD_VALUE
;
1067 return WN_BAD_POINTER
;
1069 return WN_BAD_POINTER
;
1071 return WN_BAD_POINTER
;
1072 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1073 return WN_MORE_DATA
;
1075 ret
= _globalEnumeratorAdvance(enumerator
);
1076 if (ret
== WN_SUCCESS
)
1078 ret
= providerTable
->table
[enumerator
->providerIndex
].
1079 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1080 enumerator
->dwUsage
, enumerator
->specific
.net
,
1081 &enumerator
->handle
);
1082 if (ret
== WN_SUCCESS
)
1084 ret
= providerTable
->table
[enumerator
->providerIndex
].
1085 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1087 if (ret
!= WN_MORE_DATA
)
1088 enumerator
->providerDone
= TRUE
;
1091 TRACE("Returning %d\n", ret
);
1095 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1096 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1101 return WN_BAD_POINTER
;
1102 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1103 return WN_BAD_VALUE
;
1105 return WN_BAD_POINTER
;
1107 return WN_BAD_POINTER
;
1109 return WN_BAD_POINTER
;
1110 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1111 return WN_MORE_DATA
;
1113 return WN_NO_NETWORK
;
1115 switch (enumerator
->dwScope
)
1117 case RESOURCE_GLOBALNET
:
1118 if (enumerator
->specific
.net
)
1119 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1120 lpBuffer
, lpBufferSize
);
1122 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1125 case RESOURCE_CONTEXT
:
1126 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1130 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1131 ret
= WN_NO_MORE_ENTRIES
;
1133 TRACE("Returning %d\n", ret
);
1137 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1138 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1141 return WN_BAD_POINTER
;
1142 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1143 return WN_BAD_VALUE
;
1144 if (!enumerator
->handle
)
1145 return WN_BAD_VALUE
;
1147 return WN_BAD_POINTER
;
1149 return WN_BAD_POINTER
;
1151 return WN_BAD_POINTER
;
1153 return WN_NO_NETWORK
;
1154 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1155 return WN_NO_MORE_ENTRIES
;
1156 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1157 return WN_BAD_VALUE
;
1158 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1159 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1162 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1163 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1166 size_t cchEntireNetworkLen
, bytesNeeded
;
1169 return WN_BAD_POINTER
;
1170 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1171 return WN_BAD_VALUE
;
1173 return WN_BAD_POINTER
;
1175 return WN_BAD_POINTER
;
1177 return WN_BAD_POINTER
;
1179 return WN_NO_NETWORK
;
1181 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1182 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1183 if (*lpBufferSize
< bytesNeeded
)
1185 *lpBufferSize
= bytesNeeded
;
1190 LPNETRESOURCEW lpNet
= lpBuffer
;
1192 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1193 lpNet
->dwType
= enumerator
->dwType
;
1194 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1195 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1196 lpNet
->lpLocalName
= NULL
;
1197 lpNet
->lpRemoteName
= NULL
;
1198 lpNet
->lpProvider
= NULL
;
1199 /* odd, but correct: put comment at end of buffer, so it won't get
1200 * overwritten by subsequent calls to a provider's enumResource
1202 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1203 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1204 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1207 if (ret
== WN_SUCCESS
)
1209 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1211 /* "Entire Network" entry enumerated--morph this into a global
1212 * enumerator. enumerator->lpNet continues to be NULL, since it has
1213 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1215 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1216 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1217 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1218 if (ret
== WN_SUCCESS
)
1220 /* reflect the fact that we already enumerated "Entire Network" */
1222 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1226 /* the provider enumeration failed, but we already succeeded in
1227 * enumerating "Entire Network"--leave type as global to allow a
1228 * retry, but indicate success with a count of one.
1232 *lpBufferSize
= bytesNeeded
;
1235 TRACE("Returning %d\n", ret
);
1239 static DWORD
_copyStringToEnumW(const WCHAR
*source
, DWORD
* left
, void** end
)
1242 WCHAR
* local
= *end
;
1244 len
= strlenW(source
) + 1;
1245 len
*= sizeof(WCHAR
);
1247 return WN_MORE_DATA
;
1249 local
-= (len
/ sizeof(WCHAR
));
1250 memcpy(local
, source
, len
);
1257 static DWORD
_enumerateConnectedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1258 void* user_buffer
, DWORD
* user_size
)
1260 DWORD ret
, index
, count
, size
, i
, left
;
1262 NETRESOURCEW
* curr
, * buffer
;
1266 return WN_BAD_POINTER
;
1267 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONNECTED
)
1268 return WN_BAD_VALUE
;
1269 if (!user_count
|| !user_buffer
|| !user_size
)
1270 return WN_BAD_POINTER
;
1272 return WN_NO_NETWORK
;
1274 handles
= enumerator
->specific
.handles
;
1277 buffer
= HeapAlloc(GetProcessHeap(), 0, *user_size
);
1279 return WN_NO_NETWORK
;
1282 end
= (char *)user_buffer
+ size
;
1283 count
= *user_count
;
1285 ret
= WN_NO_MORE_ENTRIES
;
1286 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1288 if (providerTable
->table
[index
].dwEnumScopes
)
1290 if (handles
[index
] == 0)
1292 ret
= providerTable
->table
[index
].openEnum(enumerator
->dwScope
,
1294 enumerator
->dwUsage
,
1295 NULL
, &handles
[index
]);
1296 if (ret
!= WN_SUCCESS
)
1300 ret
= providerTable
->table
[index
].enumResource(handles
[index
],
1303 if (ret
== WN_MORE_DATA
)
1306 if (ret
== WN_SUCCESS
)
1308 for (i
= 0; i
< count
; ++i
)
1310 if (left
< sizeof(NETRESOURCEW
))
1316 memcpy(curr
, &buffer
[i
], sizeof(NETRESOURCEW
));
1317 left
-= sizeof(NETRESOURCEW
);
1319 ret
= _copyStringToEnumW(buffer
[i
].lpLocalName
, &left
, &end
);
1320 if (ret
== WN_MORE_DATA
)
1322 curr
->lpLocalName
= end
;
1324 ret
= _copyStringToEnumW(buffer
[i
].lpRemoteName
, &left
, &end
);
1325 if (ret
== WN_MORE_DATA
)
1327 curr
->lpRemoteName
= end
;
1329 ret
= _copyStringToEnumW(buffer
[i
].lpProvider
, &left
, &end
);
1330 if (ret
== WN_MORE_DATA
)
1332 curr
->lpProvider
= end
;
1337 count
= *user_count
- count
;
1341 if (ret
!= WN_SUCCESS
|| count
== 0)
1347 ret
= WN_NO_MORE_ENTRIES
;
1349 *user_count
= *user_count
- count
;
1350 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1353 HeapFree(GetProcessHeap(), 0, buffer
);
1355 TRACE("Returning %d\n", ret
);
1359 /*********************************************************************
1360 * WNetEnumResourceW [MPR.@]
1362 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1363 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1367 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1370 ret
= WN_BAD_POINTER
;
1372 ret
= WN_BAD_POINTER
;
1374 ret
= WN_BAD_POINTER
;
1375 else if (!lpBufferSize
)
1376 ret
= WN_BAD_POINTER
;
1377 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1379 *lpBufferSize
= sizeof(NETRESOURCEW
);
1384 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1386 switch (enumerator
->enumType
)
1388 case WNET_ENUMERATOR_TYPE_NULL
:
1389 ret
= WN_NO_MORE_ENTRIES
;
1391 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1392 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1395 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1396 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1399 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1400 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1403 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1404 ret
= _enumerateConnectedW(enumerator
, lpcCount
, lpBuffer
,
1408 WARN("bogus enumerator type!\n");
1409 ret
= WN_NO_NETWORK
;
1414 TRACE("Returning %d\n", ret
);
1418 /*********************************************************************
1419 * WNetCloseEnum [MPR.@]
1421 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1426 TRACE( "(%p)\n", hEnum
);
1430 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1432 switch (enumerator
->enumType
)
1434 case WNET_ENUMERATOR_TYPE_NULL
:
1437 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1438 if (enumerator
->specific
.net
)
1439 _freeEnumNetResource(enumerator
->specific
.net
);
1440 if (enumerator
->handle
)
1441 providerTable
->table
[enumerator
->providerIndex
].
1442 closeEnum(enumerator
->handle
);
1445 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1446 if (enumerator
->handle
)
1447 providerTable
->table
[enumerator
->providerIndex
].
1448 closeEnum(enumerator
->handle
);
1451 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1452 handles
= enumerator
->specific
.handles
;
1453 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1455 if (providerTable
->table
[index
].dwEnumScopes
&& handles
[index
])
1456 providerTable
->table
[index
].closeEnum(handles
[index
]);
1458 HeapFree(GetProcessHeap(), 0, handles
);
1462 WARN("bogus enumerator type!\n");
1463 ret
= WN_BAD_HANDLE
;
1465 HeapFree(GetProcessHeap(), 0, hEnum
);
1468 ret
= WN_BAD_HANDLE
;
1471 TRACE("Returning %d\n", ret
);
1475 /*********************************************************************
1476 * WNetGetResourceInformationA [MPR.@]
1478 * See WNetGetResourceInformationW
1480 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1481 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1486 TRACE( "(%p, %p, %p, %p)\n",
1487 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1489 if (!providerTable
|| providerTable
->numProviders
== 0)
1490 ret
= WN_NO_NETWORK
;
1491 else if (lpNetResource
)
1493 LPNETRESOURCEW lpNetResourceW
= NULL
;
1494 DWORD size
= 1024, count
= 1;
1497 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1498 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1499 if (ret
== WN_MORE_DATA
)
1501 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1502 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1504 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1505 &count
, lpNetResourceW
, &size
);
1507 ret
= WN_OUT_OF_MEMORY
;
1509 if (ret
== WN_SUCCESS
)
1511 LPWSTR lpSystemW
= NULL
;
1514 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1517 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1518 lpBufferW
, &size
, &lpSystemW
);
1519 if (ret
== WN_MORE_DATA
)
1521 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1522 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1524 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1525 lpBufferW
, &size
, &lpSystemW
);
1527 ret
= WN_OUT_OF_MEMORY
;
1529 if (ret
== WN_SUCCESS
)
1531 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1532 &count
, lpBuffer
, cbBuffer
);
1533 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1534 lpNetResourceW
= lpBufferW
;
1535 size
= sizeof(NETRESOURCEA
);
1536 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1537 -1, NULL
, 0, NULL
, NULL
);
1538 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1539 -1, NULL
, 0, NULL
, NULL
);
1541 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1542 -1, NULL
, 0, NULL
, NULL
);
1543 if ((len
) && ( size
+ len
< *cbBuffer
))
1545 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1546 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1547 *lplpSystem
, len
, NULL
, NULL
);
1554 ret
= WN_OUT_OF_MEMORY
;
1555 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1558 ret
= WN_OUT_OF_MEMORY
;
1559 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1561 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1564 ret
= WN_NO_NETWORK
;
1568 TRACE("Returning %d\n", ret
);
1572 /*********************************************************************
1573 * WNetGetResourceInformationW [MPR.@]
1575 * WNetGetResourceInformationW function identifies the network provider
1576 * that owns the resource and gets information about the type of the resource.
1579 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1580 * defines a network resource.
1581 * lpBuffer [ O] the pointer to buffer, containing result. It
1582 * contains NETRESOURCEW structure and strings to
1583 * which the members of the NETRESOURCEW structure
1585 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1587 * lplpSystem [ O] the pointer to string in the output buffer,
1588 * containing the part of the resource name without
1589 * names of the server and share.
1592 * NO_ERROR if the function succeeds. System error code if the function fails.
1595 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1596 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1597 LPWSTR
*lplpSystem
)
1599 DWORD ret
= WN_NO_NETWORK
;
1602 TRACE( "(%p, %p, %p, %p)\n",
1603 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1606 ret
= WN_OUT_OF_MEMORY
;
1607 else if (providerTable
!= NULL
)
1609 /* FIXME: For function value of a variable is indifferent, it does
1610 * search of all providers in a network.
1612 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1614 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1615 WNNC_DLG_GETRESOURCEINFORMATION
)
1617 if (providerTable
->table
[index
].getResourceInformation
)
1618 ret
= providerTable
->table
[index
].getResourceInformation(
1619 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1621 ret
= WN_NO_NETWORK
;
1622 if (ret
== WN_SUCCESS
)
1632 /*********************************************************************
1633 * WNetGetResourceParentA [MPR.@]
1635 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1636 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1638 FIXME( "(%p, %p, %p): stub\n",
1639 lpNetResource
, lpBuffer
, lpBufferSize
);
1641 SetLastError(WN_NO_NETWORK
);
1642 return WN_NO_NETWORK
;
1645 /*********************************************************************
1646 * WNetGetResourceParentW [MPR.@]
1648 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1649 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1651 FIXME( "(%p, %p, %p): stub\n",
1652 lpNetResource
, lpBuffer
, lpBufferSize
);
1654 SetLastError(WN_NO_NETWORK
);
1655 return WN_NO_NETWORK
;
1661 * Connection Functions
1664 /*********************************************************************
1665 * WNetAddConnectionA [MPR.@]
1667 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1668 LPCSTR lpLocalName
)
1670 NETRESOURCEA resourcesA
;
1672 memset(&resourcesA
, 0, sizeof(resourcesA
));
1673 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
1674 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
1675 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1678 /*********************************************************************
1679 * WNetAddConnectionW [MPR.@]
1681 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1682 LPCWSTR lpLocalName
)
1684 NETRESOURCEW resourcesW
;
1686 memset(&resourcesW
, 0, sizeof(resourcesW
));
1687 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
1688 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
1689 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1692 /*********************************************************************
1693 * WNetAddConnection2A [MPR.@]
1695 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1696 LPCSTR lpPassword
, LPCSTR lpUserID
,
1699 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1703 /*********************************************************************
1704 * WNetAddConnection2W [MPR.@]
1706 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1707 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1710 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1714 /*********************************************************************
1715 * WNetAddConnection3A [MPR.@]
1717 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1718 LPCSTR lpPassword
, LPCSTR lpUserID
,
1721 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1722 dwFlags
, NULL
, 0, NULL
);
1725 /*********************************************************************
1726 * WNetAddConnection3W [MPR.@]
1728 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1729 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1732 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1733 dwFlags
, NULL
, 0, NULL
);
1736 struct use_connection_context
1739 NETRESOURCEW
*resource
;
1740 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
1747 DWORD (*pre_set_accessname
)(struct use_connection_context
*, WCHAR
*);
1748 void (*set_accessname
)(struct use_connection_context
*, WCHAR
*);
1751 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1753 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1758 len
= strlenW(local_name
);
1760 len
= strlenW(ctxt
->resource
->lpRemoteName
);
1762 if (++len
> *ctxt
->buffer_size
)
1764 *ctxt
->buffer_size
= len
;
1765 return ERROR_MORE_DATA
;
1769 ctxt
->accessname
= NULL
;
1771 return ERROR_SUCCESS
;
1774 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1776 WCHAR
*accessname
= ctxt
->accessname
;
1779 strcpyW(accessname
, local_name
);
1781 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1784 strcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
1787 static DWORD
wnet_use_provider( struct use_connection_context
*ctxt
, NETRESOURCEW
* netres
, WNetProvider
*provider
, BOOLEAN redirect
)
1791 caps
= provider
->getCaps(WNNC_CONNECTION
);
1792 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
1793 return ERROR_BAD_PROVIDER
;
1795 ret
= WN_ACCESS_DENIED
;
1798 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
1799 ret
= provider
->addConnection3(ctxt
->hwndOwner
, netres
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
1800 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
1801 ret
= provider
->addConnection(netres
, ctxt
->password
, ctxt
->userid
);
1803 if (ret
== WN_ALREADY_CONNECTED
&& redirect
)
1804 netres
->lpLocalName
[0] -= 1;
1805 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& netres
->lpLocalName
[0] >= 'C');
1807 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
1808 ctxt
->set_accessname(ctxt
, netres
->lpLocalName
);
1813 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
1815 WNetProvider
*provider
;
1816 DWORD index
, ret
= WN_NO_NETWORK
;
1817 BOOL redirect
= FALSE
;
1818 WCHAR letter
[3] = {'Z', ':', 0};
1819 NETRESOURCEW netres
;
1821 if (!providerTable
|| providerTable
->numProviders
== 0)
1822 return WN_NO_NETWORK
;
1824 if (!ctxt
->resource
)
1825 return ERROR_INVALID_PARAMETER
;
1826 netres
= *ctxt
->resource
;
1828 if (!netres
.lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
1830 if (netres
.dwType
!= RESOURCETYPE_DISK
&& netres
.dwType
!= RESOURCETYPE_PRINT
)
1831 return ERROR_BAD_DEV_TYPE
;
1833 if (netres
.dwType
== RESOURCETYPE_PRINT
)
1835 FIXME("Local device selection is not implemented for printers.\n");
1836 return WN_NO_NETWORK
;
1840 netres
.lpLocalName
= letter
;
1843 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
1844 return ERROR_BAD_NET_NAME
;
1846 if ((ret
= ctxt
->pre_set_accessname(ctxt
, netres
.lpLocalName
)))
1849 if (netres
.lpProvider
)
1851 index
= _findProviderIndexW(netres
.lpProvider
);
1852 if (index
== BAD_PROVIDER_INDEX
)
1853 return ERROR_BAD_PROVIDER
;
1855 provider
= &providerTable
->table
[index
];
1856 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
1860 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1862 provider
= &providerTable
->table
[index
];
1863 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
1864 if (ret
== WN_SUCCESS
|| ret
== WN_ALREADY_CONNECTED
)
1872 /*****************************************************************
1873 * WNetUseConnectionW [MPR.@]
1875 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
1876 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
1878 struct use_connection_context ctxt
;
1880 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1881 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
1882 accessname
, buffer_size
, result
);
1884 ctxt
.hwndOwner
= hwndOwner
;
1885 ctxt
.resource
= resource
;
1886 ctxt
.resourceA
= NULL
;
1887 ctxt
.password
= (WCHAR
*)password
;
1888 ctxt
.userid
= (WCHAR
*)userid
;
1890 ctxt
.accessname
= accessname
;
1891 ctxt
.buffer_size
= buffer_size
;
1892 ctxt
.result
= result
;
1893 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
1894 ctxt
.set_accessname
= use_connection_set_accessnameW
;
1896 return wnet_use_connection(&ctxt
);
1899 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1901 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1906 len
= WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, NULL
, 0, NULL
, NULL
) - 1;
1908 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
1910 if (++len
> *ctxt
->buffer_size
)
1912 *ctxt
->buffer_size
= len
;
1913 return ERROR_MORE_DATA
;
1917 ctxt
->accessname
= NULL
;
1919 return ERROR_SUCCESS
;
1922 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1924 char *accessname
= ctxt
->accessname
;
1927 WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, accessname
, *ctxt
->buffer_size
, NULL
, NULL
);
1929 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1932 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
1935 static LPWSTR
strdupAtoW( LPCSTR str
)
1940 if (!str
) return NULL
;
1941 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
1942 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1943 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
1947 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
1949 resourceW
->dwScope
= resourceA
->dwScope
;
1950 resourceW
->dwType
= resourceA
->dwType
;
1951 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
1952 resourceW
->dwUsage
= resourceA
->dwUsage
;
1953 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
1954 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
1955 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
1956 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
1959 static void free_netresourceW( NETRESOURCEW
*resource
)
1961 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
1962 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
1963 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
1964 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
1967 /*****************************************************************
1968 * WNetUseConnectionA [MPR.@]
1970 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
1971 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
1972 DWORD
*buffer_size
, DWORD
*result
)
1974 struct use_connection_context ctxt
;
1975 NETRESOURCEW resourceW
;
1978 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
1979 accessname
, buffer_size
, result
);
1981 netresource_a_to_w(resource
, &resourceW
);
1983 ctxt
.hwndOwner
= hwndOwner
;
1984 ctxt
.resource
= &resourceW
;
1985 ctxt
.resourceA
= resource
;
1986 ctxt
.password
= strdupAtoW(password
);
1987 ctxt
.userid
= strdupAtoW(userid
);
1989 ctxt
.accessname
= accessname
;
1990 ctxt
.buffer_size
= buffer_size
;
1991 ctxt
.result
= result
;
1992 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
1993 ctxt
.set_accessname
= use_connection_set_accessnameA
;
1995 ret
= wnet_use_connection(&ctxt
);
1997 free_netresourceW(&resourceW
);
1998 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
1999 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
2004 /*********************************************************************
2005 * WNetCancelConnectionA [MPR.@]
2007 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
2009 return WNetCancelConnection2A(lpName
, 0, fForce
);
2012 /*********************************************************************
2013 * WNetCancelConnectionW [MPR.@]
2015 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
2017 return WNetCancelConnection2W(lpName
, 0, fForce
);
2020 /*********************************************************************
2021 * WNetCancelConnection2A [MPR.@]
2023 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2026 WCHAR
* name
= strdupAtoW(lpName
);
2028 return ERROR_NOT_CONNECTED
;
2030 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
2031 HeapFree(GetProcessHeap(), 0, name
);
2036 /*********************************************************************
2037 * WNetCancelConnection2W [MPR.@]
2039 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2041 DWORD ret
= WN_NO_NETWORK
;
2044 if (providerTable
!= NULL
)
2046 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2048 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2049 WNNC_CON_CANCELCONNECTION
)
2051 if (providerTable
->table
[index
].cancelConnection
)
2052 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
2054 ret
= WN_NO_NETWORK
;
2055 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
2063 /*****************************************************************
2064 * WNetRestoreConnectionA [MPR.@]
2066 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
2068 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
2070 SetLastError(WN_NO_NETWORK
);
2071 return WN_NO_NETWORK
;
2074 /*****************************************************************
2075 * WNetRestoreConnectionW [MPR.@]
2077 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
2079 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
2081 SetLastError(WN_NO_NETWORK
);
2082 return WN_NO_NETWORK
;
2085 /**************************************************************************
2086 * WNetGetConnectionA [MPR.@]
2089 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2090 * - WN_NOT_CONNECTED drive is a local drive
2091 * - WN_MORE_DATA buffer isn't big enough
2092 * - WN_SUCCESS success (net path in buffer)
2094 * FIXME: need to test return values under different errors
2096 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
2097 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
2102 ret
= WN_BAD_POINTER
;
2103 else if (!lpBufferSize
)
2104 ret
= WN_BAD_POINTER
;
2105 else if (!lpRemoteName
&& *lpBufferSize
)
2106 ret
= WN_BAD_POINTER
;
2109 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
2113 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2117 WCHAR wideRemoteStatic
[MAX_PATH
];
2118 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
2120 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
2122 /* try once without memory allocation */
2123 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
2125 if (ret
== WN_SUCCESS
)
2127 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2128 -1, NULL
, 0, NULL
, NULL
);
2130 if (len
<= *lpBufferSize
)
2132 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
2133 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2138 *lpBufferSize
= len
;
2142 else if (ret
== WN_MORE_DATA
)
2144 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2145 wideRemoteSize
* sizeof(WCHAR
));
2149 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2151 if (ret
== WN_SUCCESS
)
2153 if (len
<= *lpBufferSize
)
2155 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2156 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2161 *lpBufferSize
= len
;
2165 HeapFree(GetProcessHeap(), 0, wideRemote
);
2168 ret
= WN_OUT_OF_MEMORY
;
2170 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2173 ret
= WN_OUT_OF_MEMORY
;
2176 ret
= WN_BAD_LOCALNAME
;
2180 TRACE("Returning %d\n", ret
);
2184 /* find the network connection for a given drive; helper for WNetGetConnection */
2185 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2189 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2191 DWORD ret
= WN_NOT_CONNECTED
;
2192 DWORD bytes_returned
;
2194 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2195 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2196 0, 0 )) == INVALID_HANDLE_VALUE
)
2198 ERR( "failed to open mount manager err %u\n", GetLastError() );
2201 memset( data
, 0, sizeof(*data
) );
2202 data
->letter
= letter
;
2203 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2204 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2206 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2209 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2212 mount_point
[0] = '\\';
2213 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2215 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2223 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2231 DWORD ret
= WN_NO_NETWORK
;
2233 WCHAR local
[3] = {letter
, ':', 0};
2235 if (providerTable
!= NULL
)
2237 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2239 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2240 WNNC_CON_GETCONNECTIONS
)
2242 if (providerTable
->table
[index
].getConnection
)
2243 ret
= providerTable
->table
[index
].getConnection(
2244 local
, remote
, size
);
2246 ret
= WN_NO_NETWORK
;
2247 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2258 /**************************************************************************
2259 * WNetGetConnectionW [MPR.@]
2261 * FIXME: need to test return values under different errors
2263 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2264 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2268 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2272 ret
= WN_BAD_POINTER
;
2273 else if (!lpBufferSize
)
2274 ret
= WN_BAD_POINTER
;
2275 else if (!lpRemoteName
&& *lpBufferSize
)
2276 ret
= WN_BAD_POINTER
;
2277 else if (!lpLocalName
[0])
2278 ret
= WN_BAD_LOCALNAME
;
2281 if (lpLocalName
[1] == ':')
2283 switch(GetDriveTypeW(lpLocalName
))
2286 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2288 case DRIVE_REMOVABLE
:
2291 TRACE("file is local\n");
2292 ret
= WN_NOT_CONNECTED
;
2295 ret
= WN_BAD_LOCALNAME
;
2299 ret
= WN_BAD_LOCALNAME
;
2303 TRACE("Returning %d\n", ret
);
2307 /**************************************************************************
2308 * WNetSetConnectionA [MPR.@]
2310 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2313 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2315 SetLastError(WN_NO_NETWORK
);
2316 return WN_NO_NETWORK
;
2319 /**************************************************************************
2320 * WNetSetConnectionW [MPR.@]
2322 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2325 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2327 SetLastError(WN_NO_NETWORK
);
2328 return WN_NO_NETWORK
;
2331 /*****************************************************************
2332 * WNetGetUniversalNameA [MPR.@]
2334 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2335 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2339 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2340 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2342 switch (dwInfoLevel
)
2344 case UNIVERSAL_NAME_INFO_LEVEL
:
2346 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2348 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2350 err
= ERROR_NOT_CONNECTED
;
2354 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2355 if (*lpBufferSize
< size
)
2360 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2361 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2365 case REMOTE_NAME_INFO_LEVEL
:
2366 err
= WN_NOT_CONNECTED
;
2378 /*****************************************************************
2379 * WNetGetUniversalNameW [MPR.@]
2381 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2382 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2386 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2387 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2389 switch (dwInfoLevel
)
2391 case UNIVERSAL_NAME_INFO_LEVEL
:
2393 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2395 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2397 err
= ERROR_NOT_CONNECTED
;
2401 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2402 if (*lpBufferSize
< size
)
2407 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2408 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2412 case REMOTE_NAME_INFO_LEVEL
:
2413 err
= WN_NO_NETWORK
;
2421 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2431 /**************************************************************************
2432 * WNetGetUserA [MPR.@]
2434 * FIXME: we should not return ourselves, but the owner of the drive lpName
2436 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2438 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2439 return GetLastError();
2442 /*****************************************************************
2443 * WNetGetUserW [MPR.@]
2445 * FIXME: we should not return ourselves, but the owner of the drive lpName
2447 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2449 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2450 return GetLastError();
2453 /*********************************************************************
2454 * WNetConnectionDialog [MPR.@]
2456 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2458 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2460 SetLastError(WN_NO_NETWORK
);
2461 return WN_NO_NETWORK
;
2464 /*********************************************************************
2465 * WNetConnectionDialog1A [MPR.@]
2467 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2469 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2471 SetLastError(WN_NO_NETWORK
);
2472 return WN_NO_NETWORK
;
2475 /*********************************************************************
2476 * WNetConnectionDialog1W [MPR.@]
2478 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2480 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2482 SetLastError(WN_NO_NETWORK
);
2483 return WN_NO_NETWORK
;
2486 /*********************************************************************
2487 * WNetDisconnectDialog [MPR.@]
2489 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2491 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2493 SetLastError(WN_NO_NETWORK
);
2494 return WN_NO_NETWORK
;
2497 /*********************************************************************
2498 * WNetDisconnectDialog1A [MPR.@]
2500 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2502 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2504 SetLastError(WN_NO_NETWORK
);
2505 return WN_NO_NETWORK
;
2508 /*********************************************************************
2509 * WNetDisconnectDialog1W [MPR.@]
2511 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2513 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2515 SetLastError(WN_NO_NETWORK
);
2516 return WN_NO_NETWORK
;
2519 /*********************************************************************
2520 * WNetGetLastErrorA [MPR.@]
2522 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2523 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2524 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2526 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2527 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2529 SetLastError(WN_NO_NETWORK
);
2530 return WN_NO_NETWORK
;
2533 /*********************************************************************
2534 * WNetGetLastErrorW [MPR.@]
2536 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2537 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2538 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2540 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2541 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2543 SetLastError(WN_NO_NETWORK
);
2544 return WN_NO_NETWORK
;
2547 /*********************************************************************
2548 * WNetGetNetworkInformationA [MPR.@]
2550 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2551 LPNETINFOSTRUCT lpNetInfoStruct
)
2555 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2558 ret
= WN_BAD_POINTER
;
2563 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2566 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2570 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2572 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2573 HeapFree(GetProcessHeap(), 0, wideProvider
);
2576 ret
= WN_OUT_OF_MEMORY
;
2579 ret
= GetLastError();
2583 TRACE("Returning %d\n", ret
);
2587 /*********************************************************************
2588 * WNetGetNetworkInformationW [MPR.@]
2590 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2591 LPNETINFOSTRUCT lpNetInfoStruct
)
2595 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2598 ret
= WN_BAD_POINTER
;
2599 else if (!lpNetInfoStruct
)
2600 ret
= WN_BAD_POINTER
;
2601 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2605 if (providerTable
&& providerTable
->numProviders
)
2607 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2609 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2611 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2612 lpNetInfoStruct
->dwProviderVersion
=
2613 providerTable
->table
[providerIndex
].dwSpecVersion
;
2614 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2615 lpNetInfoStruct
->dwCharacteristics
= 0;
2616 lpNetInfoStruct
->dwHandle
= 0;
2617 lpNetInfoStruct
->wNetType
=
2618 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2619 lpNetInfoStruct
->dwPrinters
= -1;
2620 lpNetInfoStruct
->dwDrives
= -1;
2624 ret
= WN_BAD_PROVIDER
;
2627 ret
= WN_NO_NETWORK
;
2631 TRACE("Returning %d\n", ret
);
2635 /*****************************************************************
2636 * WNetGetProviderNameA [MPR.@]
2638 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2639 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2643 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2647 ret
= WN_BAD_POINTER
;
2648 else if (!lpBufferSize
)
2649 ret
= WN_BAD_POINTER
;
2656 ret
= WN_NO_NETWORK
;
2657 for (i
= 0; i
< providerTable
->numProviders
&&
2658 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2661 if (i
< providerTable
->numProviders
)
2663 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2664 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2666 if (*lpBufferSize
< sizeNeeded
)
2668 *lpBufferSize
= sizeNeeded
;
2673 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2674 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2676 /* FIXME: is *lpBufferSize set to the number of characters
2682 ret
= WN_NO_NETWORK
;
2686 TRACE("Returning %d\n", ret
);
2690 /*****************************************************************
2691 * WNetGetProviderNameW [MPR.@]
2693 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2694 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2698 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2702 ret
= WN_BAD_POINTER
;
2703 else if (!lpBufferSize
)
2704 ret
= WN_BAD_POINTER
;
2711 ret
= WN_NO_NETWORK
;
2712 for (i
= 0; i
< providerTable
->numProviders
&&
2713 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2716 if (i
< providerTable
->numProviders
)
2718 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2720 if (*lpBufferSize
< sizeNeeded
)
2722 *lpBufferSize
= sizeNeeded
;
2727 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2729 /* FIXME: is *lpBufferSize set to the number of characters
2735 ret
= WN_NO_NETWORK
;
2739 TRACE("Returning %d\n", ret
);