4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #define WINE_MOUNTMGR_EXTENSIONS
28 #include <ddk/mountmgr.h>
29 #include <wine/unicode.h>
31 /* Data structures representing network service providers. Assumes only one
32 * thread creates them, and that they are constant for the life of the process
33 * (and therefore doesn't synchronize access).
34 * FIXME: only basic provider data and enumeration-related data are implemented
35 * so far, need to implement the rest too.
37 typedef struct _WNetProvider
45 PF_NPOpenEnum openEnum
;
46 PF_NPEnumResource enumResource
;
47 PF_NPCloseEnum closeEnum
;
48 PF_NPGetResourceInformation getResourceInformation
;
49 PF_NPAddConnection addConnection
;
50 PF_NPAddConnection3 addConnection3
;
51 PF_NPCancelConnection cancelConnection
;
53 PF_NPGetConnection getConnection
;
55 } WNetProvider
, *PWNetProvider
;
57 typedef struct _WNetProviderTable
62 WNetProvider table
[1];
63 } WNetProviderTable
, *PWNetProviderTable
;
65 #define WNET_ENUMERATOR_TYPE_NULL 0
66 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
67 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
68 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
69 #define WNET_ENUMERATOR_TYPE_CONNECTED 4
71 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
72 * the enumeration; it represents one of the following types:
73 * - a 'null' enumeration, one that contains no members
74 * - a global enumeration, one that's executed across all providers
75 * - a provider-specific enumeration, one that's only executed by a single
77 * - a context enumeration. I know this contradicts what I just said about
78 * there being no correspondence between the scope and the type, but it's
79 * necessary for the special case that a "Entire Network" entry needs to
80 * be enumerated in an enumeration of the context scope. Thus an enumeration
81 * of the context scope results in a context type enumerator, which morphs
82 * into a global enumeration (so the enumeration continues across all
85 typedef struct _WNetEnumerator
95 } WNetEnumerator
, *PWNetEnumerator
;
97 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
99 /* Returns an index (into the global WNetProviderTable) of the provider with
100 * the given name, or BAD_PROVIDER_INDEX if not found.
102 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
104 static PWNetProviderTable providerTable
;
107 * Global provider table functions
110 static void _tryLoadProvider(PCWSTR provider
)
112 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
113 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
114 'S','e','r','v','i','c','e','s','\\',0 };
115 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
116 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
117 WCHAR serviceName
[MAX_PATH
];
120 TRACE("%s\n", debugstr_w(provider
));
121 snprintfW(serviceName
, sizeof(serviceName
) / sizeof(WCHAR
), serviceFmt
,
122 servicePrefix
, provider
);
123 serviceName
[sizeof(serviceName
) / sizeof(WCHAR
) - 1] = '\0';
124 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
127 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
129 WCHAR providerPath
[MAX_PATH
];
130 DWORD type
, size
= sizeof(providerPath
);
132 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
133 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
135 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
138 if (type
== REG_EXPAND_SZ
)
140 WCHAR path
[MAX_PATH
];
141 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
145 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
148 name
= HeapAlloc(GetProcessHeap(), 0, size
);
149 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
150 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
152 HeapFree(GetProcessHeap(), 0, name
);
158 HMODULE hLib
= LoadLibraryW(providerPath
);
162 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
164 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
166 TRACE("loaded lib %p\n", hLib
);
169 PWNetProvider provider
=
170 &providerTable
->table
[providerTable
->numProviders
];
172 provider
->hLib
= hLib
;
173 provider
->name
= name
;
174 TRACE("name is %s\n", debugstr_w(name
));
175 provider
->getCaps
= getCaps
;
176 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
177 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
178 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
179 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
180 if (provider
->dwEnumScopes
)
182 TRACE("supports enumeration\n");
183 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
184 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
185 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
186 TRACE("NPEnumResource %p\n", provider
->enumResource
);
187 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
188 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
189 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
190 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
191 if (!provider
->openEnum
||
192 !provider
->enumResource
||
193 !provider
->closeEnum
)
195 provider
->openEnum
= NULL
;
196 provider
->enumResource
= NULL
;
197 provider
->closeEnum
= NULL
;
198 provider
->dwEnumScopes
= 0;
199 WARN("Couldn't load enumeration functions\n");
202 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
203 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
204 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
206 provider
->getConnection
= MPR_GETPROC(NPGetConnection
);
208 TRACE("NPAddConnection %p\n", provider
->addConnection
);
209 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
210 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
211 providerTable
->numProviders
++;
215 WARN("Provider %s didn't export NPGetCaps\n",
216 debugstr_w(provider
));
217 HeapFree(GetProcessHeap(), 0, name
);
225 WARN("Couldn't load library %s for provider %s\n",
226 debugstr_w(providerPath
), debugstr_w(provider
));
227 HeapFree(GetProcessHeap(), 0, name
);
232 WARN("Couldn't get provider name for provider %s\n",
233 debugstr_w(provider
));
237 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
241 WARN("Couldn't open service key for provider %s\n",
242 debugstr_w(provider
));
245 void wnetInit(HINSTANCE hInstDll
)
247 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
248 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
249 'C','o','n','t','r','o','l','\\',
250 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
251 'O','r','d','e','r',0 };
252 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
253 'O','r','d','e','r',0 };
256 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
261 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
264 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
270 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
271 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
276 TRACE("provider order is %s\n", debugstr_w(providers
));
277 /* first count commas as a heuristic for how many to
278 * allocate space for */
279 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
281 ptr
= strchrW(ptr
, ',');
288 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
289 sizeof(WNetProviderTable
)
290 + (numToAllocate
- 1) * sizeof(WNetProvider
));
294 int entireNetworkLen
;
295 LPCWSTR stringresource
;
297 entireNetworkLen
= LoadStringW(hInstDll
,
298 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
299 providerTable
->entireNetwork
= HeapAlloc(
300 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
302 if (providerTable
->entireNetwork
)
304 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
305 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
307 providerTable
->numAllocated
= numToAllocate
;
308 for (ptr
= providers
; ptr
; )
311 ptr
= strchrW(ptr
, ',');
314 _tryLoadProvider(ptrPrev
);
318 HeapFree(GetProcessHeap(), 0, providers
);
331 for (i
= 0; i
< providerTable
->numProviders
; i
++)
333 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
334 FreeModule(providerTable
->table
[i
].hLib
);
336 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
337 HeapFree(GetProcessHeap(), 0, providerTable
);
338 providerTable
= NULL
;
342 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
344 DWORD ret
= BAD_PROVIDER_INDEX
;
346 if (providerTable
&& providerTable
->numProviders
)
350 for (i
= 0; i
< providerTable
->numProviders
&&
351 ret
== BAD_PROVIDER_INDEX
; i
++)
352 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
362 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
368 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
374 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
375 if (lpNet
->lpRemoteName
)
377 len
= strlenW(lpNet
->lpRemoteName
) + 1;
378 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
379 if (ret
->lpRemoteName
)
380 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
389 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
393 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
394 HeapFree(GetProcessHeap(), 0, lpNet
);
398 static PWNetEnumerator
_createNullEnumerator(void)
400 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
401 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
404 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
408 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
409 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
411 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
412 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
416 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
417 ret
->dwScope
= dwScope
;
418 ret
->dwType
= dwType
;
419 ret
->dwUsage
= dwUsage
;
420 ret
->lpBuffer
= _copyNetResourceForEnumW(lpNet
);
425 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
426 DWORD dwUsage
, DWORD index
, HANDLE handle
)
430 if (!providerTable
|| index
>= providerTable
->numProviders
)
434 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
437 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
438 ret
->providerIndex
= index
;
439 ret
->dwScope
= dwScope
;
440 ret
->dwType
= dwType
;
441 ret
->dwUsage
= dwUsage
;
442 ret
->handle
= handle
;
448 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
451 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
452 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
456 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
457 ret
->dwScope
= dwScope
;
458 ret
->dwType
= dwType
;
459 ret
->dwUsage
= dwUsage
;
464 static PWNetEnumerator
_createConnectedEnumerator(DWORD dwScope
, DWORD dwType
,
467 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
468 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
472 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONNECTED
;
473 ret
->dwScope
= dwScope
;
474 ret
->dwType
= dwType
;
475 ret
->dwUsage
= dwUsage
;
476 ret
->lpBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HANDLE
) * providerTable
->numProviders
);
479 HeapFree(GetProcessHeap(), 0, ret
);
486 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
487 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
488 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
489 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
490 * if not all members of the array could be thunked, and something else on
493 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
494 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
496 DWORD i
, numToThunk
, totalBytes
, ret
;
500 return WN_BAD_POINTER
;
502 return WN_BAD_POINTER
;
506 return WN_BAD_POINTER
;
508 return WN_BAD_POINTER
;
510 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
512 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
514 totalBytes
+= sizeof(NETRESOURCEA
);
515 if (lpNet
->lpLocalName
)
516 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
517 -1, NULL
, 0, NULL
, NULL
);
518 if (lpNet
->lpRemoteName
)
519 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
520 -1, NULL
, 0, NULL
, NULL
);
521 if (lpNet
->lpComment
)
522 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
523 -1, NULL
, 0, NULL
, NULL
);
524 if (lpNet
->lpProvider
)
525 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
526 -1, NULL
, 0, NULL
, NULL
);
527 if (totalBytes
< *lpBufferSize
)
530 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
531 for (i
= 0; i
< numToThunk
; i
++)
533 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
534 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
536 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
537 /* lie about string lengths, we already verified how many
538 * we have space for above
540 if (lpNetIn
->lpLocalName
)
542 lpNetOut
->lpLocalName
= strNext
;
543 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
544 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
546 if (lpNetIn
->lpRemoteName
)
548 lpNetOut
->lpRemoteName
= strNext
;
549 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
550 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
552 if (lpNetIn
->lpComment
)
554 lpNetOut
->lpComment
= strNext
;
555 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
556 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
558 if (lpNetIn
->lpProvider
)
560 lpNetOut
->lpProvider
= strNext
;
561 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
562 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
565 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
566 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
571 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
572 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
573 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
574 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
575 * if not all members of the array could be thunked, and something else on
578 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
579 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
581 DWORD i
, numToThunk
, totalBytes
, ret
;
585 return WN_BAD_POINTER
;
587 return WN_BAD_POINTER
;
591 return WN_BAD_POINTER
;
593 return WN_BAD_POINTER
;
595 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
597 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
599 totalBytes
+= sizeof(NETRESOURCEW
);
600 if (lpNet
->lpLocalName
)
601 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
602 -1, NULL
, 0) * sizeof(WCHAR
);
603 if (lpNet
->lpRemoteName
)
604 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
605 -1, NULL
, 0) * sizeof(WCHAR
);
606 if (lpNet
->lpComment
)
607 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
608 -1, NULL
, 0) * sizeof(WCHAR
);
609 if (lpNet
->lpProvider
)
610 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
611 -1, NULL
, 0) * sizeof(WCHAR
);
612 if (totalBytes
< *lpBufferSize
)
615 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
616 for (i
= 0; i
< numToThunk
; i
++)
618 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
619 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
621 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
622 /* lie about string lengths, we already verified how many
623 * we have space for above
625 if (lpNetIn
->lpLocalName
)
627 lpNetOut
->lpLocalName
= strNext
;
628 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
629 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
631 if (lpNetIn
->lpRemoteName
)
633 lpNetOut
->lpRemoteName
= strNext
;
634 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
635 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
637 if (lpNetIn
->lpComment
)
639 lpNetOut
->lpComment
= strNext
;
640 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
641 -1, lpNetOut
->lpComment
, *lpBufferSize
);
643 if (lpNetIn
->lpProvider
)
645 lpNetOut
->lpProvider
= strNext
;
646 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
647 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
650 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
651 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
656 /*********************************************************************
657 * WNetOpenEnumA [MPR.@]
659 * See comments for WNetOpenEnumW.
661 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
662 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
666 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
667 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
670 ret
= WN_BAD_POINTER
;
671 else if (!providerTable
|| providerTable
->numProviders
== 0)
680 LPNETRESOURCEW lpNetWide
= NULL
;
682 DWORD size
= sizeof(buf
), count
= 1;
683 BOOL allocated
= FALSE
;
685 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
686 if (ret
== WN_MORE_DATA
)
688 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
692 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
697 ret
= WN_OUT_OF_MEMORY
;
699 else if (ret
== WN_SUCCESS
)
700 lpNetWide
= (LPNETRESOURCEW
)buf
;
701 if (ret
== WN_SUCCESS
)
702 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
705 HeapFree(GetProcessHeap(), 0, lpNetWide
);
708 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
712 TRACE("Returning %d\n", ret
);
716 /*********************************************************************
717 * WNetOpenEnumW [MPR.@]
719 * Network enumeration has way too many parameters, so I'm not positive I got
720 * them right. What I've got so far:
722 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
723 * all the network providers should be enumerated.
725 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
726 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
727 * lpProvider is set, all the network providers should be enumerated.
728 * (This means the enumeration is a list of network providers, not that the
729 * enumeration is passed on to the providers.)
731 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
732 * resource matches the "Entire Network" resource (no remote name, no
733 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
734 * enumeration is done on every network provider.
736 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
737 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
738 * only to the given network provider.
740 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
741 * no lpProvider is set, enumeration will be tried on every network provider,
742 * in the order in which they're loaded.
744 * - The LPNETRESOURCE should be disregarded for scopes besides
745 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
746 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
748 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
749 * resource in the enumerated list, as well as any machines in your
750 * workgroup. The machines in your workgroup come from doing a
751 * RESOURCE_CONTEXT enumeration of every Network Provider.
753 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
754 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
758 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
759 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
762 ret
= WN_BAD_POINTER
;
763 else if (!providerTable
|| providerTable
->numProviders
== 0)
772 case RESOURCE_GLOBALNET
:
775 if (lpNet
->lpProvider
)
777 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
779 if (index
!= BAD_PROVIDER_INDEX
)
781 if (providerTable
->table
[index
].openEnum
&&
782 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
785 PWSTR RemoteName
= lpNet
->lpRemoteName
;
787 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
788 RemoteName
&& !strcmpW(RemoteName
, lpNet
->lpProvider
))
789 lpNet
->lpRemoteName
= NULL
;
791 ret
= providerTable
->table
[index
].openEnum(
792 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
793 if (ret
== WN_SUCCESS
)
795 *lphEnum
= _createProviderEnumerator(
796 dwScope
, dwType
, dwUsage
, index
, handle
);
797 ret
= *lphEnum
? WN_SUCCESS
:
801 lpNet
->lpRemoteName
= RemoteName
;
804 ret
= WN_NOT_SUPPORTED
;
807 ret
= WN_BAD_PROVIDER
;
809 else if (lpNet
->lpRemoteName
)
811 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
812 dwType
, dwUsage
, lpNet
);
813 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
817 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
818 providerTable
->entireNetwork
))
820 /* comment matches the "Entire Network", enumerate
821 * global scope of every provider
823 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
824 dwType
, dwUsage
, lpNet
);
828 /* this is the same as not having passed lpNet */
829 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
830 dwType
, dwUsage
, NULL
);
832 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
837 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
839 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
842 case RESOURCE_CONTEXT
:
843 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
844 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
846 case RESOURCE_REMEMBERED
:
847 *lphEnum
= _createNullEnumerator();
848 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
850 case RESOURCE_CONNECTED
:
851 *lphEnum
= _createConnectedEnumerator(dwScope
, dwType
, dwUsage
);
852 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
855 WARN("unknown scope 0x%08x\n", dwScope
);
861 TRACE("Returning %d\n", ret
);
865 /*********************************************************************
866 * WNetEnumResourceA [MPR.@]
868 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
869 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
873 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
876 ret
= WN_BAD_POINTER
;
878 ret
= WN_BAD_POINTER
;
880 ret
= WN_BAD_POINTER
;
881 else if (!lpBufferSize
)
882 ret
= WN_BAD_POINTER
;
883 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
885 *lpBufferSize
= sizeof(NETRESOURCEA
);
890 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
891 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
895 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
897 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
899 /* FIXME: this isn't necessarily going to work in the case of
900 * WN_MORE_DATA, because our enumerator may have moved on to
901 * the next provider. MSDN states that a large (16KB) buffer
902 * size is the appropriate usage of this function, so
903 * hopefully it won't be an issue.
905 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
906 lpBuffer
, lpBufferSize
);
907 *lpcCount
= localCount
;
909 HeapFree(GetProcessHeap(), 0, localBuffer
);
912 ret
= WN_OUT_OF_MEMORY
;
916 TRACE("Returning %d\n", ret
);
920 static DWORD
_countProviderBytesW(PWNetProvider provider
)
926 ret
= sizeof(NETRESOURCEW
);
927 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
934 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
935 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
940 return WN_BAD_POINTER
;
941 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
944 return WN_BAD_POINTER
;
946 return WN_BAD_POINTER
;
948 return WN_BAD_POINTER
;
949 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
952 if (!providerTable
|| enumerator
->providerIndex
>=
953 providerTable
->numProviders
)
954 ret
= WN_NO_MORE_ENTRIES
;
957 DWORD bytes
= 0, count
= 0, countLimit
, i
;
958 LPNETRESOURCEW resource
;
961 countLimit
= *lpcCount
== -1 ?
962 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
963 while (count
< countLimit
&& bytes
< *lpBufferSize
)
965 DWORD bytesNext
= _countProviderBytesW(
966 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
968 if (bytes
+ bytesNext
< *lpBufferSize
)
974 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
975 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
977 resource
->dwScope
= RESOURCE_GLOBALNET
;
978 resource
->dwType
= RESOURCETYPE_ANY
;
979 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
980 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
981 RESOURCEUSAGE_RESERVED
;
982 resource
->lpLocalName
= NULL
;
983 resource
->lpRemoteName
= strNext
;
984 strcpyW(resource
->lpRemoteName
,
985 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
986 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
987 resource
->lpComment
= NULL
;
988 resource
->lpProvider
= strNext
;
989 strcpyW(resource
->lpProvider
,
990 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
991 strNext
+= strlenW(resource
->lpProvider
) + 1;
993 enumerator
->providerIndex
+= count
;
995 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
997 TRACE("Returning %d\n", ret
);
1001 /* Advances the enumerator (assumed to be a global enumerator) to the next
1002 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1003 * not open a handle with the next provider.
1004 * If the existing handle is NULL, may leave the enumerator unchanged, since
1005 * the current provider may support the desired scope.
1006 * If the existing handle is not NULL, closes it before moving on.
1007 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1008 * provider, and another error on failure.
1010 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
1013 return WN_BAD_POINTER
;
1014 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1015 return WN_BAD_VALUE
;
1016 if (!providerTable
|| enumerator
->providerIndex
>=
1017 providerTable
->numProviders
)
1018 return WN_NO_MORE_ENTRIES
;
1020 if (enumerator
->providerDone
)
1023 enumerator
->providerDone
= FALSE
;
1024 if (enumerator
->handle
)
1026 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1027 enumerator
->handle
);
1028 enumerator
->handle
= NULL
;
1029 enumerator
->providerIndex
++;
1031 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1032 dwEnum
= WNNC_ENUM_LOCAL
;
1033 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1034 dwEnum
= WNNC_ENUM_GLOBAL
;
1035 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1036 dwEnum
= WNNC_ENUM_CONTEXT
;
1037 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1038 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1039 & dwEnum
); enumerator
->providerIndex
++)
1042 return enumerator
->providerIndex
< providerTable
->numProviders
?
1043 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1046 /* "Passes through" call to the next provider that supports the enumeration
1048 * FIXME: if one call to a provider's enumerator succeeds while there's still
1049 * space in lpBuffer, I don't call to the next provider. The caller may not
1050 * expect that it should call EnumResourceW again with a return value of
1051 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1052 * may have to be moved around a bit, ick.
1054 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1055 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1060 return WN_BAD_POINTER
;
1061 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1062 return WN_BAD_VALUE
;
1064 return WN_BAD_POINTER
;
1066 return WN_BAD_POINTER
;
1068 return WN_BAD_POINTER
;
1069 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1070 return WN_MORE_DATA
;
1072 ret
= _globalEnumeratorAdvance(enumerator
);
1073 if (ret
== WN_SUCCESS
)
1075 ret
= providerTable
->table
[enumerator
->providerIndex
].
1076 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1077 enumerator
->dwUsage
, enumerator
->lpBuffer
,
1078 &enumerator
->handle
);
1079 if (ret
== WN_SUCCESS
)
1081 ret
= providerTable
->table
[enumerator
->providerIndex
].
1082 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1084 if (ret
!= WN_MORE_DATA
)
1085 enumerator
->providerDone
= TRUE
;
1088 TRACE("Returning %d\n", ret
);
1092 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1093 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1098 return WN_BAD_POINTER
;
1099 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1100 return WN_BAD_VALUE
;
1102 return WN_BAD_POINTER
;
1104 return WN_BAD_POINTER
;
1106 return WN_BAD_POINTER
;
1107 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1108 return WN_MORE_DATA
;
1110 return WN_NO_NETWORK
;
1112 switch (enumerator
->dwScope
)
1114 case RESOURCE_GLOBALNET
:
1115 if (enumerator
->lpBuffer
)
1116 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1117 lpBuffer
, lpBufferSize
);
1119 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1122 case RESOURCE_CONTEXT
:
1123 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1127 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1128 ret
= WN_NO_MORE_ENTRIES
;
1130 TRACE("Returning %d\n", ret
);
1134 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1135 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1138 return WN_BAD_POINTER
;
1139 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1140 return WN_BAD_VALUE
;
1141 if (!enumerator
->handle
)
1142 return WN_BAD_VALUE
;
1144 return WN_BAD_POINTER
;
1146 return WN_BAD_POINTER
;
1148 return WN_BAD_POINTER
;
1150 return WN_NO_NETWORK
;
1151 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1152 return WN_NO_MORE_ENTRIES
;
1153 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1154 return WN_BAD_VALUE
;
1155 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1156 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1159 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1160 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1163 size_t cchEntireNetworkLen
, bytesNeeded
;
1166 return WN_BAD_POINTER
;
1167 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1168 return WN_BAD_VALUE
;
1170 return WN_BAD_POINTER
;
1172 return WN_BAD_POINTER
;
1174 return WN_BAD_POINTER
;
1176 return WN_NO_NETWORK
;
1178 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1179 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1180 if (*lpBufferSize
< bytesNeeded
)
1182 *lpBufferSize
= bytesNeeded
;
1187 LPNETRESOURCEW lpNet
= lpBuffer
;
1189 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1190 lpNet
->dwType
= enumerator
->dwType
;
1191 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1192 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1193 lpNet
->lpLocalName
= NULL
;
1194 lpNet
->lpRemoteName
= NULL
;
1195 lpNet
->lpProvider
= NULL
;
1196 /* odd, but correct: put comment at end of buffer, so it won't get
1197 * overwritten by subsequent calls to a provider's enumResource
1199 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1200 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1201 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1204 if (ret
== WN_SUCCESS
)
1206 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1208 /* "Entire Network" entry enumerated--morph this into a global
1209 * enumerator. enumerator->lpNet continues to be NULL, since it has
1210 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1212 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1213 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1214 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1215 if (ret
== WN_SUCCESS
)
1217 /* reflect the fact that we already enumerated "Entire Network" */
1219 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1223 /* the provider enumeration failed, but we already succeeded in
1224 * enumerating "Entire Network"--leave type as global to allow a
1225 * retry, but indicate success with a count of one.
1229 *lpBufferSize
= bytesNeeded
;
1232 TRACE("Returning %d\n", ret
);
1236 static DWORD
_enumerateConnectedW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1237 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1239 DWORD ret
, index
, count
, size
, i
, len
, left
;
1241 LPNETRESOURCEW curr
, buffer
;
1245 return WN_BAD_POINTER
;
1246 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONNECTED
)
1247 return WN_BAD_VALUE
;
1249 return WN_BAD_POINTER
;
1251 return WN_BAD_POINTER
;
1253 return WN_BAD_POINTER
;
1255 return WN_NO_NETWORK
;
1257 handles
= enumerator
->lpBuffer
;
1258 left
= *lpBufferSize
;
1259 size
= *lpBufferSize
;
1260 buffer
= HeapAlloc(GetProcessHeap(), 0, *lpBufferSize
);
1262 return WN_NO_NETWORK
;
1265 end
= (PVOID
)((ULONG_PTR
)lpBuffer
+ size
);
1269 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1271 if (providerTable
->table
[index
].dwEnumScopes
)
1273 if (handles
[index
] == 0)
1275 ret
= providerTable
->table
[index
].openEnum(enumerator
->dwScope
,
1277 enumerator
->dwUsage
,
1278 NULL
, &handles
[index
]);
1279 if (ret
!= WN_SUCCESS
)
1283 ret
= providerTable
->table
[index
].enumResource(handles
[index
],
1288 if (ret
== WN_MORE_DATA
)
1294 if (ret
== WN_SUCCESS
)
1296 for (i
= 0; i
< count
; ++i
)
1298 if (left
< sizeof(NETRESOURCEW
))
1304 memcpy(curr
, &buffer
[i
], sizeof(NETRESOURCEW
));
1305 left
-= sizeof(NETRESOURCEW
);
1307 len
= WideCharToMultiByte(CP_ACP
, 0, buffer
[i
].lpLocalName
, -1, NULL
, 0, NULL
, NULL
);
1308 len
*= sizeof(WCHAR
);
1315 end
= (PVOID
)((ULONG_PTR
)end
- len
);
1316 curr
->lpLocalName
= end
;
1317 memcpy(end
, buffer
[i
].lpLocalName
, len
);
1320 len
= WideCharToMultiByte(CP_ACP
, 0, buffer
[i
].lpRemoteName
, -1, NULL
, 0, NULL
, NULL
);
1321 len
*= sizeof(WCHAR
);
1328 end
= (PVOID
)((ULONG_PTR
)end
- len
);
1329 curr
->lpRemoteName
= end
;
1330 memcpy(end
, buffer
[i
].lpRemoteName
, len
);
1333 len
= WideCharToMultiByte(CP_ACP
, 0, buffer
[i
].lpProvider
, -1, NULL
, 0, NULL
, NULL
);
1334 len
*= sizeof(WCHAR
);
1341 end
= (PVOID
)((ULONG_PTR
)end
- len
);
1342 curr
->lpProvider
= end
;
1343 memcpy(end
, buffer
[i
].lpProvider
, len
);
1349 count
= *lpcCount
- count
;
1353 if (ret
!= WN_SUCCESS
|| count
== 0)
1361 ret
= WN_NO_MORE_ENTRIES
;
1363 *lpcCount
= *lpcCount
- count
;
1364 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1367 HeapFree(GetProcessHeap(), 0, buffer
);
1369 TRACE("Returning %d\n", ret
);
1373 /*********************************************************************
1374 * WNetEnumResourceW [MPR.@]
1376 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1377 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1381 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1384 ret
= WN_BAD_POINTER
;
1386 ret
= WN_BAD_POINTER
;
1388 ret
= WN_BAD_POINTER
;
1389 else if (!lpBufferSize
)
1390 ret
= WN_BAD_POINTER
;
1391 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1393 *lpBufferSize
= sizeof(NETRESOURCEW
);
1398 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1400 switch (enumerator
->enumType
)
1402 case WNET_ENUMERATOR_TYPE_NULL
:
1403 ret
= WN_NO_MORE_ENTRIES
;
1405 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1406 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1409 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1410 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1413 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1414 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1417 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1418 ret
= _enumerateConnectedW(enumerator
, lpcCount
, lpBuffer
,
1422 WARN("bogus enumerator type!\n");
1423 ret
= WN_NO_NETWORK
;
1428 TRACE("Returning %d\n", ret
);
1432 /*********************************************************************
1433 * WNetCloseEnum [MPR.@]
1435 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1440 TRACE( "(%p)\n", hEnum
);
1444 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1446 switch (enumerator
->enumType
)
1448 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1449 handles
= enumerator
->lpBuffer
;
1450 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1452 if (providerTable
->table
[index
].dwEnumScopes
&& handles
[index
] != 0)
1453 providerTable
->table
[index
].closeEnum(handles
[index
]);
1455 HeapFree(GetProcessHeap(), 0, handles
);
1457 case WNET_ENUMERATOR_TYPE_NULL
:
1460 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1461 if (enumerator
->lpBuffer
)
1462 _freeEnumNetResource(enumerator
->lpBuffer
);
1463 if (enumerator
->handle
)
1464 providerTable
->table
[enumerator
->providerIndex
].
1465 closeEnum(enumerator
->handle
);
1468 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1469 if (enumerator
->handle
)
1470 providerTable
->table
[enumerator
->providerIndex
].
1471 closeEnum(enumerator
->handle
);
1475 WARN("bogus enumerator type!\n");
1476 ret
= WN_BAD_HANDLE
;
1478 HeapFree(GetProcessHeap(), 0, hEnum
);
1481 ret
= WN_BAD_HANDLE
;
1484 TRACE("Returning %d\n", ret
);
1488 /*********************************************************************
1489 * WNetGetResourceInformationA [MPR.@]
1491 * See WNetGetResourceInformationW
1493 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1494 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1499 TRACE( "(%p, %p, %p, %p)\n",
1500 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1502 if (!providerTable
|| providerTable
->numProviders
== 0)
1503 ret
= WN_NO_NETWORK
;
1504 else if (lpNetResource
)
1506 LPNETRESOURCEW lpNetResourceW
= NULL
;
1507 DWORD size
= 1024, count
= 1;
1510 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1511 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1512 if (ret
== WN_MORE_DATA
)
1514 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1515 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1517 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1518 &count
, lpNetResourceW
, &size
);
1520 ret
= WN_OUT_OF_MEMORY
;
1522 if (ret
== WN_SUCCESS
)
1524 LPWSTR lpSystemW
= NULL
;
1527 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1530 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1531 lpBufferW
, &size
, &lpSystemW
);
1532 if (ret
== WN_MORE_DATA
)
1534 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1535 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1537 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1538 lpBufferW
, &size
, &lpSystemW
);
1540 ret
= WN_OUT_OF_MEMORY
;
1542 if (ret
== WN_SUCCESS
)
1544 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1545 &count
, lpBuffer
, cbBuffer
);
1546 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1547 lpNetResourceW
= lpBufferW
;
1548 size
= sizeof(NETRESOURCEA
);
1549 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1550 -1, NULL
, 0, NULL
, NULL
);
1551 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1552 -1, NULL
, 0, NULL
, NULL
);
1554 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1555 -1, NULL
, 0, NULL
, NULL
);
1556 if ((len
) && ( size
+ len
< *cbBuffer
))
1558 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1559 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1560 *lplpSystem
, len
, NULL
, NULL
);
1567 ret
= WN_OUT_OF_MEMORY
;
1568 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1571 ret
= WN_OUT_OF_MEMORY
;
1572 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1574 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1577 ret
= WN_NO_NETWORK
;
1581 TRACE("Returning %d\n", ret
);
1585 /*********************************************************************
1586 * WNetGetResourceInformationW [MPR.@]
1588 * WNetGetResourceInformationW function identifies the network provider
1589 * that owns the resource and gets information about the type of the resource.
1592 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1593 * defines a network resource.
1594 * lpBuffer [ O] the pointer to buffer, containing result. It
1595 * contains NETRESOURCEW structure and strings to
1596 * which the members of the NETRESOURCEW structure
1598 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1600 * lplpSystem [ O] the pointer to string in the output buffer,
1601 * containing the part of the resource name without
1602 * names of the server and share.
1605 * NO_ERROR if the function succeeds. System error code if the function fails.
1608 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1609 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1610 LPWSTR
*lplpSystem
)
1612 DWORD ret
= WN_NO_NETWORK
;
1615 TRACE( "(%p, %p, %p, %p)\n",
1616 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1619 ret
= WN_OUT_OF_MEMORY
;
1620 else if (providerTable
!= NULL
)
1622 /* FIXME: For function value of a variable is indifferent, it does
1623 * search of all providers in a network.
1625 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1627 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1628 WNNC_DLG_GETRESOURCEINFORMATION
)
1630 if (providerTable
->table
[index
].getResourceInformation
)
1631 ret
= providerTable
->table
[index
].getResourceInformation(
1632 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1634 ret
= WN_NO_NETWORK
;
1635 if (ret
== WN_SUCCESS
)
1645 /*********************************************************************
1646 * WNetGetResourceParentA [MPR.@]
1648 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA 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
;
1658 /*********************************************************************
1659 * WNetGetResourceParentW [MPR.@]
1661 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1662 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1664 FIXME( "(%p, %p, %p): stub\n",
1665 lpNetResource
, lpBuffer
, lpBufferSize
);
1667 SetLastError(WN_NO_NETWORK
);
1668 return WN_NO_NETWORK
;
1674 * Connection Functions
1677 /*********************************************************************
1678 * WNetAddConnectionA [MPR.@]
1680 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1681 LPCSTR lpLocalName
)
1683 NETRESOURCEA resourcesA
;
1685 memset(&resourcesA
, 0, sizeof(resourcesA
));
1686 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
1687 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
1688 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1691 /*********************************************************************
1692 * WNetAddConnectionW [MPR.@]
1694 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1695 LPCWSTR lpLocalName
)
1697 NETRESOURCEW resourcesW
;
1699 memset(&resourcesW
, 0, sizeof(resourcesW
));
1700 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
1701 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
1702 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1705 /*********************************************************************
1706 * WNetAddConnection2A [MPR.@]
1708 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1709 LPCSTR lpPassword
, LPCSTR lpUserID
,
1712 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1716 /*********************************************************************
1717 * WNetAddConnection2W [MPR.@]
1719 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1720 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1723 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1727 /*********************************************************************
1728 * WNetAddConnection3A [MPR.@]
1730 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1731 LPCSTR lpPassword
, LPCSTR lpUserID
,
1734 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1735 dwFlags
, NULL
, 0, NULL
);
1738 /*********************************************************************
1739 * WNetAddConnection3W [MPR.@]
1741 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1742 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1745 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1746 dwFlags
, NULL
, 0, NULL
);
1749 struct use_connection_context
1752 NETRESOURCEW
*resource
;
1753 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
1760 DWORD (*pre_set_accessname
)(struct use_connection_context
*, WCHAR
*);
1761 void (*set_accessname
)(struct use_connection_context
*, WCHAR
*);
1764 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1766 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1771 len
= strlenW(local_name
);
1773 len
= strlenW(ctxt
->resource
->lpRemoteName
);
1775 if (++len
> *ctxt
->buffer_size
)
1777 *ctxt
->buffer_size
= len
;
1778 return ERROR_MORE_DATA
;
1782 ctxt
->accessname
= NULL
;
1784 return ERROR_SUCCESS
;
1787 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1789 WCHAR
*accessname
= ctxt
->accessname
;
1792 strcpyW(accessname
, local_name
);
1794 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1797 strcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
1800 static WCHAR
* select_provider(struct use_connection_context
*ctxt
)
1802 DWORD ret
, prov_size
= 0x1000, len
;
1803 LPNETRESOURCEW provider
;
1805 WCHAR
* provider_name
;
1807 provider
= HeapAlloc(GetProcessHeap(), 0, prov_size
);
1813 ret
= WNetGetResourceInformationW(ctxt
->resource
, provider
, &prov_size
, &system
);
1814 if (ret
== ERROR_MORE_DATA
)
1816 HeapFree(GetProcessHeap(), 0, provider
);
1817 provider
= HeapAlloc(GetProcessHeap(), 0, prov_size
);
1823 ret
= WNetGetResourceInformationW(ctxt
->resource
, provider
, &prov_size
, &system
);
1826 if (ret
!= NO_ERROR
)
1828 HeapFree(GetProcessHeap(), 0, provider
);
1832 len
= WideCharToMultiByte(CP_ACP
, 0, provider
->lpProvider
, -1, NULL
, 0, NULL
, NULL
);
1833 provider_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1835 memcpy(provider_name
, provider
->lpProvider
, len
* sizeof(WCHAR
));
1837 HeapFree(GetProcessHeap(), 0, provider
);
1839 return provider_name
;
1842 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
1844 WNetProvider
*provider
;
1845 DWORD index
, ret
, caps
;
1846 BOOLEAN redirect
= FALSE
, prov
= FALSE
;
1847 WCHAR letter
[3] = {'z', ':', 0};
1848 NETRESOURCEW netres
;
1850 if (!providerTable
|| providerTable
->numProviders
== 0)
1851 return WN_NO_NETWORK
;
1853 if (!ctxt
->resource
)
1854 return ERROR_INVALID_PARAMETER
;
1855 netres
= *ctxt
->resource
;
1857 if (!netres
.lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
1859 if (netres
.dwType
!= RESOURCETYPE_DISK
&& netres
.dwType
!= RESOURCETYPE_PRINT
)
1861 return ERROR_BAD_DEV_TYPE
;
1864 if (netres
.dwType
== RESOURCETYPE_PRINT
)
1866 FIXME("Locale device selection is not implemented for printers.\n");
1867 return WN_NO_NETWORK
;
1871 netres
.lpLocalName
= letter
;
1874 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
1876 return ERROR_BAD_NET_NAME
;
1879 if (ctxt
->flags
& CONNECT_UPDATE_PROFILE
)
1880 FIXME("Connection saving is not implemented\n");
1882 if (!netres
.lpProvider
)
1884 netres
.lpProvider
= select_provider(ctxt
);
1885 if (!netres
.lpProvider
)
1887 return ERROR_NO_NET_OR_BAD_PATH
;
1893 index
= _findProviderIndexW(netres
.lpProvider
);
1894 if (index
== BAD_PROVIDER_INDEX
)
1896 ret
= ERROR_BAD_PROVIDER
;
1900 provider
= &providerTable
->table
[index
];
1901 caps
= provider
->getCaps(WNNC_CONNECTION
);
1902 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
1904 ret
= ERROR_BAD_PROVIDER
;
1908 if ((ret
= ctxt
->pre_set_accessname(ctxt
, netres
.lpLocalName
)))
1913 ret
= WN_ACCESS_DENIED
;
1916 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
1917 ret
= provider
->addConnection3(ctxt
->hwndOwner
, &netres
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
1918 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
1919 ret
= provider
->addConnection(&netres
, ctxt
->password
, ctxt
->userid
);
1921 if (ret
!= NO_ERROR
&& redirect
)
1923 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& letter
[0] >= 'c');
1925 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
1926 ctxt
->set_accessname(ctxt
, netres
.lpLocalName
);
1930 HeapFree(GetProcessHeap(), 0, netres
.lpProvider
);
1935 /*****************************************************************
1936 * WNetUseConnectionW [MPR.@]
1938 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
1939 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
1941 struct use_connection_context ctxt
;
1943 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1944 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
1945 accessname
, buffer_size
, result
);
1947 ctxt
.hwndOwner
= hwndOwner
;
1948 ctxt
.resource
= resource
;
1949 ctxt
.resourceA
= NULL
;
1950 ctxt
.password
= (WCHAR
*)password
;
1951 ctxt
.userid
= (WCHAR
*)userid
;
1953 ctxt
.accessname
= accessname
;
1954 ctxt
.buffer_size
= buffer_size
;
1955 ctxt
.result
= result
;
1956 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
1957 ctxt
.set_accessname
= use_connection_set_accessnameW
;
1959 return wnet_use_connection(&ctxt
);
1962 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1964 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1969 len
= WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, NULL
, 0, NULL
, NULL
) - 1;
1971 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
1973 if (++len
> *ctxt
->buffer_size
)
1975 *ctxt
->buffer_size
= len
;
1976 return ERROR_MORE_DATA
;
1980 ctxt
->accessname
= NULL
;
1982 return ERROR_SUCCESS
;
1985 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1987 char *accessname
= ctxt
->accessname
;
1990 WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, accessname
, *ctxt
->buffer_size
, NULL
, NULL
);
1992 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1995 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
1998 static LPWSTR
strdupAtoW( LPCSTR str
)
2003 if (!str
) return NULL
;
2004 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
2005 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2006 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
2010 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
2012 resourceW
->dwScope
= resourceA
->dwScope
;
2013 resourceW
->dwType
= resourceA
->dwType
;
2014 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
2015 resourceW
->dwUsage
= resourceA
->dwUsage
;
2016 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
2017 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
2018 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
2019 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
2022 static void free_netresourceW( NETRESOURCEW
*resource
)
2024 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
2025 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
2026 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
2027 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
2030 /*****************************************************************
2031 * WNetUseConnectionA [MPR.@]
2033 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
2034 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
2035 DWORD
*buffer_size
, DWORD
*result
)
2037 struct use_connection_context ctxt
;
2038 NETRESOURCEW resourceW
;
2041 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
2042 accessname
, buffer_size
, result
);
2044 netresource_a_to_w(resource
, &resourceW
);
2046 ctxt
.hwndOwner
= hwndOwner
;
2047 ctxt
.resource
= &resourceW
;
2048 ctxt
.resourceA
= resource
;
2049 ctxt
.password
= strdupAtoW(password
);
2050 ctxt
.userid
= strdupAtoW(userid
);
2052 ctxt
.accessname
= accessname
;
2053 ctxt
.buffer_size
= buffer_size
;
2054 ctxt
.result
= result
;
2055 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
2056 ctxt
.set_accessname
= use_connection_set_accessnameA
;
2058 ret
= wnet_use_connection(&ctxt
);
2060 free_netresourceW(&resourceW
);
2061 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
2062 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
2067 /*********************************************************************
2068 * WNetCancelConnectionA [MPR.@]
2070 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
2072 return WNetCancelConnection2A(lpName
, 0, fForce
);
2075 /*********************************************************************
2076 * WNetCancelConnectionW [MPR.@]
2078 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
2080 return WNetCancelConnection2W(lpName
, 0, fForce
);
2083 /*********************************************************************
2084 * WNetCancelConnection2A [MPR.@]
2086 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2089 WCHAR
* name
= strdupAtoW(lpName
);
2091 return ERROR_NOT_CONNECTED
;
2093 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
2094 HeapFree(GetProcessHeap(), 0, name
);
2099 /*********************************************************************
2100 * WNetCancelConnection2W [MPR.@]
2102 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2104 DWORD ret
= WN_NO_NETWORK
;
2107 if (providerTable
!= NULL
)
2109 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2111 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2112 WNNC_CON_GETCONNECTIONS
)
2114 if (providerTable
->table
[index
].cancelConnection
)
2115 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
2117 ret
= WN_NO_NETWORK
;
2118 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
2126 /*****************************************************************
2127 * WNetRestoreConnectionA [MPR.@]
2129 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
2131 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
2133 SetLastError(WN_NO_NETWORK
);
2134 return WN_NO_NETWORK
;
2137 /*****************************************************************
2138 * WNetRestoreConnectionW [MPR.@]
2140 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
2142 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
2144 SetLastError(WN_NO_NETWORK
);
2145 return WN_NO_NETWORK
;
2148 /**************************************************************************
2149 * WNetGetConnectionA [MPR.@]
2152 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2153 * - WN_NOT_CONNECTED drive is a local drive
2154 * - WN_MORE_DATA buffer isn't big enough
2155 * - WN_SUCCESS success (net path in buffer)
2157 * FIXME: need to test return values under different errors
2159 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
2160 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
2165 ret
= WN_BAD_POINTER
;
2166 else if (!lpBufferSize
)
2167 ret
= WN_BAD_POINTER
;
2168 else if (!lpRemoteName
&& *lpBufferSize
)
2169 ret
= WN_BAD_POINTER
;
2172 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
2176 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2180 WCHAR wideRemoteStatic
[MAX_PATH
];
2181 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
2183 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
2185 /* try once without memory allocation */
2186 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
2188 if (ret
== WN_SUCCESS
)
2190 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2191 -1, NULL
, 0, NULL
, NULL
);
2193 if (len
<= *lpBufferSize
)
2195 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
2196 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2201 *lpBufferSize
= len
;
2205 else if (ret
== WN_MORE_DATA
)
2207 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2208 wideRemoteSize
* sizeof(WCHAR
));
2212 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2214 if (ret
== WN_SUCCESS
)
2216 if (len
<= *lpBufferSize
)
2218 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2219 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2224 *lpBufferSize
= len
;
2228 HeapFree(GetProcessHeap(), 0, wideRemote
);
2231 ret
= WN_OUT_OF_MEMORY
;
2233 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2236 ret
= WN_OUT_OF_MEMORY
;
2239 ret
= WN_BAD_LOCALNAME
;
2243 TRACE("Returning %d\n", ret
);
2247 /* find the network connection for a given drive; helper for WNetGetConnection */
2248 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2252 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2254 DWORD ret
= WN_NOT_CONNECTED
;
2255 DWORD bytes_returned
;
2257 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2258 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2259 0, 0 )) == INVALID_HANDLE_VALUE
)
2261 ERR( "failed to open mount manager err %u\n", GetLastError() );
2264 memset( data
, 0, sizeof(*data
) );
2265 data
->letter
= letter
;
2266 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2267 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2269 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2272 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2275 mount_point
[0] = '\\';
2276 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2278 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2286 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2294 DWORD ret
= WN_NO_NETWORK
;
2296 WCHAR local
[3] = {letter
, ':', 0};
2298 if (providerTable
!= NULL
)
2300 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2302 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2303 WNNC_CON_GETCONNECTIONS
)
2305 if (providerTable
->table
[index
].getConnection
)
2306 ret
= providerTable
->table
[index
].getConnection(
2307 local
, remote
, size
);
2309 ret
= WN_NO_NETWORK
;
2310 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2321 /**************************************************************************
2322 * WNetGetConnectionW [MPR.@]
2324 * FIXME: need to test return values under different errors
2326 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2327 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2331 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2335 ret
= WN_BAD_POINTER
;
2336 else if (!lpBufferSize
)
2337 ret
= WN_BAD_POINTER
;
2338 else if (!lpRemoteName
&& *lpBufferSize
)
2339 ret
= WN_BAD_POINTER
;
2340 else if (!lpLocalName
[0])
2341 ret
= WN_BAD_LOCALNAME
;
2344 if (lpLocalName
[1] == ':')
2346 switch(GetDriveTypeW(lpLocalName
))
2349 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2351 case DRIVE_REMOVABLE
:
2354 TRACE("file is local\n");
2355 ret
= WN_NOT_CONNECTED
;
2358 ret
= WN_BAD_LOCALNAME
;
2362 ret
= WN_BAD_LOCALNAME
;
2366 TRACE("Returning %d\n", ret
);
2370 /**************************************************************************
2371 * WNetSetConnectionA [MPR.@]
2373 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2376 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2378 SetLastError(WN_NO_NETWORK
);
2379 return WN_NO_NETWORK
;
2382 /**************************************************************************
2383 * WNetSetConnectionW [MPR.@]
2385 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2388 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2390 SetLastError(WN_NO_NETWORK
);
2391 return WN_NO_NETWORK
;
2394 /*****************************************************************
2395 * WNetGetUniversalNameA [MPR.@]
2397 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2398 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2402 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2403 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2405 switch (dwInfoLevel
)
2407 case UNIVERSAL_NAME_INFO_LEVEL
:
2409 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2411 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2413 err
= ERROR_NOT_CONNECTED
;
2417 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2418 if (*lpBufferSize
< size
)
2423 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2424 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2428 case REMOTE_NAME_INFO_LEVEL
:
2429 err
= WN_NOT_CONNECTED
;
2441 /*****************************************************************
2442 * WNetGetUniversalNameW [MPR.@]
2444 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2445 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2449 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2450 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2452 switch (dwInfoLevel
)
2454 case UNIVERSAL_NAME_INFO_LEVEL
:
2456 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2458 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2460 err
= ERROR_NOT_CONNECTED
;
2464 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2465 if (*lpBufferSize
< size
)
2470 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2471 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2475 case REMOTE_NAME_INFO_LEVEL
:
2476 err
= WN_NO_NETWORK
;
2484 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2494 /**************************************************************************
2495 * WNetGetUserA [MPR.@]
2497 * FIXME: we should not return ourselves, but the owner of the drive lpName
2499 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2501 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2502 return GetLastError();
2505 /*****************************************************************
2506 * WNetGetUserW [MPR.@]
2508 * FIXME: we should not return ourselves, but the owner of the drive lpName
2510 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2512 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2513 return GetLastError();
2516 /*********************************************************************
2517 * WNetConnectionDialog [MPR.@]
2519 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2521 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2523 SetLastError(WN_NO_NETWORK
);
2524 return WN_NO_NETWORK
;
2527 /*********************************************************************
2528 * WNetConnectionDialog1A [MPR.@]
2530 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2532 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2534 SetLastError(WN_NO_NETWORK
);
2535 return WN_NO_NETWORK
;
2538 /*********************************************************************
2539 * WNetConnectionDialog1W [MPR.@]
2541 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2543 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2545 SetLastError(WN_NO_NETWORK
);
2546 return WN_NO_NETWORK
;
2549 /*********************************************************************
2550 * WNetDisconnectDialog [MPR.@]
2552 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2554 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2556 SetLastError(WN_NO_NETWORK
);
2557 return WN_NO_NETWORK
;
2560 /*********************************************************************
2561 * WNetDisconnectDialog1A [MPR.@]
2563 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2565 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2567 SetLastError(WN_NO_NETWORK
);
2568 return WN_NO_NETWORK
;
2571 /*********************************************************************
2572 * WNetDisconnectDialog1W [MPR.@]
2574 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2576 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2578 SetLastError(WN_NO_NETWORK
);
2579 return WN_NO_NETWORK
;
2582 /*********************************************************************
2583 * WNetGetLastErrorA [MPR.@]
2585 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2586 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2587 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2589 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2590 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2592 SetLastError(WN_NO_NETWORK
);
2593 return WN_NO_NETWORK
;
2596 /*********************************************************************
2597 * WNetGetLastErrorW [MPR.@]
2599 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2600 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2601 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2603 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2604 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2606 SetLastError(WN_NO_NETWORK
);
2607 return WN_NO_NETWORK
;
2610 /*********************************************************************
2611 * WNetGetNetworkInformationA [MPR.@]
2613 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2614 LPNETINFOSTRUCT lpNetInfoStruct
)
2618 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2621 ret
= WN_BAD_POINTER
;
2626 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2629 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2633 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2635 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2636 HeapFree(GetProcessHeap(), 0, wideProvider
);
2639 ret
= WN_OUT_OF_MEMORY
;
2642 ret
= GetLastError();
2646 TRACE("Returning %d\n", ret
);
2650 /*********************************************************************
2651 * WNetGetNetworkInformationW [MPR.@]
2653 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2654 LPNETINFOSTRUCT lpNetInfoStruct
)
2658 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2661 ret
= WN_BAD_POINTER
;
2662 else if (!lpNetInfoStruct
)
2663 ret
= WN_BAD_POINTER
;
2664 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2668 if (providerTable
&& providerTable
->numProviders
)
2670 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2672 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2674 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2675 lpNetInfoStruct
->dwProviderVersion
=
2676 providerTable
->table
[providerIndex
].dwSpecVersion
;
2677 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2678 lpNetInfoStruct
->dwCharacteristics
= 0;
2679 lpNetInfoStruct
->dwHandle
= 0;
2680 lpNetInfoStruct
->wNetType
=
2681 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2682 lpNetInfoStruct
->dwPrinters
= -1;
2683 lpNetInfoStruct
->dwDrives
= -1;
2687 ret
= WN_BAD_PROVIDER
;
2690 ret
= WN_NO_NETWORK
;
2694 TRACE("Returning %d\n", ret
);
2698 /*****************************************************************
2699 * WNetGetProviderNameA [MPR.@]
2701 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2702 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2706 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2710 ret
= WN_BAD_POINTER
;
2711 else if (!lpBufferSize
)
2712 ret
= WN_BAD_POINTER
;
2719 ret
= WN_NO_NETWORK
;
2720 for (i
= 0; i
< providerTable
->numProviders
&&
2721 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2724 if (i
< providerTable
->numProviders
)
2726 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2727 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2729 if (*lpBufferSize
< sizeNeeded
)
2731 *lpBufferSize
= sizeNeeded
;
2736 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2737 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2739 /* FIXME: is *lpBufferSize set to the number of characters
2745 ret
= WN_NO_NETWORK
;
2749 TRACE("Returning %d\n", ret
);
2753 /*****************************************************************
2754 * WNetGetProviderNameW [MPR.@]
2756 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2757 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2761 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2765 ret
= WN_BAD_POINTER
;
2766 else if (!lpBufferSize
)
2767 ret
= WN_BAD_POINTER
;
2774 ret
= WN_NO_NETWORK
;
2775 for (i
= 0; i
< providerTable
->numProviders
&&
2776 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2779 if (i
< providerTable
->numProviders
)
2781 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2783 if (*lpBufferSize
< sizeNeeded
)
2785 *lpBufferSize
= sizeNeeded
;
2790 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2792 /* FIXME: is *lpBufferSize set to the number of characters
2798 ret
= WN_NO_NETWORK
;
2802 TRACE("Returning %d\n", ret
);