4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
7 * Copyright 2016-2018 Pierre Schweitzer
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #define WINE_MOUNTMGR_EXTENSIONS
34 #include "ddk/mountmgr.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(mpr
);
42 /* Data structures representing network service providers. Assumes only one
43 * thread creates them, and that they are constant for the life of the process
44 * (and therefore doesn't synchronize access).
45 * FIXME: only basic provider data and enumeration-related data are implemented
46 * so far, need to implement the rest too.
48 typedef struct _WNetProvider
56 PF_NPOpenEnum openEnum
;
57 PF_NPEnumResource enumResource
;
58 PF_NPCloseEnum closeEnum
;
59 PF_NPGetResourceInformation getResourceInformation
;
60 PF_NPAddConnection addConnection
;
61 PF_NPAddConnection3 addConnection3
;
62 PF_NPCancelConnection cancelConnection
;
63 } WNetProvider
, *PWNetProvider
;
65 typedef struct _WNetProviderTable
70 WNetProvider table
[1];
71 } WNetProviderTable
, *PWNetProviderTable
;
73 #define WNET_ENUMERATOR_TYPE_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
, ARRAY_SIZE(serviceName
), serviceFmt
, servicePrefix
, provider
);
134 serviceName
[ARRAY_SIZE(serviceName
) - 1] = '\0';
135 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
138 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
140 WCHAR providerPath
[MAX_PATH
];
141 DWORD type
, size
= sizeof(providerPath
);
143 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
144 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
146 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
149 if (type
== REG_EXPAND_SZ
)
151 WCHAR path
[MAX_PATH
];
152 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
156 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
159 name
= HeapAlloc(GetProcessHeap(), 0, size
);
160 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
161 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
163 HeapFree(GetProcessHeap(), 0, name
);
169 HMODULE hLib
= LoadLibraryW(providerPath
);
173 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
175 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
177 TRACE("loaded lib %p\n", hLib
);
181 PWNetProvider provider
=
182 &providerTable
->table
[providerTable
->numProviders
];
184 provider
->hLib
= hLib
;
185 provider
->name
= name
;
186 TRACE("name is %s\n", debugstr_w(name
));
187 provider
->getCaps
= getCaps
;
188 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
189 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
190 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
191 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
192 if (provider
->dwEnumScopes
)
194 TRACE("supports enumeration\n");
195 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
196 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
197 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
198 TRACE("NPEnumResource %p\n", provider
->enumResource
);
199 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
200 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
201 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
202 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
203 if (!provider
->openEnum
||
204 !provider
->enumResource
||
205 !provider
->closeEnum
)
207 provider
->openEnum
= NULL
;
208 provider
->enumResource
= NULL
;
209 provider
->closeEnum
= NULL
;
210 provider
->dwEnumScopes
= 0;
211 WARN("Couldn't load enumeration functions\n");
214 connectCap
= getCaps(WNNC_CONNECTION
);
215 if (connectCap
& WNNC_CON_ADDCONNECTION
)
216 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
217 if (connectCap
& WNNC_CON_ADDCONNECTION3
)
218 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
219 if (connectCap
& WNNC_CON_CANCELCONNECTION
)
220 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
221 TRACE("NPAddConnection %p\n", provider
->addConnection
);
222 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
223 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
224 providerTable
->numProviders
++;
228 WARN("Provider %s didn't export NPGetCaps\n",
229 debugstr_w(provider
));
230 HeapFree(GetProcessHeap(), 0, name
);
238 WARN("Couldn't load library %s for provider %s\n",
239 debugstr_w(providerPath
), debugstr_w(provider
));
240 HeapFree(GetProcessHeap(), 0, name
);
245 WARN("Couldn't get provider name for provider %s\n",
246 debugstr_w(provider
));
250 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
254 WARN("Couldn't open service key for provider %s\n",
255 debugstr_w(provider
));
258 void wnetInit(HINSTANCE hInstDll
)
260 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
261 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
262 'C','o','n','t','r','o','l','\\',
263 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
264 'O','r','d','e','r',0 };
265 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
266 'O','r','d','e','r',0 };
269 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
274 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
277 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
283 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
284 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
289 TRACE("provider order is %s\n", debugstr_w(providers
));
290 /* first count commas as a heuristic for how many to
291 * allocate space for */
292 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
294 ptr
= strchrW(ptr
, ',');
301 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
302 sizeof(WNetProviderTable
)
303 + (numToAllocate
- 1) * sizeof(WNetProvider
));
307 int entireNetworkLen
;
308 LPCWSTR stringresource
;
310 entireNetworkLen
= LoadStringW(hInstDll
,
311 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
312 providerTable
->entireNetwork
= HeapAlloc(
313 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
315 if (providerTable
->entireNetwork
)
317 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
318 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
320 providerTable
->numAllocated
= numToAllocate
;
321 for (ptr
= providers
; ptr
; )
324 ptr
= strchrW(ptr
, ',');
327 _tryLoadProvider(ptrPrev
);
331 HeapFree(GetProcessHeap(), 0, providers
);
344 for (i
= 0; i
< providerTable
->numProviders
; i
++)
346 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
347 FreeModule(providerTable
->table
[i
].hLib
);
349 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
350 HeapFree(GetProcessHeap(), 0, providerTable
);
351 providerTable
= NULL
;
355 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
357 DWORD ret
= BAD_PROVIDER_INDEX
;
359 if (providerTable
&& providerTable
->numProviders
)
363 for (i
= 0; i
< providerTable
->numProviders
&&
364 ret
== BAD_PROVIDER_INDEX
; i
++)
365 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
375 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
381 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
387 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
388 if (lpNet
->lpRemoteName
)
390 len
= strlenW(lpNet
->lpRemoteName
) + 1;
391 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
392 if (ret
->lpRemoteName
)
393 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
402 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
406 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
407 HeapFree(GetProcessHeap(), 0, lpNet
);
411 static PWNetEnumerator
_createNullEnumerator(void)
413 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
414 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
417 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
421 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
422 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
424 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
425 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
429 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
430 ret
->dwScope
= dwScope
;
431 ret
->dwType
= dwType
;
432 ret
->dwUsage
= dwUsage
;
433 ret
->specific
.net
= _copyNetResourceForEnumW(lpNet
);
438 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
439 DWORD dwUsage
, DWORD index
, HANDLE handle
)
443 if (!providerTable
|| index
>= providerTable
->numProviders
)
447 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
450 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
451 ret
->providerIndex
= index
;
452 ret
->dwScope
= dwScope
;
453 ret
->dwType
= dwType
;
454 ret
->dwUsage
= dwUsage
;
455 ret
->handle
= handle
;
461 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
464 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
465 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
469 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
470 ret
->dwScope
= dwScope
;
471 ret
->dwType
= dwType
;
472 ret
->dwUsage
= dwUsage
;
477 static PWNetEnumerator
_createConnectedEnumerator(DWORD dwScope
, DWORD dwType
,
480 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
483 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONNECTED
;
484 ret
->dwScope
= dwScope
;
485 ret
->dwType
= dwType
;
486 ret
->dwUsage
= dwUsage
;
487 ret
->specific
.handles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HANDLE
) * providerTable
->numProviders
);
488 if (!ret
->specific
.handles
)
490 HeapFree(GetProcessHeap(), 0, ret
);
497 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
498 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
499 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
500 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
501 * if not all members of the array could be thunked, and something else on
504 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
505 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
507 DWORD i
, numToThunk
, totalBytes
, ret
;
511 return WN_BAD_POINTER
;
513 return WN_BAD_POINTER
;
517 return WN_BAD_POINTER
;
519 return WN_BAD_POINTER
;
521 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
523 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
525 totalBytes
+= sizeof(NETRESOURCEA
);
526 if (lpNet
->lpLocalName
)
527 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
528 -1, NULL
, 0, NULL
, NULL
);
529 if (lpNet
->lpRemoteName
)
530 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
531 -1, NULL
, 0, NULL
, NULL
);
532 if (lpNet
->lpComment
)
533 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
534 -1, NULL
, 0, NULL
, NULL
);
535 if (lpNet
->lpProvider
)
536 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
537 -1, NULL
, 0, NULL
, NULL
);
538 if (totalBytes
< *lpBufferSize
)
541 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
542 for (i
= 0; i
< numToThunk
; i
++)
544 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
545 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
547 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
548 /* lie about string lengths, we already verified how many
549 * we have space for above
551 if (lpNetIn
->lpLocalName
)
553 lpNetOut
->lpLocalName
= strNext
;
554 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
555 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
557 if (lpNetIn
->lpRemoteName
)
559 lpNetOut
->lpRemoteName
= strNext
;
560 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
561 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
563 if (lpNetIn
->lpComment
)
565 lpNetOut
->lpComment
= strNext
;
566 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
567 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
569 if (lpNetIn
->lpProvider
)
571 lpNetOut
->lpProvider
= strNext
;
572 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
573 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
576 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
577 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
582 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
583 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
584 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
585 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
586 * if not all members of the array could be thunked, and something else on
589 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
590 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
592 DWORD i
, numToThunk
, totalBytes
, ret
;
596 return WN_BAD_POINTER
;
598 return WN_BAD_POINTER
;
602 return WN_BAD_POINTER
;
604 return WN_BAD_POINTER
;
606 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
608 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
610 totalBytes
+= sizeof(NETRESOURCEW
);
611 if (lpNet
->lpLocalName
)
612 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
613 -1, NULL
, 0) * sizeof(WCHAR
);
614 if (lpNet
->lpRemoteName
)
615 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
616 -1, NULL
, 0) * sizeof(WCHAR
);
617 if (lpNet
->lpComment
)
618 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
619 -1, NULL
, 0) * sizeof(WCHAR
);
620 if (lpNet
->lpProvider
)
621 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
622 -1, NULL
, 0) * sizeof(WCHAR
);
623 if (totalBytes
< *lpBufferSize
)
626 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
627 for (i
= 0; i
< numToThunk
; i
++)
629 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
630 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
632 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
633 /* lie about string lengths, we already verified how many
634 * we have space for above
636 if (lpNetIn
->lpLocalName
)
638 lpNetOut
->lpLocalName
= strNext
;
639 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
640 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
642 if (lpNetIn
->lpRemoteName
)
644 lpNetOut
->lpRemoteName
= strNext
;
645 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
646 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
648 if (lpNetIn
->lpComment
)
650 lpNetOut
->lpComment
= strNext
;
651 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
652 -1, lpNetOut
->lpComment
, *lpBufferSize
);
654 if (lpNetIn
->lpProvider
)
656 lpNetOut
->lpProvider
= strNext
;
657 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
658 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
661 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
662 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
667 /*********************************************************************
668 * WNetOpenEnumA [MPR.@]
670 * See comments for WNetOpenEnumW.
672 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
673 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
677 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
678 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
681 ret
= WN_BAD_POINTER
;
682 else if (!providerTable
|| providerTable
->numProviders
== 0)
691 LPNETRESOURCEW lpNetWide
= NULL
;
693 DWORD size
= sizeof(buf
), count
= 1;
694 BOOL allocated
= FALSE
;
696 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
697 if (ret
== WN_MORE_DATA
)
699 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
703 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
708 ret
= WN_OUT_OF_MEMORY
;
710 else if (ret
== WN_SUCCESS
)
711 lpNetWide
= (LPNETRESOURCEW
)buf
;
712 if (ret
== WN_SUCCESS
)
713 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
716 HeapFree(GetProcessHeap(), 0, lpNetWide
);
719 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
723 TRACE("Returning %d\n", ret
);
727 /*********************************************************************
728 * WNetOpenEnumW [MPR.@]
730 * Network enumeration has way too many parameters, so I'm not positive I got
731 * them right. What I've got so far:
733 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
734 * all the network providers should be enumerated.
736 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
737 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
738 * lpProvider is set, all the network providers should be enumerated.
739 * (This means the enumeration is a list of network providers, not that the
740 * enumeration is passed on to the providers.)
742 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
743 * resource matches the "Entire Network" resource (no remote name, no
744 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
745 * enumeration is done on every network provider.
747 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
748 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
749 * only to the given network provider.
751 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
752 * no lpProvider is set, enumeration will be tried on every network provider,
753 * in the order in which they're loaded.
755 * - The LPNETRESOURCE should be disregarded for scopes besides
756 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
757 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
759 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
760 * resource in the enumerated list, as well as any machines in your
761 * workgroup. The machines in your workgroup come from doing a
762 * RESOURCE_CONTEXT enumeration of every Network Provider.
764 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
765 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
769 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
770 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
773 ret
= WN_BAD_POINTER
;
774 else if (!providerTable
|| providerTable
->numProviders
== 0)
783 case RESOURCE_GLOBALNET
:
786 if (lpNet
->lpProvider
)
788 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
790 if (index
!= BAD_PROVIDER_INDEX
)
792 if (providerTable
->table
[index
].openEnum
&&
793 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
796 PWSTR RemoteName
= lpNet
->lpRemoteName
;
798 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
799 RemoteName
&& !strcmpW(RemoteName
, lpNet
->lpProvider
))
800 lpNet
->lpRemoteName
= NULL
;
802 ret
= providerTable
->table
[index
].openEnum(
803 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
804 if (ret
== WN_SUCCESS
)
806 *lphEnum
= _createProviderEnumerator(
807 dwScope
, dwType
, dwUsage
, index
, handle
);
808 ret
= *lphEnum
? WN_SUCCESS
:
812 lpNet
->lpRemoteName
= RemoteName
;
815 ret
= WN_NOT_SUPPORTED
;
818 ret
= WN_BAD_PROVIDER
;
820 else if (lpNet
->lpRemoteName
)
822 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
823 dwType
, dwUsage
, lpNet
);
824 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
828 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
829 providerTable
->entireNetwork
))
831 /* comment matches the "Entire Network", enumerate
832 * global scope of every provider
834 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
835 dwType
, dwUsage
, lpNet
);
839 /* this is the same as not having passed lpNet */
840 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
841 dwType
, dwUsage
, NULL
);
843 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
848 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
850 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
853 case RESOURCE_CONTEXT
:
854 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
855 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
857 case RESOURCE_CONNECTED
:
858 *lphEnum
= _createConnectedEnumerator(dwScope
, dwType
, dwUsage
);
859 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
861 case RESOURCE_REMEMBERED
:
862 *lphEnum
= _createNullEnumerator();
863 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
866 WARN("unknown scope 0x%08x\n", dwScope
);
872 TRACE("Returning %d\n", ret
);
876 /*********************************************************************
877 * WNetEnumResourceA [MPR.@]
879 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
880 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
884 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
887 ret
= WN_BAD_POINTER
;
889 ret
= WN_BAD_POINTER
;
891 ret
= WN_BAD_POINTER
;
892 else if (!lpBufferSize
)
893 ret
= WN_BAD_POINTER
;
894 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
896 *lpBufferSize
= sizeof(NETRESOURCEA
);
901 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
902 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
906 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
908 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
910 /* FIXME: this isn't necessarily going to work in the case of
911 * WN_MORE_DATA, because our enumerator may have moved on to
912 * the next provider. MSDN states that a large (16KB) buffer
913 * size is the appropriate usage of this function, so
914 * hopefully it won't be an issue.
916 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
917 lpBuffer
, lpBufferSize
);
918 *lpcCount
= localCount
;
920 HeapFree(GetProcessHeap(), 0, localBuffer
);
923 ret
= WN_OUT_OF_MEMORY
;
927 TRACE("Returning %d\n", ret
);
931 static DWORD
_countProviderBytesW(PWNetProvider provider
)
937 ret
= sizeof(NETRESOURCEW
);
938 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
945 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
946 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
951 return WN_BAD_POINTER
;
952 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
955 return WN_BAD_POINTER
;
957 return WN_BAD_POINTER
;
959 return WN_BAD_POINTER
;
960 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
963 if (!providerTable
|| enumerator
->providerIndex
>=
964 providerTable
->numProviders
)
965 ret
= WN_NO_MORE_ENTRIES
;
968 DWORD bytes
= 0, count
= 0, countLimit
, i
;
969 LPNETRESOURCEW resource
;
972 countLimit
= *lpcCount
== -1 ?
973 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
974 while (count
< countLimit
&& bytes
< *lpBufferSize
)
976 DWORD bytesNext
= _countProviderBytesW(
977 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
979 if (bytes
+ bytesNext
< *lpBufferSize
)
985 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
986 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
988 resource
->dwScope
= RESOURCE_GLOBALNET
;
989 resource
->dwType
= RESOURCETYPE_ANY
;
990 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
991 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
992 RESOURCEUSAGE_RESERVED
;
993 resource
->lpLocalName
= NULL
;
994 resource
->lpRemoteName
= strNext
;
995 strcpyW(resource
->lpRemoteName
,
996 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
997 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
998 resource
->lpComment
= NULL
;
999 resource
->lpProvider
= strNext
;
1000 strcpyW(resource
->lpProvider
,
1001 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
1002 strNext
+= strlenW(resource
->lpProvider
) + 1;
1004 enumerator
->providerIndex
+= count
;
1006 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
1008 TRACE("Returning %d\n", ret
);
1012 /* Advances the enumerator (assumed to be a global enumerator) to the next
1013 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
1014 * not open a handle with the next provider.
1015 * If the existing handle is NULL, may leave the enumerator unchanged, since
1016 * the current provider may support the desired scope.
1017 * If the existing handle is not NULL, closes it before moving on.
1018 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
1019 * provider, and another error on failure.
1021 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
1024 return WN_BAD_POINTER
;
1025 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1026 return WN_BAD_VALUE
;
1027 if (!providerTable
|| enumerator
->providerIndex
>=
1028 providerTable
->numProviders
)
1029 return WN_NO_MORE_ENTRIES
;
1031 if (enumerator
->providerDone
)
1034 enumerator
->providerDone
= FALSE
;
1035 if (enumerator
->handle
)
1037 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1038 enumerator
->handle
);
1039 enumerator
->handle
= NULL
;
1040 enumerator
->providerIndex
++;
1042 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1043 dwEnum
= WNNC_ENUM_LOCAL
;
1044 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1045 dwEnum
= WNNC_ENUM_GLOBAL
;
1046 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1047 dwEnum
= WNNC_ENUM_CONTEXT
;
1048 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1049 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1050 & dwEnum
); enumerator
->providerIndex
++)
1053 return enumerator
->providerIndex
< providerTable
->numProviders
?
1054 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1057 /* "Passes through" call to the next provider that supports the enumeration
1059 * FIXME: if one call to a provider's enumerator succeeds while there's still
1060 * space in lpBuffer, I don't call to the next provider. The caller may not
1061 * expect that it should call EnumResourceW again with a return value of
1062 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1063 * may have to be moved around a bit, ick.
1065 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1066 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1071 return WN_BAD_POINTER
;
1072 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1073 return WN_BAD_VALUE
;
1075 return WN_BAD_POINTER
;
1077 return WN_BAD_POINTER
;
1079 return WN_BAD_POINTER
;
1080 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1081 return WN_MORE_DATA
;
1083 ret
= _globalEnumeratorAdvance(enumerator
);
1084 if (ret
== WN_SUCCESS
)
1086 ret
= providerTable
->table
[enumerator
->providerIndex
].
1087 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1088 enumerator
->dwUsage
, enumerator
->specific
.net
,
1089 &enumerator
->handle
);
1090 if (ret
== WN_SUCCESS
)
1092 ret
= providerTable
->table
[enumerator
->providerIndex
].
1093 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1095 if (ret
!= WN_MORE_DATA
)
1096 enumerator
->providerDone
= TRUE
;
1099 TRACE("Returning %d\n", ret
);
1103 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1104 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1109 return WN_BAD_POINTER
;
1110 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1111 return WN_BAD_VALUE
;
1113 return WN_BAD_POINTER
;
1115 return WN_BAD_POINTER
;
1117 return WN_BAD_POINTER
;
1118 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1119 return WN_MORE_DATA
;
1121 return WN_NO_NETWORK
;
1123 switch (enumerator
->dwScope
)
1125 case RESOURCE_GLOBALNET
:
1126 if (enumerator
->specific
.net
)
1127 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1128 lpBuffer
, lpBufferSize
);
1130 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1133 case RESOURCE_CONTEXT
:
1134 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1138 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1139 ret
= WN_NO_MORE_ENTRIES
;
1141 TRACE("Returning %d\n", ret
);
1145 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1146 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1149 return WN_BAD_POINTER
;
1150 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1151 return WN_BAD_VALUE
;
1152 if (!enumerator
->handle
)
1153 return WN_BAD_VALUE
;
1155 return WN_BAD_POINTER
;
1157 return WN_BAD_POINTER
;
1159 return WN_BAD_POINTER
;
1161 return WN_NO_NETWORK
;
1162 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1163 return WN_NO_MORE_ENTRIES
;
1164 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1165 return WN_BAD_VALUE
;
1166 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1167 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1170 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1171 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1174 size_t cchEntireNetworkLen
, bytesNeeded
;
1177 return WN_BAD_POINTER
;
1178 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1179 return WN_BAD_VALUE
;
1181 return WN_BAD_POINTER
;
1183 return WN_BAD_POINTER
;
1185 return WN_BAD_POINTER
;
1187 return WN_NO_NETWORK
;
1189 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1190 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1191 if (*lpBufferSize
< bytesNeeded
)
1193 *lpBufferSize
= bytesNeeded
;
1198 LPNETRESOURCEW lpNet
= lpBuffer
;
1200 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1201 lpNet
->dwType
= enumerator
->dwType
;
1202 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1203 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1204 lpNet
->lpLocalName
= NULL
;
1205 lpNet
->lpRemoteName
= NULL
;
1206 lpNet
->lpProvider
= NULL
;
1207 /* odd, but correct: put comment at end of buffer, so it won't get
1208 * overwritten by subsequent calls to a provider's enumResource
1210 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1211 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1212 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1215 if (ret
== WN_SUCCESS
)
1217 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1219 /* "Entire Network" entry enumerated--morph this into a global
1220 * enumerator. enumerator->lpNet continues to be NULL, since it has
1221 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1223 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1224 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1225 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1226 if (ret
== WN_SUCCESS
)
1228 /* reflect the fact that we already enumerated "Entire Network" */
1230 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1234 /* the provider enumeration failed, but we already succeeded in
1235 * enumerating "Entire Network"--leave type as global to allow a
1236 * retry, but indicate success with a count of one.
1240 *lpBufferSize
= bytesNeeded
;
1243 TRACE("Returning %d\n", ret
);
1247 static DWORD
_copyStringToEnumW(const WCHAR
*source
, DWORD
* left
, void** end
)
1250 WCHAR
* local
= *end
;
1252 len
= strlenW(source
) + 1;
1253 len
*= sizeof(WCHAR
);
1255 return WN_MORE_DATA
;
1257 local
-= (len
/ sizeof(WCHAR
));
1258 memcpy(local
, source
, len
);
1265 static DWORD
_enumerateConnectedW(PWNetEnumerator enumerator
, DWORD
* user_count
,
1266 void* user_buffer
, DWORD
* user_size
)
1268 DWORD ret
, index
, count
, total_count
, size
, i
, left
;
1270 NETRESOURCEW
* curr
, * buffer
;
1274 return WN_BAD_POINTER
;
1275 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONNECTED
)
1276 return WN_BAD_VALUE
;
1277 if (!user_count
|| !user_buffer
|| !user_size
)
1278 return WN_BAD_POINTER
;
1280 return WN_NO_NETWORK
;
1282 handles
= enumerator
->specific
.handles
;
1285 buffer
= HeapAlloc(GetProcessHeap(), 0, *user_size
);
1287 return WN_NO_NETWORK
;
1290 end
= (char *)user_buffer
+ size
;
1291 count
= *user_count
;
1294 ret
= WN_NO_MORE_ENTRIES
;
1295 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1297 if (providerTable
->table
[index
].dwEnumScopes
)
1299 if (handles
[index
] == 0)
1301 ret
= providerTable
->table
[index
].openEnum(enumerator
->dwScope
,
1303 enumerator
->dwUsage
,
1304 NULL
, &handles
[index
]);
1305 if (ret
!= WN_SUCCESS
)
1309 ret
= providerTable
->table
[index
].enumResource(handles
[index
],
1312 total_count
+= count
;
1313 if (ret
== WN_MORE_DATA
)
1316 if (ret
== WN_SUCCESS
)
1318 for (i
= 0; i
< count
; ++i
)
1320 if (left
< sizeof(NETRESOURCEW
))
1326 memcpy(curr
, &buffer
[i
], sizeof(NETRESOURCEW
));
1327 left
-= sizeof(NETRESOURCEW
);
1329 ret
= _copyStringToEnumW(buffer
[i
].lpLocalName
, &left
, &end
);
1330 if (ret
== WN_MORE_DATA
)
1332 curr
->lpLocalName
= end
;
1334 ret
= _copyStringToEnumW(buffer
[i
].lpRemoteName
, &left
, &end
);
1335 if (ret
== WN_MORE_DATA
)
1337 curr
->lpRemoteName
= end
;
1339 ret
= _copyStringToEnumW(buffer
[i
].lpProvider
, &left
, &end
);
1340 if (ret
== WN_MORE_DATA
)
1342 curr
->lpProvider
= end
;
1350 if (*user_count
!= -1)
1351 count
= *user_count
- total_count
;
1353 count
= *user_count
;
1357 if (total_count
== 0)
1358 ret
= WN_NO_MORE_ENTRIES
;
1360 *user_count
= total_count
;
1361 if (ret
!= WN_MORE_DATA
&& ret
!= WN_NO_MORE_ENTRIES
)
1364 HeapFree(GetProcessHeap(), 0, buffer
);
1366 TRACE("Returning %d\n", ret
);
1370 /*********************************************************************
1371 * WNetEnumResourceW [MPR.@]
1373 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1374 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1378 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1381 ret
= WN_BAD_POINTER
;
1383 ret
= WN_BAD_POINTER
;
1385 ret
= WN_BAD_POINTER
;
1386 else if (!lpBufferSize
)
1387 ret
= WN_BAD_POINTER
;
1388 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1390 *lpBufferSize
= sizeof(NETRESOURCEW
);
1395 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1397 switch (enumerator
->enumType
)
1399 case WNET_ENUMERATOR_TYPE_NULL
:
1400 ret
= WN_NO_MORE_ENTRIES
;
1402 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1403 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1406 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1407 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1410 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1411 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1414 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1415 ret
= _enumerateConnectedW(enumerator
, lpcCount
, lpBuffer
,
1419 WARN("bogus enumerator type!\n");
1420 ret
= WN_NO_NETWORK
;
1425 TRACE("Returning %d\n", ret
);
1429 /*********************************************************************
1430 * WNetCloseEnum [MPR.@]
1432 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1437 TRACE( "(%p)\n", hEnum
);
1441 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1443 switch (enumerator
->enumType
)
1445 case WNET_ENUMERATOR_TYPE_NULL
:
1448 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1449 if (enumerator
->specific
.net
)
1450 _freeEnumNetResource(enumerator
->specific
.net
);
1451 if (enumerator
->handle
)
1452 providerTable
->table
[enumerator
->providerIndex
].
1453 closeEnum(enumerator
->handle
);
1456 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1457 if (enumerator
->handle
)
1458 providerTable
->table
[enumerator
->providerIndex
].
1459 closeEnum(enumerator
->handle
);
1462 case WNET_ENUMERATOR_TYPE_CONNECTED
:
1463 handles
= enumerator
->specific
.handles
;
1464 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1466 if (providerTable
->table
[index
].dwEnumScopes
&& handles
[index
])
1467 providerTable
->table
[index
].closeEnum(handles
[index
]);
1469 HeapFree(GetProcessHeap(), 0, handles
);
1473 WARN("bogus enumerator type!\n");
1474 ret
= WN_BAD_HANDLE
;
1476 HeapFree(GetProcessHeap(), 0, hEnum
);
1479 ret
= WN_BAD_HANDLE
;
1482 TRACE("Returning %d\n", ret
);
1486 /*********************************************************************
1487 * WNetGetResourceInformationA [MPR.@]
1489 * See WNetGetResourceInformationW
1491 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1492 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1497 TRACE( "(%p, %p, %p, %p)\n",
1498 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1500 if (!providerTable
|| providerTable
->numProviders
== 0)
1501 ret
= WN_NO_NETWORK
;
1502 else if (lpNetResource
)
1504 LPNETRESOURCEW lpNetResourceW
= NULL
;
1505 DWORD size
= 1024, count
= 1;
1508 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1509 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1510 if (ret
== WN_MORE_DATA
)
1512 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1513 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1515 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1516 &count
, lpNetResourceW
, &size
);
1518 ret
= WN_OUT_OF_MEMORY
;
1520 if (ret
== WN_SUCCESS
)
1522 LPWSTR lpSystemW
= NULL
;
1525 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1528 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1529 lpBufferW
, &size
, &lpSystemW
);
1530 if (ret
== WN_MORE_DATA
)
1532 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1533 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1535 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1536 lpBufferW
, &size
, &lpSystemW
);
1538 ret
= WN_OUT_OF_MEMORY
;
1540 if (ret
== WN_SUCCESS
)
1542 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1543 &count
, lpBuffer
, cbBuffer
);
1544 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1545 lpNetResourceW
= lpBufferW
;
1546 size
= sizeof(NETRESOURCEA
);
1547 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1548 -1, NULL
, 0, NULL
, NULL
);
1549 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1550 -1, NULL
, 0, NULL
, NULL
);
1552 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1553 -1, NULL
, 0, NULL
, NULL
);
1554 if ((len
) && ( size
+ len
< *cbBuffer
))
1556 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1557 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1558 *lplpSystem
, len
, NULL
, NULL
);
1565 ret
= WN_OUT_OF_MEMORY
;
1566 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1569 ret
= WN_OUT_OF_MEMORY
;
1570 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1572 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1575 ret
= WN_NO_NETWORK
;
1579 TRACE("Returning %d\n", ret
);
1583 /*********************************************************************
1584 * WNetGetResourceInformationW [MPR.@]
1586 * WNetGetResourceInformationW function identifies the network provider
1587 * that owns the resource and gets information about the type of the resource.
1590 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1591 * defines a network resource.
1592 * lpBuffer [ O] the pointer to buffer, containing result. It
1593 * contains NETRESOURCEW structure and strings to
1594 * which the members of the NETRESOURCEW structure
1596 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1598 * lplpSystem [ O] the pointer to string in the output buffer,
1599 * containing the part of the resource name without
1600 * names of the server and share.
1603 * NO_ERROR if the function succeeds. System error code if the function fails.
1606 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1607 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1608 LPWSTR
*lplpSystem
)
1610 DWORD ret
= WN_NO_NETWORK
;
1613 TRACE( "(%p, %p, %p, %p)\n",
1614 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1617 ret
= WN_OUT_OF_MEMORY
;
1618 else if (providerTable
!= NULL
)
1620 /* FIXME: For function value of a variable is indifferent, it does
1621 * search of all providers in a network.
1623 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1625 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1626 WNNC_DLG_GETRESOURCEINFORMATION
)
1628 if (providerTable
->table
[index
].getResourceInformation
)
1629 ret
= providerTable
->table
[index
].getResourceInformation(
1630 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1632 ret
= WN_NO_NETWORK
;
1633 if (ret
== WN_SUCCESS
)
1643 /*********************************************************************
1644 * WNetGetResourceParentA [MPR.@]
1646 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1647 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1649 FIXME( "(%p, %p, %p): stub\n",
1650 lpNetResource
, lpBuffer
, lpBufferSize
);
1652 SetLastError(WN_NO_NETWORK
);
1653 return WN_NO_NETWORK
;
1656 /*********************************************************************
1657 * WNetGetResourceParentW [MPR.@]
1659 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1660 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1662 FIXME( "(%p, %p, %p): stub\n",
1663 lpNetResource
, lpBuffer
, lpBufferSize
);
1665 SetLastError(WN_NO_NETWORK
);
1666 return WN_NO_NETWORK
;
1672 * Connection Functions
1675 /*********************************************************************
1676 * WNetAddConnectionA [MPR.@]
1678 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1679 LPCSTR lpLocalName
)
1681 NETRESOURCEA resourcesA
;
1683 memset(&resourcesA
, 0, sizeof(resourcesA
));
1684 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
1685 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
1686 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1689 /*********************************************************************
1690 * WNetAddConnectionW [MPR.@]
1692 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1693 LPCWSTR lpLocalName
)
1695 NETRESOURCEW resourcesW
;
1697 memset(&resourcesW
, 0, sizeof(resourcesW
));
1698 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
1699 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
1700 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1703 /*********************************************************************
1704 * WNetAddConnection2A [MPR.@]
1706 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1707 LPCSTR lpPassword
, LPCSTR lpUserID
,
1710 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1714 /*********************************************************************
1715 * WNetAddConnection2W [MPR.@]
1717 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1718 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1721 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1725 /*********************************************************************
1726 * WNetAddConnection3A [MPR.@]
1728 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1729 LPCSTR lpPassword
, LPCSTR lpUserID
,
1732 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1733 dwFlags
, NULL
, 0, NULL
);
1736 /*********************************************************************
1737 * WNetAddConnection3W [MPR.@]
1739 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1740 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1743 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1744 dwFlags
, NULL
, 0, NULL
);
1747 struct use_connection_context
1750 NETRESOURCEW
*resource
;
1751 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
1758 DWORD (*pre_set_accessname
)(struct use_connection_context
*, WCHAR
*);
1759 void (*set_accessname
)(struct use_connection_context
*, WCHAR
*);
1762 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1764 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1769 len
= strlenW(local_name
);
1771 len
= strlenW(ctxt
->resource
->lpRemoteName
);
1773 if (++len
> *ctxt
->buffer_size
)
1775 *ctxt
->buffer_size
= len
;
1776 return ERROR_MORE_DATA
;
1780 ctxt
->accessname
= NULL
;
1782 return ERROR_SUCCESS
;
1785 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1787 WCHAR
*accessname
= ctxt
->accessname
;
1790 strcpyW(accessname
, local_name
);
1792 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1795 strcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
1798 static DWORD
wnet_use_provider( struct use_connection_context
*ctxt
, NETRESOURCEW
* netres
, WNetProvider
*provider
, BOOLEAN redirect
)
1802 caps
= provider
->getCaps(WNNC_CONNECTION
);
1803 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
1804 return ERROR_BAD_PROVIDER
;
1806 ret
= WN_ACCESS_DENIED
;
1809 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
1810 ret
= provider
->addConnection3(ctxt
->hwndOwner
, netres
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
1811 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
1812 ret
= provider
->addConnection(netres
, ctxt
->password
, ctxt
->userid
);
1814 if (ret
== WN_ALREADY_CONNECTED
&& redirect
)
1815 netres
->lpLocalName
[0] -= 1;
1816 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& netres
->lpLocalName
[0] >= 'C');
1818 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
1819 ctxt
->set_accessname(ctxt
, netres
->lpLocalName
);
1824 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
1826 WNetProvider
*provider
;
1827 DWORD index
, ret
= WN_NO_NETWORK
;
1828 BOOL redirect
= FALSE
;
1829 WCHAR letter
[3] = {'Z', ':', 0};
1830 NETRESOURCEW netres
;
1832 if (!providerTable
|| providerTable
->numProviders
== 0)
1833 return WN_NO_NETWORK
;
1835 if (!ctxt
->resource
)
1836 return ERROR_INVALID_PARAMETER
;
1837 netres
= *ctxt
->resource
;
1839 if (!netres
.lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
1841 if (netres
.dwType
!= RESOURCETYPE_DISK
&& netres
.dwType
!= RESOURCETYPE_PRINT
)
1842 return ERROR_BAD_DEV_TYPE
;
1844 if (netres
.dwType
== RESOURCETYPE_PRINT
)
1846 FIXME("Local device selection is not implemented for printers.\n");
1847 return WN_NO_NETWORK
;
1851 netres
.lpLocalName
= letter
;
1854 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
1855 return ERROR_BAD_NET_NAME
;
1857 if ((ret
= ctxt
->pre_set_accessname(ctxt
, netres
.lpLocalName
)))
1860 if (netres
.lpProvider
)
1862 index
= _findProviderIndexW(netres
.lpProvider
);
1863 if (index
== BAD_PROVIDER_INDEX
)
1864 return ERROR_BAD_PROVIDER
;
1866 provider
= &providerTable
->table
[index
];
1867 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
1871 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1873 provider
= &providerTable
->table
[index
];
1874 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
1875 if (ret
== WN_SUCCESS
|| ret
== WN_ALREADY_CONNECTED
)
1883 /*****************************************************************
1884 * WNetUseConnectionW [MPR.@]
1886 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
1887 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
1889 struct use_connection_context ctxt
;
1891 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1892 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
1893 accessname
, buffer_size
, result
);
1895 ctxt
.hwndOwner
= hwndOwner
;
1896 ctxt
.resource
= resource
;
1897 ctxt
.resourceA
= NULL
;
1898 ctxt
.password
= (WCHAR
*)password
;
1899 ctxt
.userid
= (WCHAR
*)userid
;
1901 ctxt
.accessname
= accessname
;
1902 ctxt
.buffer_size
= buffer_size
;
1903 ctxt
.result
= result
;
1904 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
1905 ctxt
.set_accessname
= use_connection_set_accessnameW
;
1907 return wnet_use_connection(&ctxt
);
1910 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1912 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1917 len
= WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, NULL
, 0, NULL
, NULL
) - 1;
1919 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
1921 if (++len
> *ctxt
->buffer_size
)
1923 *ctxt
->buffer_size
= len
;
1924 return ERROR_MORE_DATA
;
1928 ctxt
->accessname
= NULL
;
1930 return ERROR_SUCCESS
;
1933 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1935 char *accessname
= ctxt
->accessname
;
1938 WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, accessname
, *ctxt
->buffer_size
, NULL
, NULL
);
1940 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1943 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
1946 static LPWSTR
strdupAtoW( LPCSTR str
)
1951 if (!str
) return NULL
;
1952 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
1953 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1954 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
1958 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
1960 resourceW
->dwScope
= resourceA
->dwScope
;
1961 resourceW
->dwType
= resourceA
->dwType
;
1962 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
1963 resourceW
->dwUsage
= resourceA
->dwUsage
;
1964 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
1965 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
1966 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
1967 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
1970 static void free_netresourceW( NETRESOURCEW
*resource
)
1972 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
1973 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
1974 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
1975 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
1978 /*****************************************************************
1979 * WNetUseConnectionA [MPR.@]
1981 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
1982 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
1983 DWORD
*buffer_size
, DWORD
*result
)
1985 struct use_connection_context ctxt
;
1986 NETRESOURCEW resourceW
;
1989 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
1990 accessname
, buffer_size
, result
);
1992 netresource_a_to_w(resource
, &resourceW
);
1994 ctxt
.hwndOwner
= hwndOwner
;
1995 ctxt
.resource
= &resourceW
;
1996 ctxt
.resourceA
= resource
;
1997 ctxt
.password
= strdupAtoW(password
);
1998 ctxt
.userid
= strdupAtoW(userid
);
2000 ctxt
.accessname
= accessname
;
2001 ctxt
.buffer_size
= buffer_size
;
2002 ctxt
.result
= result
;
2003 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
2004 ctxt
.set_accessname
= use_connection_set_accessnameA
;
2006 ret
= wnet_use_connection(&ctxt
);
2008 free_netresourceW(&resourceW
);
2009 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
2010 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
2015 /*********************************************************************
2016 * WNetCancelConnectionA [MPR.@]
2018 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
2020 return WNetCancelConnection2A(lpName
, 0, fForce
);
2023 /*********************************************************************
2024 * WNetCancelConnectionW [MPR.@]
2026 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
2028 return WNetCancelConnection2W(lpName
, 0, fForce
);
2031 /*********************************************************************
2032 * WNetCancelConnection2A [MPR.@]
2034 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2037 WCHAR
* name
= strdupAtoW(lpName
);
2039 return ERROR_NOT_CONNECTED
;
2041 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
2042 HeapFree(GetProcessHeap(), 0, name
);
2047 /*********************************************************************
2048 * WNetCancelConnection2W [MPR.@]
2050 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
2052 DWORD ret
= WN_NO_NETWORK
;
2055 if (providerTable
!= NULL
)
2057 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2059 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2060 WNNC_CON_CANCELCONNECTION
)
2062 if (providerTable
->table
[index
].cancelConnection
)
2063 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
2065 ret
= WN_NO_NETWORK
;
2066 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
2074 /*****************************************************************
2075 * WNetRestoreConnectionA [MPR.@]
2077 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
2079 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
2081 SetLastError(WN_NO_NETWORK
);
2082 return WN_NO_NETWORK
;
2085 /*****************************************************************
2086 * WNetRestoreConnectionW [MPR.@]
2088 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
2090 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
2092 SetLastError(WN_NO_NETWORK
);
2093 return WN_NO_NETWORK
;
2096 /**************************************************************************
2097 * WNetGetConnectionA [MPR.@]
2100 * - WN_BAD_LOCALNAME lpLocalName makes no sense
2101 * - WN_NOT_CONNECTED drive is a local drive
2102 * - WN_MORE_DATA buffer isn't big enough
2103 * - WN_SUCCESS success (net path in buffer)
2105 * FIXME: need to test return values under different errors
2107 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
2108 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
2113 ret
= WN_BAD_POINTER
;
2114 else if (!lpBufferSize
)
2115 ret
= WN_BAD_POINTER
;
2116 else if (!lpRemoteName
&& *lpBufferSize
)
2117 ret
= WN_BAD_POINTER
;
2120 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
2124 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2128 WCHAR wideRemoteStatic
[MAX_PATH
];
2129 DWORD wideRemoteSize
= ARRAY_SIZE(wideRemoteStatic
);
2131 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
2133 /* try once without memory allocation */
2134 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
2136 if (ret
== WN_SUCCESS
)
2138 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2139 -1, NULL
, 0, NULL
, NULL
);
2141 if (len
<= *lpBufferSize
)
2143 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
2144 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2149 *lpBufferSize
= len
;
2153 else if (ret
== WN_MORE_DATA
)
2155 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2156 wideRemoteSize
* sizeof(WCHAR
));
2160 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2162 if (ret
== WN_SUCCESS
)
2164 if (len
<= *lpBufferSize
)
2166 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2167 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2172 *lpBufferSize
= len
;
2176 HeapFree(GetProcessHeap(), 0, wideRemote
);
2179 ret
= WN_OUT_OF_MEMORY
;
2181 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2184 ret
= WN_OUT_OF_MEMORY
;
2187 ret
= WN_BAD_LOCALNAME
;
2191 TRACE("Returning %d\n", ret
);
2195 /* find the network connection for a given drive; helper for WNetGetConnection */
2196 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2199 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2201 DWORD ret
= WN_NOT_CONNECTED
;
2202 DWORD bytes_returned
;
2204 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2205 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2206 0, 0 )) == INVALID_HANDLE_VALUE
)
2208 ERR( "failed to open mount manager err %u\n", GetLastError() );
2211 memset( data
, 0, sizeof(*data
) );
2212 data
->letter
= letter
;
2213 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2214 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2216 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2219 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2222 mount_point
[0] = '\\';
2223 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2225 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2233 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2242 /**************************************************************************
2243 * WNetGetConnectionW [MPR.@]
2245 * FIXME: need to test return values under different errors
2247 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2248 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2252 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2256 ret
= WN_BAD_POINTER
;
2257 else if (!lpBufferSize
)
2258 ret
= WN_BAD_POINTER
;
2259 else if (!lpRemoteName
&& *lpBufferSize
)
2260 ret
= WN_BAD_POINTER
;
2261 else if (!lpLocalName
[0])
2262 ret
= WN_BAD_LOCALNAME
;
2265 if (lpLocalName
[1] == ':')
2267 switch(GetDriveTypeW(lpLocalName
))
2270 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2272 case DRIVE_REMOVABLE
:
2275 TRACE("file is local\n");
2276 ret
= WN_NOT_CONNECTED
;
2279 ret
= WN_BAD_LOCALNAME
;
2283 ret
= WN_BAD_LOCALNAME
;
2287 TRACE("Returning %d\n", ret
);
2291 /**************************************************************************
2292 * WNetSetConnectionA [MPR.@]
2294 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2297 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2299 SetLastError(WN_NO_NETWORK
);
2300 return WN_NO_NETWORK
;
2303 /**************************************************************************
2304 * WNetSetConnectionW [MPR.@]
2306 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2309 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2311 SetLastError(WN_NO_NETWORK
);
2312 return WN_NO_NETWORK
;
2315 /*****************************************************************
2316 * WNetGetUniversalNameA [MPR.@]
2318 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2319 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2323 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2324 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2326 switch (dwInfoLevel
)
2328 case UNIVERSAL_NAME_INFO_LEVEL
:
2330 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2332 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2334 err
= ERROR_NOT_CONNECTED
;
2338 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2339 if (*lpBufferSize
< size
)
2344 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2345 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2349 case REMOTE_NAME_INFO_LEVEL
:
2350 err
= WN_NOT_CONNECTED
;
2362 /*****************************************************************
2363 * WNetGetUniversalNameW [MPR.@]
2365 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2366 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2370 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2371 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2373 switch (dwInfoLevel
)
2375 case UNIVERSAL_NAME_INFO_LEVEL
:
2377 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2379 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2381 err
= ERROR_NOT_CONNECTED
;
2385 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2386 if (*lpBufferSize
< size
)
2388 *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
);
2410 /*****************************************************************
2411 * WNetClearConnections [MPR.@]
2413 DWORD WINAPI
WNetClearConnections ( HWND owner
)
2417 DWORD ret
, size
, count
;
2418 NETRESOURCEW
* resources
, * iter
;
2420 ret
= WNetOpenEnumW(RESOURCE_CONNECTED
, RESOURCETYPE_ANY
, 0, NULL
, &connected
);
2421 if (ret
!= WN_SUCCESS
)
2423 if (ret
!= WN_NO_NETWORK
)
2428 /* Means no provider, then, clearing is OK */
2433 resources
= HeapAlloc(GetProcessHeap(), 0, size
);
2436 WNetCloseEnum(connected
);
2437 return WN_OUT_OF_MEMORY
;
2445 memset(resources
, 0, size
);
2446 ret
= WNetEnumResourceW(connected
, &count
, resources
, &size
);
2447 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2449 for (iter
= resources
; count
; count
--, iter
++)
2451 if (iter
->lpLocalName
&& iter
->lpLocalName
[0])
2452 connection
= iter
->lpLocalName
;
2454 connection
= iter
->lpRemoteName
;
2456 WNetCancelConnection2W(connection
, 0, TRUE
);
2463 HeapFree(GetProcessHeap(), 0, resources
);
2464 WNetCloseEnum(connected
);
2474 /**************************************************************************
2475 * WNetGetUserA [MPR.@]
2477 * FIXME: we should not return ourselves, but the owner of the drive lpName
2479 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2481 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2482 return GetLastError();
2485 /*****************************************************************
2486 * WNetGetUserW [MPR.@]
2488 * FIXME: we should not return ourselves, but the owner of the drive lpName
2490 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2492 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2493 return GetLastError();
2496 /*********************************************************************
2497 * WNetConnectionDialog [MPR.@]
2499 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2501 CONNECTDLGSTRUCTW conn_dlg
;
2502 NETRESOURCEW net_res
;
2504 ZeroMemory(&conn_dlg
, sizeof(conn_dlg
));
2505 ZeroMemory(&net_res
, sizeof(net_res
));
2507 conn_dlg
.cbStructure
= sizeof(conn_dlg
);
2508 conn_dlg
.lpConnRes
= &net_res
;
2509 conn_dlg
.hwndOwner
= hwnd
;
2510 net_res
.dwType
= dwType
;
2512 return WNetConnectionDialog1W(&conn_dlg
);
2515 /*********************************************************************
2516 * WNetConnectionDialog1A [MPR.@]
2518 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2520 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2522 SetLastError(WN_NO_NETWORK
);
2523 return WN_NO_NETWORK
;
2526 /*********************************************************************
2527 * WNetConnectionDialog1W [MPR.@]
2529 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2531 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2533 SetLastError(WN_NO_NETWORK
);
2534 return WN_NO_NETWORK
;
2537 /*********************************************************************
2538 * WNetDisconnectDialog [MPR.@]
2540 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2542 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2544 SetLastError(WN_NO_NETWORK
);
2545 return WN_NO_NETWORK
;
2548 /*********************************************************************
2549 * WNetDisconnectDialog1A [MPR.@]
2551 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2553 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2555 SetLastError(WN_NO_NETWORK
);
2556 return WN_NO_NETWORK
;
2559 /*********************************************************************
2560 * WNetDisconnectDialog1W [MPR.@]
2562 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2564 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2566 SetLastError(WN_NO_NETWORK
);
2567 return WN_NO_NETWORK
;
2570 /*********************************************************************
2571 * WNetGetLastErrorA [MPR.@]
2573 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2574 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2575 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2577 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2578 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2580 SetLastError(WN_NO_NETWORK
);
2581 return WN_NO_NETWORK
;
2584 /*********************************************************************
2585 * WNetGetLastErrorW [MPR.@]
2587 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2588 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2589 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2591 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2592 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2594 SetLastError(WN_NO_NETWORK
);
2595 return WN_NO_NETWORK
;
2598 /*********************************************************************
2599 * WNetGetNetworkInformationA [MPR.@]
2601 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2602 LPNETINFOSTRUCT lpNetInfoStruct
)
2606 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2609 ret
= WN_BAD_POINTER
;
2614 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2617 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2621 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2623 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2624 HeapFree(GetProcessHeap(), 0, wideProvider
);
2627 ret
= WN_OUT_OF_MEMORY
;
2630 ret
= GetLastError();
2634 TRACE("Returning %d\n", ret
);
2638 /*********************************************************************
2639 * WNetGetNetworkInformationW [MPR.@]
2641 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2642 LPNETINFOSTRUCT lpNetInfoStruct
)
2646 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2649 ret
= WN_BAD_POINTER
;
2650 else if (!lpNetInfoStruct
)
2651 ret
= WN_BAD_POINTER
;
2652 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2656 if (providerTable
&& providerTable
->numProviders
)
2658 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2660 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2662 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2663 lpNetInfoStruct
->dwProviderVersion
=
2664 providerTable
->table
[providerIndex
].dwSpecVersion
;
2665 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2666 lpNetInfoStruct
->dwCharacteristics
= 0;
2667 lpNetInfoStruct
->dwHandle
= 0;
2668 lpNetInfoStruct
->wNetType
=
2669 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2670 lpNetInfoStruct
->dwPrinters
= -1;
2671 lpNetInfoStruct
->dwDrives
= -1;
2675 ret
= WN_BAD_PROVIDER
;
2678 ret
= WN_NO_NETWORK
;
2682 TRACE("Returning %d\n", ret
);
2686 /*****************************************************************
2687 * WNetGetProviderNameA [MPR.@]
2689 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2690 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2694 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2698 ret
= WN_BAD_POINTER
;
2699 else if (!lpBufferSize
)
2700 ret
= WN_BAD_POINTER
;
2707 ret
= WN_NO_NETWORK
;
2708 for (i
= 0; i
< providerTable
->numProviders
&&
2709 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2712 if (i
< providerTable
->numProviders
)
2714 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2715 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2717 if (*lpBufferSize
< sizeNeeded
)
2719 *lpBufferSize
= sizeNeeded
;
2724 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2725 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2727 /* FIXME: is *lpBufferSize set to the number of characters
2733 ret
= WN_NO_NETWORK
;
2737 TRACE("Returning %d\n", ret
);
2741 /*****************************************************************
2742 * WNetGetProviderNameW [MPR.@]
2744 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2745 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2749 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2753 ret
= WN_BAD_POINTER
;
2754 else if (!lpBufferSize
)
2755 ret
= WN_BAD_POINTER
;
2762 ret
= WN_NO_NETWORK
;
2763 for (i
= 0; i
< providerTable
->numProviders
&&
2764 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2767 if (i
< providerTable
->numProviders
)
2769 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2771 if (*lpBufferSize
< sizeNeeded
)
2773 *lpBufferSize
= sizeNeeded
;
2778 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2780 /* FIXME: is *lpBufferSize set to the number of characters
2786 ret
= WN_NO_NETWORK
;
2790 TRACE("Returning %d\n", ret
);