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
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_NULL 0
74 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
75 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
76 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
77 #define WNET_ENUMERATOR_TYPE_CONNECTED 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 'null' enumeration, one that contains no members
82 * - a global enumeration, one that's executed across all providers
83 * - a provider-specific enumeration, one that's only executed by a single
85 * - a context enumeration. I know this contradicts what I just said about
86 * there being no correspondence between the scope and the type, but it's
87 * necessary for the special case that a "Entire Network" entry needs to
88 * be enumerated in an enumeration of the context scope. Thus an enumeration
89 * of the context scope results in a context type enumerator, which morphs
90 * into a global enumeration (so the enumeration continues across all
93 typedef struct _WNetEnumerator
107 } WNetEnumerator
, *PWNetEnumerator
;
109 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
111 /* Returns an index (into the global WNetProviderTable) of the provider with
112 * the given name, or BAD_PROVIDER_INDEX if not found.
114 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
116 static PWNetProviderTable providerTable
;
119 * Global provider table functions
122 static void _tryLoadProvider(PCWSTR provider
)
124 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
125 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
126 'S','e','r','v','i','c','e','s','\\',0 };
127 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
128 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
129 WCHAR serviceName
[MAX_PATH
];
132 TRACE("%s\n", debugstr_w(provider
));
133 snprintfW(serviceName
, sizeof(serviceName
) / sizeof(WCHAR
), serviceFmt
,
134 servicePrefix
, provider
);
135 serviceName
[sizeof(serviceName
) / sizeof(WCHAR
) - 1] = '\0';
136 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
139 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
141 WCHAR providerPath
[MAX_PATH
];
142 DWORD type
, size
= sizeof(providerPath
);
144 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
145 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
147 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
150 if (type
== REG_EXPAND_SZ
)
152 WCHAR path
[MAX_PATH
];
153 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
157 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
160 name
= HeapAlloc(GetProcessHeap(), 0, size
);
161 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
162 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
164 HeapFree(GetProcessHeap(), 0, name
);
170 HMODULE hLib
= LoadLibraryW(providerPath
);
174 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
176 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
178 TRACE("loaded lib %p\n", hLib
);
182 PWNetProvider provider
=
183 &providerTable
->table
[providerTable
->numProviders
];
185 provider
->hLib
= hLib
;
186 provider
->name
= name
;
187 TRACE("name is %s\n", debugstr_w(name
));
188 provider
->getCaps
= getCaps
;
189 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
190 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
191 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
192 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
193 if (provider
->dwEnumScopes
)
195 TRACE("supports enumeration\n");
196 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
197 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
198 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
199 TRACE("NPEnumResource %p\n", provider
->enumResource
);
200 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
201 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
202 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
203 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
204 if (!provider
->openEnum
||
205 !provider
->enumResource
||
206 !provider
->closeEnum
)
208 provider
->openEnum
= NULL
;
209 provider
->enumResource
= NULL
;
210 provider
->closeEnum
= NULL
;
211 provider
->dwEnumScopes
= 0;
212 WARN("Couldn't load enumeration functions\n");
215 connectCap
= getCaps(WNNC_CONNECTION
);
216 if (connectCap
& WNNC_CON_ADDCONNECTION
)
217 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
218 if (connectCap
& WNNC_CON_ADDCONNECTION3
)
219 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
220 if (connectCap
& WNNC_CON_CANCELCONNECTION
)
221 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
222 TRACE("NPAddConnection %p\n", provider
->addConnection
);
223 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
224 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
225 providerTable
->numProviders
++;
229 WARN("Provider %s didn't export NPGetCaps\n",
230 debugstr_w(provider
));
231 HeapFree(GetProcessHeap(), 0, name
);
239 WARN("Couldn't load library %s for provider %s\n",
240 debugstr_w(providerPath
), debugstr_w(provider
));
241 HeapFree(GetProcessHeap(), 0, name
);
246 WARN("Couldn't get provider name for provider %s\n",
247 debugstr_w(provider
));
251 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
255 WARN("Couldn't open service key for provider %s\n",
256 debugstr_w(provider
));
259 void wnetInit(HINSTANCE hInstDll
)
261 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
262 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
263 'C','o','n','t','r','o','l','\\',
264 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
265 'O','r','d','e','r',0 };
266 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
267 'O','r','d','e','r',0 };
270 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
275 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
278 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
284 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
285 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
290 TRACE("provider order is %s\n", debugstr_w(providers
));
291 /* first count commas as a heuristic for how many to
292 * allocate space for */
293 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
295 ptr
= strchrW(ptr
, ',');
302 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
303 sizeof(WNetProviderTable
)
304 + (numToAllocate
- 1) * sizeof(WNetProvider
));
308 int entireNetworkLen
;
309 LPCWSTR stringresource
;
311 entireNetworkLen
= LoadStringW(hInstDll
,
312 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
313 providerTable
->entireNetwork
= HeapAlloc(
314 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
316 if (providerTable
->entireNetwork
)
318 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
319 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
321 providerTable
->numAllocated
= numToAllocate
;
322 for (ptr
= providers
; ptr
; )
325 ptr
= strchrW(ptr
, ',');
328 _tryLoadProvider(ptrPrev
);
332 HeapFree(GetProcessHeap(), 0, providers
);
345 for (i
= 0; i
< providerTable
->numProviders
; i
++)
347 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
348 FreeModule(providerTable
->table
[i
].hLib
);
350 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
351 HeapFree(GetProcessHeap(), 0, providerTable
);
352 providerTable
= NULL
;
356 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
358 DWORD ret
= BAD_PROVIDER_INDEX
;
360 if (providerTable
&& providerTable
->numProviders
)
364 for (i
= 0; i
< providerTable
->numProviders
&&
365 ret
== BAD_PROVIDER_INDEX
; i
++)
366 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
376 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
382 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
388 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
389 if (lpNet
->lpRemoteName
)
391 len
= strlenW(lpNet
->lpRemoteName
) + 1;
392 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
393 if (ret
->lpRemoteName
)
394 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
403 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
407 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
408 HeapFree(GetProcessHeap(), 0, lpNet
);
412 static PWNetEnumerator
_createNullEnumerator(void)
414 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
415 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
418 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
422 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
423 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
425 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
426 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
430 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
431 ret
->dwScope
= dwScope
;
432 ret
->dwType
= dwType
;
433 ret
->dwUsage
= dwUsage
;
434 ret
->specific
.net
= _copyNetResourceForEnumW(lpNet
);
439 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
440 DWORD dwUsage
, DWORD index
, HANDLE handle
)
444 if (!providerTable
|| index
>= providerTable
->numProviders
)
448 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
451 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
452 ret
->providerIndex
= index
;
453 ret
->dwScope
= dwScope
;
454 ret
->dwType
= dwType
;
455 ret
->dwUsage
= dwUsage
;
456 ret
->handle
= handle
;
462 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
465 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
466 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
470 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
471 ret
->dwScope
= dwScope
;
472 ret
->dwType
= dwType
;
473 ret
->dwUsage
= dwUsage
;
478 static PWNetEnumerator
_createConnectedEnumerator(DWORD dwScope
, DWORD dwType
,
481 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
484 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONNECTED
;
485 ret
->dwScope
= dwScope
;
486 ret
->dwType
= dwType
;
487 ret
->dwUsage
= dwUsage
;
488 ret
->specific
.handles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HANDLE
) * providerTable
->numProviders
);
489 if (!ret
->specific
.handles
)
491 HeapFree(GetProcessHeap(), 0, ret
);
498 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
499 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
500 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
501 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
502 * if not all members of the array could be thunked, and something else on
505 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
506 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
508 DWORD i
, numToThunk
, totalBytes
, ret
;
512 return WN_BAD_POINTER
;
514 return WN_BAD_POINTER
;
518 return WN_BAD_POINTER
;
520 return WN_BAD_POINTER
;
522 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
524 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
526 totalBytes
+= sizeof(NETRESOURCEA
);
527 if (lpNet
->lpLocalName
)
528 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
529 -1, NULL
, 0, NULL
, NULL
);
530 if (lpNet
->lpRemoteName
)
531 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
532 -1, NULL
, 0, NULL
, NULL
);
533 if (lpNet
->lpComment
)
534 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
535 -1, NULL
, 0, NULL
, NULL
);
536 if (lpNet
->lpProvider
)
537 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
538 -1, NULL
, 0, NULL
, NULL
);
539 if (totalBytes
< *lpBufferSize
)
542 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
543 for (i
= 0; i
< numToThunk
; i
++)
545 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
546 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
548 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
549 /* lie about string lengths, we already verified how many
550 * we have space for above
552 if (lpNetIn
->lpLocalName
)
554 lpNetOut
->lpLocalName
= strNext
;
555 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
556 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
558 if (lpNetIn
->lpRemoteName
)
560 lpNetOut
->lpRemoteName
= strNext
;
561 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
562 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
564 if (lpNetIn
->lpComment
)
566 lpNetOut
->lpComment
= strNext
;
567 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
568 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
570 if (lpNetIn
->lpProvider
)
572 lpNetOut
->lpProvider
= strNext
;
573 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
574 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
577 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
578 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
583 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
584 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
585 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
586 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
587 * if not all members of the array could be thunked, and something else on
590 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
591 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
593 DWORD i
, numToThunk
, totalBytes
, ret
;
597 return WN_BAD_POINTER
;
599 return WN_BAD_POINTER
;
603 return WN_BAD_POINTER
;
605 return WN_BAD_POINTER
;
607 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
609 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
611 totalBytes
+= sizeof(NETRESOURCEW
);
612 if (lpNet
->lpLocalName
)
613 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
614 -1, NULL
, 0) * sizeof(WCHAR
);
615 if (lpNet
->lpRemoteName
)
616 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
617 -1, NULL
, 0) * sizeof(WCHAR
);
618 if (lpNet
->lpComment
)
619 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
620 -1, NULL
, 0) * sizeof(WCHAR
);
621 if (lpNet
->lpProvider
)
622 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
623 -1, NULL
, 0) * sizeof(WCHAR
);
624 if (totalBytes
< *lpBufferSize
)
627 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
628 for (i
= 0; i
< numToThunk
; i
++)
630 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
631 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
633 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
634 /* lie about string lengths, we already verified how many
635 * we have space for above
637 if (lpNetIn
->lpLocalName
)
639 lpNetOut
->lpLocalName
= strNext
;
640 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
641 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
643 if (lpNetIn
->lpRemoteName
)
645 lpNetOut
->lpRemoteName
= strNext
;
646 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
647 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
649 if (lpNetIn
->lpComment
)
651 lpNetOut
->lpComment
= strNext
;
652 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
653 -1, lpNetOut
->lpComment
, *lpBufferSize
);
655 if (lpNetIn
->lpProvider
)
657 lpNetOut
->lpProvider
= strNext
;
658 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
659 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
662 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
663 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
668 /*********************************************************************
669 * WNetOpenEnumA [MPR.@]
671 * See comments for WNetOpenEnumW.
673 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
674 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
678 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
679 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
682 ret
= WN_BAD_POINTER
;
683 else if (!providerTable
|| providerTable
->numProviders
== 0)
692 LPNETRESOURCEW lpNetWide
= NULL
;
694 DWORD size
= sizeof(buf
), count
= 1;
695 BOOL allocated
= FALSE
;
697 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
698 if (ret
== WN_MORE_DATA
)
700 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
704 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
709 ret
= WN_OUT_OF_MEMORY
;
711 else if (ret
== WN_SUCCESS
)
712 lpNetWide
= (LPNETRESOURCEW
)buf
;
713 if (ret
== WN_SUCCESS
)
714 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
717 HeapFree(GetProcessHeap(), 0, lpNetWide
);
720 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
724 TRACE("Returning %d\n", ret
);
728 /*********************************************************************
729 * WNetOpenEnumW [MPR.@]
731 * Network enumeration has way too many parameters, so I'm not positive I got
732 * them right. What I've got so far:
734 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
735 * all the network providers should be enumerated.
737 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
738 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
739 * lpProvider is set, all the network providers should be enumerated.
740 * (This means the enumeration is a list of network providers, not that the
741 * enumeration is passed on to the providers.)
743 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
744 * resource matches the "Entire Network" resource (no remote name, no
745 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
746 * enumeration is done on every network provider.
748 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
749 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
750 * only to the given network provider.
752 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
753 * no lpProvider is set, enumeration will be tried on every network provider,
754 * in the order in which they're loaded.
756 * - The LPNETRESOURCE should be disregarded for scopes besides
757 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
758 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
760 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
761 * resource in the enumerated list, as well as any machines in your
762 * workgroup. The machines in your workgroup come from doing a
763 * RESOURCE_CONTEXT enumeration of every Network Provider.
765 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
766 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
770 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
771 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
774 ret
= WN_BAD_POINTER
;
775 else if (!providerTable
|| providerTable
->numProviders
== 0)
784 case RESOURCE_GLOBALNET
:
787 if (lpNet
->lpProvider
)
789 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
791 if (index
!= BAD_PROVIDER_INDEX
)
793 if (providerTable
->table
[index
].openEnum
&&
794 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
797 PWSTR RemoteName
= lpNet
->lpRemoteName
;
799 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
800 RemoteName
&& !strcmpW(RemoteName
, lpNet
->lpProvider
))
801 lpNet
->lpRemoteName
= NULL
;
803 ret
= providerTable
->table
[index
].openEnum(
804 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
805 if (ret
== WN_SUCCESS
)
807 *lphEnum
= _createProviderEnumerator(
808 dwScope
, dwType
, dwUsage
, index
, handle
);
809 ret
= *lphEnum
? WN_SUCCESS
:
813 lpNet
->lpRemoteName
= RemoteName
;
816 ret
= WN_NOT_SUPPORTED
;
819 ret
= WN_BAD_PROVIDER
;
821 else if (lpNet
->lpRemoteName
)
823 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
824 dwType
, dwUsage
, lpNet
);
825 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
829 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
830 providerTable
->entireNetwork
))
832 /* comment matches the "Entire Network", enumerate
833 * global scope of every provider
835 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
836 dwType
, dwUsage
, lpNet
);
840 /* this is the same as not having passed lpNet */
841 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
842 dwType
, dwUsage
, NULL
);
844 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
849 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
851 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
854 case RESOURCE_CONTEXT
:
855 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
856 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
858 case RESOURCE_CONNECTED
:
859 *lphEnum
= _createConnectedEnumerator(dwScope
, dwType
, dwUsage
);
860 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
862 case RESOURCE_REMEMBERED
:
863 *lphEnum
= _createNullEnumerator();
864 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
867 WARN("unknown scope 0x%08x\n", dwScope
);
873 TRACE("Returning %d\n", ret
);
877 /*********************************************************************
878 * WNetEnumResourceA [MPR.@]
880 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
881 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
885 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
888 ret
= WN_BAD_POINTER
;
890 ret
= WN_BAD_POINTER
;
892 ret
= WN_BAD_POINTER
;
893 else if (!lpBufferSize
)
894 ret
= WN_BAD_POINTER
;
895 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
897 *lpBufferSize
= sizeof(NETRESOURCEA
);
902 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
903 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
907 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
909 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
911 /* FIXME: this isn't necessarily going to work in the case of
912 * WN_MORE_DATA, because our enumerator may have moved on to
913 * the next provider. MSDN states that a large (16KB) buffer
914 * size is the appropriate usage of this function, so
915 * hopefully it won't be an issue.
917 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
918 lpBuffer
, lpBufferSize
);
919 *lpcCount
= localCount
;
921 HeapFree(GetProcessHeap(), 0, localBuffer
);
924 ret
= WN_OUT_OF_MEMORY
;
928 TRACE("Returning %d\n", ret
);
932 static DWORD
_countProviderBytesW(PWNetProvider provider
)
938 ret
= sizeof(NETRESOURCEW
);
939 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
946 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
947 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
952 return WN_BAD_POINTER
;
953 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
956 return WN_BAD_POINTER
;
958 return WN_BAD_POINTER
;
960 return WN_BAD_POINTER
;
961 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
964 if (!providerTable
|| enumerator
->providerIndex
>=
965 providerTable
->numProviders
)
966 ret
= WN_NO_MORE_ENTRIES
;
969 DWORD bytes
= 0, count
= 0, countLimit
, i
;
970 LPNETRESOURCEW resource
;
973 countLimit
= *lpcCount
== -1 ?
974 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
975 while (count
< countLimit
&& bytes
< *lpBufferSize
)
977 DWORD bytesNext
= _countProviderBytesW(
978 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
980 if (bytes
+ bytesNext
< *lpBufferSize
)
986 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
987 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
989 resource
->dwScope
= RESOURCE_GLOBALNET
;
990 resource
->dwType
= RESOURCETYPE_ANY
;
991 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
992 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
993 RESOURCEUSAGE_RESERVED
;
994 resource
->lpLocalName
= NULL
;
995 resource
->lpRemoteName
= strNext
;
996 strcpyW(resource
->lpRemoteName
,
997 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
998 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
999 resource
->lpComment
= NULL
;
1000 resource
->lpProvider
= strNext
;
1001 strcpyW(resource
->lpProvider
,
1002 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1003 strNext
+= strlenW(resource
->lpProvider
) + 1;
1005 enumerator
->providerIndex
+= count
;
1007 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
1009 TRACE("Returning %d\n", ret
);
1013 /* Advances the enumerator (assumed to be a global enumerator) to the next
1014 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1015 * not open a handle with the next provider.
1016 * If the existing handle is NULL, may leave the enumerator unchanged, since
1017 * the current provider may support the desired scope.
1018 * If the existing handle is not NULL, closes it before moving on.
1019 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1020 * provider, and another error on failure.
1022 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
1025 return WN_BAD_POINTER
;
1026 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1027 return WN_BAD_VALUE
;
1028 if (!providerTable
|| enumerator
->providerIndex
>=
1029 providerTable
->numProviders
)
1030 return WN_NO_MORE_ENTRIES
;
1032 if (enumerator
->providerDone
)
1035 enumerator
->providerDone
= FALSE
;
1036 if (enumerator
->handle
)
1038 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1039 enumerator
->handle
);
1040 enumerator
->handle
= NULL
;
1041 enumerator
->providerIndex
++;
1043 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1044 dwEnum
= WNNC_ENUM_LOCAL
;
1045 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1046 dwEnum
= WNNC_ENUM_GLOBAL
;
1047 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1048 dwEnum
= WNNC_ENUM_CONTEXT
;
1049 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1050 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1051 & dwEnum
); enumerator
->providerIndex
++)
1054 return enumerator
->providerIndex
< providerTable
->numProviders
?
1055 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1058 /* "Passes through" call to the next provider that supports the enumeration
1060 * FIXME: if one call to a provider's enumerator succeeds while there's still
1061 * space in lpBuffer, I don't call to the next provider. The caller may not
1062 * expect that it should call EnumResourceW again with a return value of
1063 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1064 * may have to be moved around a bit, ick.
1066 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1067 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1072 return WN_BAD_POINTER
;
1073 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1074 return WN_BAD_VALUE
;
1076 return WN_BAD_POINTER
;
1078 return WN_BAD_POINTER
;
1080 return WN_BAD_POINTER
;
1081 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1082 return WN_MORE_DATA
;
1084 ret
= _globalEnumeratorAdvance(enumerator
);
1085 if (ret
== WN_SUCCESS
)
1087 ret
= providerTable
->table
[enumerator
->providerIndex
].
1088 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1089 enumerator
->dwUsage
, enumerator
->specific
.net
,
1090 &enumerator
->handle
);
1091 if (ret
== WN_SUCCESS
)
1093 ret
= providerTable
->table
[enumerator
->providerIndex
].
1094 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1096 if (ret
!= WN_MORE_DATA
)
1097 enumerator
->providerDone
= TRUE
;
1100 TRACE("Returning %d\n", ret
);
1104 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1105 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1110 return WN_BAD_POINTER
;
1111 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1112 return WN_BAD_VALUE
;
1114 return WN_BAD_POINTER
;
1116 return WN_BAD_POINTER
;
1118 return WN_BAD_POINTER
;
1119 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1120 return WN_MORE_DATA
;
1122 return WN_NO_NETWORK
;
1124 switch (enumerator
->dwScope
)
1126 case RESOURCE_GLOBALNET
:
1127 if (enumerator
->specific
.net
)
1128 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1129 lpBuffer
, lpBufferSize
);
1131 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1134 case RESOURCE_CONTEXT
:
1135 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1139 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1140 ret
= WN_NO_MORE_ENTRIES
;
1142 TRACE("Returning %d\n", ret
);
1146 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1147 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1150 return WN_BAD_POINTER
;
1151 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1152 return WN_BAD_VALUE
;
1153 if (!enumerator
->handle
)
1154 return WN_BAD_VALUE
;
1156 return WN_BAD_POINTER
;
1158 return WN_BAD_POINTER
;
1160 return WN_BAD_POINTER
;
1162 return WN_NO_NETWORK
;
1163 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1164 return WN_NO_MORE_ENTRIES
;
1165 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1166 return WN_BAD_VALUE
;
1167 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1168 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1171 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1172 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1175 size_t cchEntireNetworkLen
, bytesNeeded
;
1178 return WN_BAD_POINTER
;
1179 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1180 return WN_BAD_VALUE
;
1182 return WN_BAD_POINTER
;
1184 return WN_BAD_POINTER
;
1186 return WN_BAD_POINTER
;
1188 return WN_NO_NETWORK
;
1190 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1191 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1192 if (*lpBufferSize
< bytesNeeded
)
1194 *lpBufferSize
= bytesNeeded
;
1199 LPNETRESOURCEW lpNet
= lpBuffer
;
1201 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1202 lpNet
->dwType
= enumerator
->dwType
;
1203 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1204 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1205 lpNet
->lpLocalName
= NULL
;
1206 lpNet
->lpRemoteName
= NULL
;
1207 lpNet
->lpProvider
= NULL
;
1208 /* odd, but correct: put comment at end of buffer, so it won't get
1209 * overwritten by subsequent calls to a provider's enumResource
1211 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1212 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1213 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1216 if (ret
== WN_SUCCESS
)
1218 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1220 /* "Entire Network" entry enumerated--morph this into a global
1221 * enumerator. enumerator->lpNet continues to be NULL, since it has
1222 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1224 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1225 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1226 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1227 if (ret
== WN_SUCCESS
)
1229 /* reflect the fact that we already enumerated "Entire Network" */
1231 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1235 /* the provider enumeration failed, but we already succeeded in
1236 * enumerating "Entire Network"--leave type as global to allow a
1237 * retry, but indicate success with a count of one.
1241 *lpBufferSize
= bytesNeeded
;
1244 TRACE("Returning %d\n", ret
);
1248 static DWORD
_copyStringToEnumW(const WCHAR
*source
, DWORD
* left
, void** end
)
1251 WCHAR
* local
= *end
;
1253 len
= strlenW(source
) + 1;
1254 len
*= sizeof(WCHAR
);
1256 return WN_MORE_DATA
;
1258 local
-= (len
/ sizeof(WCHAR
));
1259 memcpy(local
, source
, len
);
1266 static DWORD
_enumerateConnectedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1267 void* user_buffer
, DWORD
* user_size
)
1269 DWORD ret
, index
, count
, total_count
, size
, i
, left
;
1271 NETRESOURCEW
* curr
, * buffer
;
1275 return WN_BAD_POINTER
;
1276 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONNECTED
)
1277 return WN_BAD_VALUE
;
1278 if (!user_count
|| !user_buffer
|| !user_size
)
1279 return WN_BAD_POINTER
;
1281 return WN_NO_NETWORK
;
1283 handles
= enumerator
->specific
.handles
;
1286 buffer
= HeapAlloc(GetProcessHeap(), 0, *user_size
);
1288 return WN_NO_NETWORK
;
1291 end
= (char *)user_buffer
+ size
;
1292 count
= *user_count
;
1295 ret
= WN_NO_MORE_ENTRIES
;
1296 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1298 if (providerTable
->table
[index
].dwEnumScopes
)
1300 if (handles
[index
] == 0)
1302 ret
= providerTable
->table
[index
].openEnum(enumerator
->dwScope
,
1304 enumerator
->dwUsage
,
1305 NULL
, &handles
[index
]);
1306 if (ret
!= WN_SUCCESS
)
1310 ret
= providerTable
->table
[index
].enumResource(handles
[index
],
1313 total_count
+= count
;
1314 if (ret
== WN_MORE_DATA
)
1317 if (ret
== WN_SUCCESS
)
1319 for (i
= 0; i
< count
; ++i
)
1321 if (left
< sizeof(NETRESOURCEW
))
1327 memcpy(curr
, &buffer
[i
], sizeof(NETRESOURCEW
));
1328 left
-= sizeof(NETRESOURCEW
);
1330 ret
= _copyStringToEnumW(buffer
[i
].lpLocalName
, &left
, &end
);
1331 if (ret
== WN_MORE_DATA
)
1333 curr
->lpLocalName
= end
;
1335 ret
= _copyStringToEnumW(buffer
[i
].lpRemoteName
, &left
, &end
);
1336 if (ret
== WN_MORE_DATA
)
1338 curr
->lpRemoteName
= end
;
1340 ret
= _copyStringToEnumW(buffer
[i
].lpProvider
, &left
, &end
);
1341 if (ret
== WN_MORE_DATA
)
1343 curr
->lpProvider
= end
;
1351 if (*user_count
!= -1)
1352 count
= *user_count
- total_count
;
1354 count
= *user_count
;
1358 if (total_count
== 0)
1359 ret
= WN_NO_MORE_ENTRIES
;
1361 *user_count
= total_count
;
1362 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1365 HeapFree(GetProcessHeap(), 0, buffer
);
1367 TRACE("Returning %d\n", ret
);
1371 /*********************************************************************
1372 * WNetEnumResourceW [MPR.@]
1374 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1375 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1379 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1382 ret
= WN_BAD_POINTER
;
1384 ret
= WN_BAD_POINTER
;
1386 ret
= WN_BAD_POINTER
;
1387 else if (!lpBufferSize
)
1388 ret
= WN_BAD_POINTER
;
1389 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1391 *lpBufferSize
= sizeof(NETRESOURCEW
);
1396 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1398 switch (enumerator
->enumType
)
1400 case WNET_ENUMERATOR_TYPE_NULL
:
1401 ret
= WN_NO_MORE_ENTRIES
;
1403 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1404 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1407 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1408 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1411 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1412 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1415 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1416 ret
= _enumerateConnectedW(enumerator
, lpcCount
, lpBuffer
,
1420 WARN("bogus enumerator type!\n");
1421 ret
= WN_NO_NETWORK
;
1426 TRACE("Returning %d\n", ret
);
1430 /*********************************************************************
1431 * WNetCloseEnum [MPR.@]
1433 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1438 TRACE( "(%p)\n", hEnum
);
1442 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1444 switch (enumerator
->enumType
)
1446 case WNET_ENUMERATOR_TYPE_NULL
:
1449 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1450 if (enumerator
->specific
.net
)
1451 _freeEnumNetResource(enumerator
->specific
.net
);
1452 if (enumerator
->handle
)
1453 providerTable
->table
[enumerator
->providerIndex
].
1454 closeEnum(enumerator
->handle
);
1457 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1458 if (enumerator
->handle
)
1459 providerTable
->table
[enumerator
->providerIndex
].
1460 closeEnum(enumerator
->handle
);
1463 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1464 handles
= enumerator
->specific
.handles
;
1465 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1467 if (providerTable
->table
[index
].dwEnumScopes
&& handles
[index
])
1468 providerTable
->table
[index
].closeEnum(handles
[index
]);
1470 HeapFree(GetProcessHeap(), 0, handles
);
1474 WARN("bogus enumerator type!\n");
1475 ret
= WN_BAD_HANDLE
;
1477 HeapFree(GetProcessHeap(), 0, hEnum
);
1480 ret
= WN_BAD_HANDLE
;
1483 TRACE("Returning %d\n", ret
);
1487 /*********************************************************************
1488 * WNetGetResourceInformationA [MPR.@]
1490 * See WNetGetResourceInformationW
1492 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1493 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1498 TRACE( "(%p, %p, %p, %p)\n",
1499 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1501 if (!providerTable
|| providerTable
->numProviders
== 0)
1502 ret
= WN_NO_NETWORK
;
1503 else if (lpNetResource
)
1505 LPNETRESOURCEW lpNetResourceW
= NULL
;
1506 DWORD size
= 1024, count
= 1;
1509 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1510 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1511 if (ret
== WN_MORE_DATA
)
1513 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1514 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1516 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1517 &count
, lpNetResourceW
, &size
);
1519 ret
= WN_OUT_OF_MEMORY
;
1521 if (ret
== WN_SUCCESS
)
1523 LPWSTR lpSystemW
= NULL
;
1526 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1529 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1530 lpBufferW
, &size
, &lpSystemW
);
1531 if (ret
== WN_MORE_DATA
)
1533 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1534 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1536 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1537 lpBufferW
, &size
, &lpSystemW
);
1539 ret
= WN_OUT_OF_MEMORY
;
1541 if (ret
== WN_SUCCESS
)
1543 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1544 &count
, lpBuffer
, cbBuffer
);
1545 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1546 lpNetResourceW
= lpBufferW
;
1547 size
= sizeof(NETRESOURCEA
);
1548 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1549 -1, NULL
, 0, NULL
, NULL
);
1550 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1551 -1, NULL
, 0, NULL
, NULL
);
1553 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1554 -1, NULL
, 0, NULL
, NULL
);
1555 if ((len
) && ( size
+ len
< *cbBuffer
))
1557 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1558 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1559 *lplpSystem
, len
, NULL
, NULL
);
1566 ret
= WN_OUT_OF_MEMORY
;
1567 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1570 ret
= WN_OUT_OF_MEMORY
;
1571 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1573 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1576 ret
= WN_NO_NETWORK
;
1580 TRACE("Returning %d\n", ret
);
1584 /*********************************************************************
1585 * WNetGetResourceInformationW [MPR.@]
1587 * WNetGetResourceInformationW function identifies the network provider
1588 * that owns the resource and gets information about the type of the resource.
1591 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1592 * defines a network resource.
1593 * lpBuffer [ O] the pointer to buffer, containing result. It
1594 * contains NETRESOURCEW structure and strings to
1595 * which the members of the NETRESOURCEW structure
1597 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1599 * lplpSystem [ O] the pointer to string in the output buffer,
1600 * containing the part of the resource name without
1601 * names of the server and share.
1604 * NO_ERROR if the function succeeds. System error code if the function fails.
1607 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1608 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1609 LPWSTR
*lplpSystem
)
1611 DWORD ret
= WN_NO_NETWORK
;
1614 TRACE( "(%p, %p, %p, %p)\n",
1615 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1618 ret
= WN_OUT_OF_MEMORY
;
1619 else if (providerTable
!= NULL
)
1621 /* FIXME: For function value of a variable is indifferent, it does
1622 * search of all providers in a network.
1624 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1626 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1627 WNNC_DLG_GETRESOURCEINFORMATION
)
1629 if (providerTable
->table
[index
].getResourceInformation
)
1630 ret
= providerTable
->table
[index
].getResourceInformation(
1631 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1633 ret
= WN_NO_NETWORK
;
1634 if (ret
== WN_SUCCESS
)
1644 /*********************************************************************
1645 * WNetGetResourceParentA [MPR.@]
1647 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1648 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1650 FIXME( "(%p, %p, %p): stub\n",
1651 lpNetResource
, lpBuffer
, lpBufferSize
);
1653 SetLastError(WN_NO_NETWORK
);
1654 return WN_NO_NETWORK
;
1657 /*********************************************************************
1658 * WNetGetResourceParentW [MPR.@]
1660 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1661 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1663 FIXME( "(%p, %p, %p): stub\n",
1664 lpNetResource
, lpBuffer
, lpBufferSize
);
1666 SetLastError(WN_NO_NETWORK
);
1667 return WN_NO_NETWORK
;
1673 * Connection Functions
1676 /*********************************************************************
1677 * WNetAddConnectionA [MPR.@]
1679 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1680 LPCSTR lpLocalName
)
1682 NETRESOURCEA resourcesA
;
1684 memset(&resourcesA
, 0, sizeof(resourcesA
));
1685 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
1686 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
1687 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1690 /*********************************************************************
1691 * WNetAddConnectionW [MPR.@]
1693 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1694 LPCWSTR lpLocalName
)
1696 NETRESOURCEW resourcesW
;
1698 memset(&resourcesW
, 0, sizeof(resourcesW
));
1699 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
1700 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
1701 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1704 /*********************************************************************
1705 * WNetAddConnection2A [MPR.@]
1707 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1708 LPCSTR lpPassword
, LPCSTR lpUserID
,
1711 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1715 /*********************************************************************
1716 * WNetAddConnection2W [MPR.@]
1718 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1719 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1722 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1726 /*********************************************************************
1727 * WNetAddConnection3A [MPR.@]
1729 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1730 LPCSTR lpPassword
, LPCSTR lpUserID
,
1733 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1734 dwFlags
, NULL
, 0, NULL
);
1737 /*********************************************************************
1738 * WNetAddConnection3W [MPR.@]
1740 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1741 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1744 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1745 dwFlags
, NULL
, 0, NULL
);
1748 struct use_connection_context
1751 NETRESOURCEW
*resource
;
1752 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
1759 DWORD (*pre_set_accessname
)(struct use_connection_context
*, WCHAR
*);
1760 void (*set_accessname
)(struct use_connection_context
*, WCHAR
*);
1763 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1765 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1770 len
= strlenW(local_name
);
1772 len
= strlenW(ctxt
->resource
->lpRemoteName
);
1774 if (++len
> *ctxt
->buffer_size
)
1776 *ctxt
->buffer_size
= len
;
1777 return ERROR_MORE_DATA
;
1781 ctxt
->accessname
= NULL
;
1783 return ERROR_SUCCESS
;
1786 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1788 WCHAR
*accessname
= ctxt
->accessname
;
1791 strcpyW(accessname
, local_name
);
1793 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1796 strcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
1799 static DWORD
wnet_use_provider( struct use_connection_context
*ctxt
, NETRESOURCEW
* netres
, WNetProvider
*provider
, BOOLEAN redirect
)
1803 caps
= provider
->getCaps(WNNC_CONNECTION
);
1804 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
1805 return ERROR_BAD_PROVIDER
;
1807 ret
= WN_ACCESS_DENIED
;
1810 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
1811 ret
= provider
->addConnection3(ctxt
->hwndOwner
, netres
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
1812 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
1813 ret
= provider
->addConnection(netres
, ctxt
->password
, ctxt
->userid
);
1815 if (ret
== WN_ALREADY_CONNECTED
&& redirect
)
1816 netres
->lpLocalName
[0] -= 1;
1817 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& netres
->lpLocalName
[0] >= 'C');
1819 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
1820 ctxt
->set_accessname(ctxt
, netres
->lpLocalName
);
1825 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
1827 WNetProvider
*provider
;
1828 DWORD index
, ret
= WN_NO_NETWORK
;
1829 BOOL redirect
= FALSE
;
1830 WCHAR letter
[3] = {'Z', ':', 0};
1831 NETRESOURCEW netres
;
1833 if (!providerTable
|| providerTable
->numProviders
== 0)
1834 return WN_NO_NETWORK
;
1836 if (!ctxt
->resource
)
1837 return ERROR_INVALID_PARAMETER
;
1838 netres
= *ctxt
->resource
;
1840 if (!netres
.lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
1842 if (netres
.dwType
!= RESOURCETYPE_DISK
&& netres
.dwType
!= RESOURCETYPE_PRINT
)
1843 return ERROR_BAD_DEV_TYPE
;
1845 if (netres
.dwType
== RESOURCETYPE_PRINT
)
1847 FIXME("Local device selection is not implemented for printers.\n");
1848 return WN_NO_NETWORK
;
1852 netres
.lpLocalName
= letter
;
1855 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
1856 return ERROR_BAD_NET_NAME
;
1858 if ((ret
= ctxt
->pre_set_accessname(ctxt
, netres
.lpLocalName
)))
1861 if (netres
.lpProvider
)
1863 index
= _findProviderIndexW(netres
.lpProvider
);
1864 if (index
== BAD_PROVIDER_INDEX
)
1865 return ERROR_BAD_PROVIDER
;
1867 provider
= &providerTable
->table
[index
];
1868 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
1872 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1874 provider
= &providerTable
->table
[index
];
1875 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
1876 if (ret
== WN_SUCCESS
|| ret
== WN_ALREADY_CONNECTED
)
1884 /*****************************************************************
1885 * WNetUseConnectionW [MPR.@]
1887 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
1888 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
1890 struct use_connection_context ctxt
;
1892 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1893 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
1894 accessname
, buffer_size
, result
);
1896 ctxt
.hwndOwner
= hwndOwner
;
1897 ctxt
.resource
= resource
;
1898 ctxt
.resourceA
= NULL
;
1899 ctxt
.password
= (WCHAR
*)password
;
1900 ctxt
.userid
= (WCHAR
*)userid
;
1902 ctxt
.accessname
= accessname
;
1903 ctxt
.buffer_size
= buffer_size
;
1904 ctxt
.result
= result
;
1905 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
1906 ctxt
.set_accessname
= use_connection_set_accessnameW
;
1908 return wnet_use_connection(&ctxt
);
1911 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1913 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1918 len
= WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, NULL
, 0, NULL
, NULL
) - 1;
1920 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
1922 if (++len
> *ctxt
->buffer_size
)
1924 *ctxt
->buffer_size
= len
;
1925 return ERROR_MORE_DATA
;
1929 ctxt
->accessname
= NULL
;
1931 return ERROR_SUCCESS
;
1934 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1936 char *accessname
= ctxt
->accessname
;
1939 WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, accessname
, *ctxt
->buffer_size
, NULL
, NULL
);
1941 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1944 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
1947 static LPWSTR
strdupAtoW( LPCSTR str
)
1952 if (!str
) return NULL
;
1953 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
1954 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1955 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
1959 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
1961 resourceW
->dwScope
= resourceA
->dwScope
;
1962 resourceW
->dwType
= resourceA
->dwType
;
1963 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
1964 resourceW
->dwUsage
= resourceA
->dwUsage
;
1965 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
1966 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
1967 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
1968 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
1971 static void free_netresourceW( NETRESOURCEW
*resource
)
1973 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
1974 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
1975 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
1976 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
1979 /*****************************************************************
1980 * WNetUseConnectionA [MPR.@]
1982 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
1983 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
1984 DWORD
*buffer_size
, DWORD
*result
)
1986 struct use_connection_context ctxt
;
1987 NETRESOURCEW resourceW
;
1990 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
1991 accessname
, buffer_size
, result
);
1993 netresource_a_to_w(resource
, &resourceW
);
1995 ctxt
.hwndOwner
= hwndOwner
;
1996 ctxt
.resource
= &resourceW
;
1997 ctxt
.resourceA
= resource
;
1998 ctxt
.password
= strdupAtoW(password
);
1999 ctxt
.userid
= strdupAtoW(userid
);
2001 ctxt
.accessname
= accessname
;
2002 ctxt
.buffer_size
= buffer_size
;
2003 ctxt
.result
= result
;
2004 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
2005 ctxt
.set_accessname
= use_connection_set_accessnameA
;
2007 ret
= wnet_use_connection(&ctxt
);
2009 free_netresourceW(&resourceW
);
2010 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
2011 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
2016 /*********************************************************************
2017 * WNetCancelConnectionA [MPR.@]
2019 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
2021 return WNetCancelConnection2A(lpName
, 0, fForce
);
2024 /*********************************************************************
2025 * WNetCancelConnectionW [MPR.@]
2027 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
2029 return WNetCancelConnection2W(lpName
, 0, fForce
);
2032 /*********************************************************************
2033 * WNetCancelConnection2A [MPR.@]
2035 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2038 WCHAR
* name
= strdupAtoW(lpName
);
2040 return ERROR_NOT_CONNECTED
;
2042 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
2043 HeapFree(GetProcessHeap(), 0, name
);
2048 /*********************************************************************
2049 * WNetCancelConnection2W [MPR.@]
2051 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2053 DWORD ret
= WN_NO_NETWORK
;
2056 if (providerTable
!= NULL
)
2058 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2060 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2061 WNNC_CON_CANCELCONNECTION
)
2063 if (providerTable
->table
[index
].cancelConnection
)
2064 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
2066 ret
= WN_NO_NETWORK
;
2067 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
2075 /*****************************************************************
2076 * WNetRestoreConnectionA [MPR.@]
2078 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
2080 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
2082 SetLastError(WN_NO_NETWORK
);
2083 return WN_NO_NETWORK
;
2086 /*****************************************************************
2087 * WNetRestoreConnectionW [MPR.@]
2089 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
2091 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
2093 SetLastError(WN_NO_NETWORK
);
2094 return WN_NO_NETWORK
;
2097 /**************************************************************************
2098 * WNetGetConnectionA [MPR.@]
2101 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2102 * - WN_NOT_CONNECTED drive is a local drive
2103 * - WN_MORE_DATA buffer isn't big enough
2104 * - WN_SUCCESS success (net path in buffer)
2106 * FIXME: need to test return values under different errors
2108 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
2109 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
2114 ret
= WN_BAD_POINTER
;
2115 else if (!lpBufferSize
)
2116 ret
= WN_BAD_POINTER
;
2117 else if (!lpRemoteName
&& *lpBufferSize
)
2118 ret
= WN_BAD_POINTER
;
2121 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
2125 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2129 WCHAR wideRemoteStatic
[MAX_PATH
];
2130 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
2132 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
2134 /* try once without memory allocation */
2135 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
2137 if (ret
== WN_SUCCESS
)
2139 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2140 -1, NULL
, 0, NULL
, NULL
);
2142 if (len
<= *lpBufferSize
)
2144 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
2145 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2150 *lpBufferSize
= len
;
2154 else if (ret
== WN_MORE_DATA
)
2156 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2157 wideRemoteSize
* sizeof(WCHAR
));
2161 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2163 if (ret
== WN_SUCCESS
)
2165 if (len
<= *lpBufferSize
)
2167 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2168 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2173 *lpBufferSize
= len
;
2177 HeapFree(GetProcessHeap(), 0, wideRemote
);
2180 ret
= WN_OUT_OF_MEMORY
;
2182 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2185 ret
= WN_OUT_OF_MEMORY
;
2188 ret
= WN_BAD_LOCALNAME
;
2192 TRACE("Returning %d\n", ret
);
2196 /* find the network connection for a given drive; helper for WNetGetConnection */
2197 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2200 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2202 DWORD ret
= WN_NOT_CONNECTED
;
2203 DWORD bytes_returned
;
2205 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2206 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2207 0, 0 )) == INVALID_HANDLE_VALUE
)
2209 ERR( "failed to open mount manager err %u\n", GetLastError() );
2212 memset( data
, 0, sizeof(*data
) );
2213 data
->letter
= letter
;
2214 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2215 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2217 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2220 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2223 mount_point
[0] = '\\';
2224 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2226 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2234 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2243 /**************************************************************************
2244 * WNetGetConnectionW [MPR.@]
2246 * FIXME: need to test return values under different errors
2248 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2249 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2253 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2257 ret
= WN_BAD_POINTER
;
2258 else if (!lpBufferSize
)
2259 ret
= WN_BAD_POINTER
;
2260 else if (!lpRemoteName
&& *lpBufferSize
)
2261 ret
= WN_BAD_POINTER
;
2262 else if (!lpLocalName
[0])
2263 ret
= WN_BAD_LOCALNAME
;
2266 if (lpLocalName
[1] == ':')
2268 switch(GetDriveTypeW(lpLocalName
))
2271 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2273 case DRIVE_REMOVABLE
:
2276 TRACE("file is local\n");
2277 ret
= WN_NOT_CONNECTED
;
2280 ret
= WN_BAD_LOCALNAME
;
2284 ret
= WN_BAD_LOCALNAME
;
2288 TRACE("Returning %d\n", ret
);
2292 /**************************************************************************
2293 * WNetSetConnectionA [MPR.@]
2295 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2298 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2300 SetLastError(WN_NO_NETWORK
);
2301 return WN_NO_NETWORK
;
2304 /**************************************************************************
2305 * WNetSetConnectionW [MPR.@]
2307 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2310 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2312 SetLastError(WN_NO_NETWORK
);
2313 return WN_NO_NETWORK
;
2316 /*****************************************************************
2317 * WNetGetUniversalNameA [MPR.@]
2319 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2320 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2324 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2325 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2327 switch (dwInfoLevel
)
2329 case UNIVERSAL_NAME_INFO_LEVEL
:
2331 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2333 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2335 err
= ERROR_NOT_CONNECTED
;
2339 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2340 if (*lpBufferSize
< size
)
2345 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2346 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2350 case REMOTE_NAME_INFO_LEVEL
:
2351 err
= WN_NOT_CONNECTED
;
2363 /*****************************************************************
2364 * WNetGetUniversalNameW [MPR.@]
2366 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2367 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2371 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2372 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2374 switch (dwInfoLevel
)
2376 case UNIVERSAL_NAME_INFO_LEVEL
:
2378 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2380 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2382 err
= ERROR_NOT_CONNECTED
;
2386 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2387 if (*lpBufferSize
< size
)
2392 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2393 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2397 case REMOTE_NAME_INFO_LEVEL
:
2398 err
= WN_NO_NETWORK
;
2406 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2416 /**************************************************************************
2417 * WNetGetUserA [MPR.@]
2419 * FIXME: we should not return ourselves, but the owner of the drive lpName
2421 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2423 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2424 return GetLastError();
2427 /*****************************************************************
2428 * WNetGetUserW [MPR.@]
2430 * FIXME: we should not return ourselves, but the owner of the drive lpName
2432 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2434 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2435 return GetLastError();
2438 /*********************************************************************
2439 * WNetConnectionDialog [MPR.@]
2441 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2443 CONNECTDLGSTRUCTW conn_dlg
;
2444 NETRESOURCEW net_res
;
2446 ZeroMemory(&conn_dlg
, sizeof(conn_dlg
));
2447 ZeroMemory(&net_res
, sizeof(net_res
));
2449 conn_dlg
.cbStructure
= sizeof(conn_dlg
);
2450 conn_dlg
.lpConnRes
= &net_res
;
2451 conn_dlg
.hwndOwner
= hwnd
;
2452 net_res
.dwType
= dwType
;
2454 return WNetConnectionDialog1W(&conn_dlg
);
2457 /*********************************************************************
2458 * WNetConnectionDialog1A [MPR.@]
2460 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2462 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2464 SetLastError(WN_NO_NETWORK
);
2465 return WN_NO_NETWORK
;
2468 /*********************************************************************
2469 * WNetConnectionDialog1W [MPR.@]
2471 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2473 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2475 SetLastError(WN_NO_NETWORK
);
2476 return WN_NO_NETWORK
;
2479 /*********************************************************************
2480 * WNetDisconnectDialog [MPR.@]
2482 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2484 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2486 SetLastError(WN_NO_NETWORK
);
2487 return WN_NO_NETWORK
;
2490 /*********************************************************************
2491 * WNetDisconnectDialog1A [MPR.@]
2493 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2495 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2497 SetLastError(WN_NO_NETWORK
);
2498 return WN_NO_NETWORK
;
2501 /*********************************************************************
2502 * WNetDisconnectDialog1W [MPR.@]
2504 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2506 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2508 SetLastError(WN_NO_NETWORK
);
2509 return WN_NO_NETWORK
;
2512 /*********************************************************************
2513 * WNetGetLastErrorA [MPR.@]
2515 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2516 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2517 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2519 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2520 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2522 SetLastError(WN_NO_NETWORK
);
2523 return WN_NO_NETWORK
;
2526 /*********************************************************************
2527 * WNetGetLastErrorW [MPR.@]
2529 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2530 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2531 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2533 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2534 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2536 SetLastError(WN_NO_NETWORK
);
2537 return WN_NO_NETWORK
;
2540 /*********************************************************************
2541 * WNetGetNetworkInformationA [MPR.@]
2543 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2544 LPNETINFOSTRUCT lpNetInfoStruct
)
2548 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2551 ret
= WN_BAD_POINTER
;
2556 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2559 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2563 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2565 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2566 HeapFree(GetProcessHeap(), 0, wideProvider
);
2569 ret
= WN_OUT_OF_MEMORY
;
2572 ret
= GetLastError();
2576 TRACE("Returning %d\n", ret
);
2580 /*********************************************************************
2581 * WNetGetNetworkInformationW [MPR.@]
2583 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2584 LPNETINFOSTRUCT lpNetInfoStruct
)
2588 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2591 ret
= WN_BAD_POINTER
;
2592 else if (!lpNetInfoStruct
)
2593 ret
= WN_BAD_POINTER
;
2594 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2598 if (providerTable
&& providerTable
->numProviders
)
2600 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2602 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2604 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2605 lpNetInfoStruct
->dwProviderVersion
=
2606 providerTable
->table
[providerIndex
].dwSpecVersion
;
2607 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2608 lpNetInfoStruct
->dwCharacteristics
= 0;
2609 lpNetInfoStruct
->dwHandle
= 0;
2610 lpNetInfoStruct
->wNetType
=
2611 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2612 lpNetInfoStruct
->dwPrinters
= -1;
2613 lpNetInfoStruct
->dwDrives
= -1;
2617 ret
= WN_BAD_PROVIDER
;
2620 ret
= WN_NO_NETWORK
;
2624 TRACE("Returning %d\n", ret
);
2628 /*****************************************************************
2629 * WNetGetProviderNameA [MPR.@]
2631 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2632 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2636 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2640 ret
= WN_BAD_POINTER
;
2641 else if (!lpBufferSize
)
2642 ret
= WN_BAD_POINTER
;
2649 ret
= WN_NO_NETWORK
;
2650 for (i
= 0; i
< providerTable
->numProviders
&&
2651 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2654 if (i
< providerTable
->numProviders
)
2656 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2657 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2659 if (*lpBufferSize
< sizeNeeded
)
2661 *lpBufferSize
= sizeNeeded
;
2666 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2667 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2669 /* FIXME: is *lpBufferSize set to the number of characters
2675 ret
= WN_NO_NETWORK
;
2679 TRACE("Returning %d\n", ret
);
2683 /*****************************************************************
2684 * WNetGetProviderNameW [MPR.@]
2686 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2687 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2691 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2695 ret
= WN_BAD_POINTER
;
2696 else if (!lpBufferSize
)
2697 ret
= WN_BAD_POINTER
;
2704 ret
= WN_NO_NETWORK
;
2705 for (i
= 0; i
< providerTable
->numProviders
&&
2706 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2709 if (i
< providerTable
->numProviders
)
2711 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2713 if (*lpBufferSize
< sizeNeeded
)
2715 *lpBufferSize
= sizeNeeded
;
2720 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2722 /* FIXME: is *lpBufferSize set to the number of characters
2728 ret
= WN_NO_NETWORK
;
2732 TRACE("Returning %d\n", ret
);