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
70 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
71 * the enumeration; it represents one of the following types:
72 * - a 'null' enumeration, one that contains no members
73 * - a global enumeration, one that's executed across all providers
74 * - a provider-specific enumeration, one that's only executed by a single
76 * - a context enumeration. I know this contradicts what I just said about
77 * there being no correspondence between the scope and the type, but it's
78 * necessary for the special case that a "Entire Network" entry needs to
79 * be enumerated in an enumeration of the context scope. Thus an enumeration
80 * of the context scope results in a context type enumerator, which morphs
81 * into a global enumeration (so the enumeration continues across all
84 typedef struct _WNetEnumerator
94 } WNetEnumerator
, *PWNetEnumerator
;
96 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
98 /* Returns an index (into the global WNetProviderTable) of the provider with
99 * the given name, or BAD_PROVIDER_INDEX if not found.
101 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
103 static PWNetProviderTable providerTable
;
106 * Global provider table functions
109 static void _tryLoadProvider(PCWSTR provider
)
111 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
112 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
113 'S','e','r','v','i','c','e','s','\\',0 };
114 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
115 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
116 WCHAR serviceName
[MAX_PATH
];
119 TRACE("%s\n", debugstr_w(provider
));
120 snprintfW(serviceName
, sizeof(serviceName
) / sizeof(WCHAR
), serviceFmt
,
121 servicePrefix
, provider
);
122 serviceName
[sizeof(serviceName
) / sizeof(WCHAR
) - 1] = '\0';
123 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
126 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
128 WCHAR providerPath
[MAX_PATH
];
129 DWORD type
, size
= sizeof(providerPath
);
131 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
132 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
134 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
137 if (type
== REG_EXPAND_SZ
)
139 WCHAR path
[MAX_PATH
];
140 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
144 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
147 name
= HeapAlloc(GetProcessHeap(), 0, size
);
148 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
149 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
151 HeapFree(GetProcessHeap(), 0, name
);
157 HMODULE hLib
= LoadLibraryW(providerPath
);
161 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
163 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
165 TRACE("loaded lib %p\n", hLib
);
168 PWNetProvider provider
=
169 &providerTable
->table
[providerTable
->numProviders
];
171 provider
->hLib
= hLib
;
172 provider
->name
= name
;
173 TRACE("name is %s\n", debugstr_w(name
));
174 provider
->getCaps
= getCaps
;
175 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
176 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
177 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
178 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
179 if (provider
->dwEnumScopes
)
181 TRACE("supports enumeration\n");
182 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
183 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
184 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
185 TRACE("NPEnumResource %p\n", provider
->enumResource
);
186 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
187 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
188 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
189 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
190 if (!provider
->openEnum
||
191 !provider
->enumResource
||
192 !provider
->closeEnum
)
194 provider
->openEnum
= NULL
;
195 provider
->enumResource
= NULL
;
196 provider
->closeEnum
= NULL
;
197 provider
->dwEnumScopes
= 0;
198 WARN("Couldn't load enumeration functions\n");
201 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
202 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
203 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
205 provider
->getConnection
= MPR_GETPROC(NPGetConnection
);
207 TRACE("NPAddConnection %p\n", provider
->addConnection
);
208 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
209 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
210 providerTable
->numProviders
++;
214 WARN("Provider %s didn't export NPGetCaps\n",
215 debugstr_w(provider
));
216 HeapFree(GetProcessHeap(), 0, name
);
224 WARN("Couldn't load library %s for provider %s\n",
225 debugstr_w(providerPath
), debugstr_w(provider
));
226 HeapFree(GetProcessHeap(), 0, name
);
231 WARN("Couldn't get provider name for provider %s\n",
232 debugstr_w(provider
));
236 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
240 WARN("Couldn't open service key for provider %s\n",
241 debugstr_w(provider
));
244 void wnetInit(HINSTANCE hInstDll
)
246 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
247 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
248 'C','o','n','t','r','o','l','\\',
249 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
250 'O','r','d','e','r',0 };
251 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
252 'O','r','d','e','r',0 };
255 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
260 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
263 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
269 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
270 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
275 TRACE("provider order is %s\n", debugstr_w(providers
));
276 /* first count commas as a heuristic for how many to
277 * allocate space for */
278 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
280 ptr
= strchrW(ptr
, ',');
287 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
288 sizeof(WNetProviderTable
)
289 + (numToAllocate
- 1) * sizeof(WNetProvider
));
293 int entireNetworkLen
;
294 LPCWSTR stringresource
;
296 entireNetworkLen
= LoadStringW(hInstDll
,
297 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
298 providerTable
->entireNetwork
= HeapAlloc(
299 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
301 if (providerTable
->entireNetwork
)
303 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
304 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
306 providerTable
->numAllocated
= numToAllocate
;
307 for (ptr
= providers
; ptr
; )
310 ptr
= strchrW(ptr
, ',');
313 _tryLoadProvider(ptrPrev
);
317 HeapFree(GetProcessHeap(), 0, providers
);
330 for (i
= 0; i
< providerTable
->numProviders
; i
++)
332 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
333 FreeModule(providerTable
->table
[i
].hLib
);
335 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
336 HeapFree(GetProcessHeap(), 0, providerTable
);
337 providerTable
= NULL
;
341 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
343 DWORD ret
= BAD_PROVIDER_INDEX
;
345 if (providerTable
&& providerTable
->numProviders
)
349 for (i
= 0; i
< providerTable
->numProviders
&&
350 ret
== BAD_PROVIDER_INDEX
; i
++)
351 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
361 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
367 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
373 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
374 if (lpNet
->lpRemoteName
)
376 len
= strlenW(lpNet
->lpRemoteName
) + 1;
377 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
378 if (ret
->lpRemoteName
)
379 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
388 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
392 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
393 HeapFree(GetProcessHeap(), 0, lpNet
);
397 static PWNetEnumerator
_createNullEnumerator(void)
399 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
400 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
403 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
407 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
408 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
410 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
411 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
415 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
416 ret
->dwScope
= dwScope
;
417 ret
->dwType
= dwType
;
418 ret
->dwUsage
= dwUsage
;
419 ret
->lpNet
= _copyNetResourceForEnumW(lpNet
);
424 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
425 DWORD dwUsage
, DWORD index
, HANDLE handle
)
429 if (!providerTable
|| index
>= providerTable
->numProviders
)
433 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
436 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
437 ret
->providerIndex
= index
;
438 ret
->dwScope
= dwScope
;
439 ret
->dwType
= dwType
;
440 ret
->dwUsage
= dwUsage
;
441 ret
->handle
= handle
;
447 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
450 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
451 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
455 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
456 ret
->dwScope
= dwScope
;
457 ret
->dwType
= dwType
;
458 ret
->dwUsage
= dwUsage
;
463 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
464 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
465 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
466 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
467 * if not all members of the array could be thunked, and something else on
470 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
471 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
473 DWORD i
, numToThunk
, totalBytes
, ret
;
477 return WN_BAD_POINTER
;
479 return WN_BAD_POINTER
;
483 return WN_BAD_POINTER
;
485 return WN_BAD_POINTER
;
487 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
489 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
491 totalBytes
+= sizeof(NETRESOURCEA
);
492 if (lpNet
->lpLocalName
)
493 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
494 -1, NULL
, 0, NULL
, NULL
);
495 if (lpNet
->lpRemoteName
)
496 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
497 -1, NULL
, 0, NULL
, NULL
);
498 if (lpNet
->lpComment
)
499 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
500 -1, NULL
, 0, NULL
, NULL
);
501 if (lpNet
->lpProvider
)
502 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
503 -1, NULL
, 0, NULL
, NULL
);
504 if (totalBytes
< *lpBufferSize
)
507 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
508 for (i
= 0; i
< numToThunk
; i
++)
510 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
511 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
513 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
514 /* lie about string lengths, we already verified how many
515 * we have space for above
517 if (lpNetIn
->lpLocalName
)
519 lpNetOut
->lpLocalName
= strNext
;
520 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
521 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
523 if (lpNetIn
->lpRemoteName
)
525 lpNetOut
->lpRemoteName
= strNext
;
526 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
527 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
529 if (lpNetIn
->lpComment
)
531 lpNetOut
->lpComment
= strNext
;
532 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
533 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
535 if (lpNetIn
->lpProvider
)
537 lpNetOut
->lpProvider
= strNext
;
538 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
539 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
542 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
543 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
548 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
549 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
550 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
551 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
552 * if not all members of the array could be thunked, and something else on
555 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
556 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
558 DWORD i
, numToThunk
, totalBytes
, ret
;
562 return WN_BAD_POINTER
;
564 return WN_BAD_POINTER
;
568 return WN_BAD_POINTER
;
570 return WN_BAD_POINTER
;
572 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
574 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
576 totalBytes
+= sizeof(NETRESOURCEW
);
577 if (lpNet
->lpLocalName
)
578 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
579 -1, NULL
, 0) * sizeof(WCHAR
);
580 if (lpNet
->lpRemoteName
)
581 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
582 -1, NULL
, 0) * sizeof(WCHAR
);
583 if (lpNet
->lpComment
)
584 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
585 -1, NULL
, 0) * sizeof(WCHAR
);
586 if (lpNet
->lpProvider
)
587 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
588 -1, NULL
, 0) * sizeof(WCHAR
);
589 if (totalBytes
< *lpBufferSize
)
592 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
593 for (i
= 0; i
< numToThunk
; i
++)
595 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
596 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
598 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
599 /* lie about string lengths, we already verified how many
600 * we have space for above
602 if (lpNetIn
->lpLocalName
)
604 lpNetOut
->lpLocalName
= strNext
;
605 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
606 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
608 if (lpNetIn
->lpRemoteName
)
610 lpNetOut
->lpRemoteName
= strNext
;
611 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
612 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
614 if (lpNetIn
->lpComment
)
616 lpNetOut
->lpComment
= strNext
;
617 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
618 -1, lpNetOut
->lpComment
, *lpBufferSize
);
620 if (lpNetIn
->lpProvider
)
622 lpNetOut
->lpProvider
= strNext
;
623 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
624 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
627 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
628 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
633 /*********************************************************************
634 * WNetOpenEnumA [MPR.@]
636 * See comments for WNetOpenEnumW.
638 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
639 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
643 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
644 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
647 ret
= WN_BAD_POINTER
;
648 else if (!providerTable
|| providerTable
->numProviders
== 0)
657 LPNETRESOURCEW lpNetWide
= NULL
;
659 DWORD size
= sizeof(buf
), count
= 1;
660 BOOL allocated
= FALSE
;
662 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
663 if (ret
== WN_MORE_DATA
)
665 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
669 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
674 ret
= WN_OUT_OF_MEMORY
;
676 else if (ret
== WN_SUCCESS
)
677 lpNetWide
= (LPNETRESOURCEW
)buf
;
678 if (ret
== WN_SUCCESS
)
679 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
682 HeapFree(GetProcessHeap(), 0, lpNetWide
);
685 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
689 TRACE("Returning %d\n", ret
);
693 /*********************************************************************
694 * WNetOpenEnumW [MPR.@]
696 * Network enumeration has way too many parameters, so I'm not positive I got
697 * them right. What I've got so far:
699 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
700 * all the network providers should be enumerated.
702 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
703 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
704 * lpProvider is set, all the network providers should be enumerated.
705 * (This means the enumeration is a list of network providers, not that the
706 * enumeration is passed on to the providers.)
708 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
709 * resource matches the "Entire Network" resource (no remote name, no
710 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
711 * enumeration is done on every network provider.
713 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
714 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
715 * only to the given network provider.
717 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
718 * no lpProvider is set, enumeration will be tried on every network provider,
719 * in the order in which they're loaded.
721 * - The LPNETRESOURCE should be disregarded for scopes besides
722 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
723 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
725 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
726 * resource in the enumerated list, as well as any machines in your
727 * workgroup. The machines in your workgroup come from doing a
728 * RESOURCE_CONTEXT enumeration of every Network Provider.
730 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
731 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
735 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
736 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
739 ret
= WN_BAD_POINTER
;
740 else if (!providerTable
|| providerTable
->numProviders
== 0)
749 case RESOURCE_GLOBALNET
:
752 if (lpNet
->lpProvider
)
754 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
756 if (index
!= BAD_PROVIDER_INDEX
)
758 if (providerTable
->table
[index
].openEnum
&&
759 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
762 PWSTR RemoteName
= lpNet
->lpRemoteName
;
764 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
765 RemoteName
&& !strcmpW(RemoteName
, lpNet
->lpProvider
))
766 lpNet
->lpRemoteName
= NULL
;
768 ret
= providerTable
->table
[index
].openEnum(
769 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
770 if (ret
== WN_SUCCESS
)
772 *lphEnum
= _createProviderEnumerator(
773 dwScope
, dwType
, dwUsage
, index
, handle
);
774 ret
= *lphEnum
? WN_SUCCESS
:
778 lpNet
->lpRemoteName
= RemoteName
;
781 ret
= WN_NOT_SUPPORTED
;
784 ret
= WN_BAD_PROVIDER
;
786 else if (lpNet
->lpRemoteName
)
788 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
789 dwType
, dwUsage
, lpNet
);
790 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
794 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
795 providerTable
->entireNetwork
))
797 /* comment matches the "Entire Network", enumerate
798 * global scope of every provider
800 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
801 dwType
, dwUsage
, lpNet
);
805 /* this is the same as not having passed lpNet */
806 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
807 dwType
, dwUsage
, NULL
);
809 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
814 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
816 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
819 case RESOURCE_CONTEXT
:
820 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
821 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
823 case RESOURCE_REMEMBERED
:
824 case RESOURCE_CONNECTED
:
825 *lphEnum
= _createNullEnumerator();
826 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
829 WARN("unknown scope 0x%08x\n", dwScope
);
835 TRACE("Returning %d\n", ret
);
839 /*********************************************************************
840 * WNetEnumResourceA [MPR.@]
842 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
843 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
847 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
850 ret
= WN_BAD_POINTER
;
852 ret
= WN_BAD_POINTER
;
854 ret
= WN_BAD_POINTER
;
855 else if (!lpBufferSize
)
856 ret
= WN_BAD_POINTER
;
857 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
859 *lpBufferSize
= sizeof(NETRESOURCEA
);
864 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
865 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
869 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
871 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
873 /* FIXME: this isn't necessarily going to work in the case of
874 * WN_MORE_DATA, because our enumerator may have moved on to
875 * the next provider. MSDN states that a large (16KB) buffer
876 * size is the appropriate usage of this function, so
877 * hopefully it won't be an issue.
879 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
880 lpBuffer
, lpBufferSize
);
881 *lpcCount
= localCount
;
883 HeapFree(GetProcessHeap(), 0, localBuffer
);
886 ret
= WN_OUT_OF_MEMORY
;
890 TRACE("Returning %d\n", ret
);
894 static DWORD
_countProviderBytesW(PWNetProvider provider
)
900 ret
= sizeof(NETRESOURCEW
);
901 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
908 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
909 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
914 return WN_BAD_POINTER
;
915 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
918 return WN_BAD_POINTER
;
920 return WN_BAD_POINTER
;
922 return WN_BAD_POINTER
;
923 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
926 if (!providerTable
|| enumerator
->providerIndex
>=
927 providerTable
->numProviders
)
928 ret
= WN_NO_MORE_ENTRIES
;
931 DWORD bytes
= 0, count
= 0, countLimit
, i
;
932 LPNETRESOURCEW resource
;
935 countLimit
= *lpcCount
== -1 ?
936 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
937 while (count
< countLimit
&& bytes
< *lpBufferSize
)
939 DWORD bytesNext
= _countProviderBytesW(
940 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
942 if (bytes
+ bytesNext
< *lpBufferSize
)
948 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
949 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
951 resource
->dwScope
= RESOURCE_GLOBALNET
;
952 resource
->dwType
= RESOURCETYPE_ANY
;
953 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
954 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
955 RESOURCEUSAGE_RESERVED
;
956 resource
->lpLocalName
= NULL
;
957 resource
->lpRemoteName
= strNext
;
958 strcpyW(resource
->lpRemoteName
,
959 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
960 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
961 resource
->lpComment
= NULL
;
962 resource
->lpProvider
= strNext
;
963 strcpyW(resource
->lpProvider
,
964 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
965 strNext
+= strlenW(resource
->lpProvider
) + 1;
967 enumerator
->providerIndex
+= count
;
969 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
971 TRACE("Returning %d\n", ret
);
975 /* Advances the enumerator (assumed to be a global enumerator) to the next
976 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
977 * not open a handle with the next provider.
978 * If the existing handle is NULL, may leave the enumerator unchanged, since
979 * the current provider may support the desired scope.
980 * If the existing handle is not NULL, closes it before moving on.
981 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
982 * provider, and another error on failure.
984 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
987 return WN_BAD_POINTER
;
988 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
990 if (!providerTable
|| enumerator
->providerIndex
>=
991 providerTable
->numProviders
)
992 return WN_NO_MORE_ENTRIES
;
994 if (enumerator
->providerDone
)
997 enumerator
->providerDone
= FALSE
;
998 if (enumerator
->handle
)
1000 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1001 enumerator
->handle
);
1002 enumerator
->handle
= NULL
;
1003 enumerator
->providerIndex
++;
1005 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1006 dwEnum
= WNNC_ENUM_LOCAL
;
1007 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1008 dwEnum
= WNNC_ENUM_GLOBAL
;
1009 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1010 dwEnum
= WNNC_ENUM_CONTEXT
;
1011 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1012 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1013 & dwEnum
); enumerator
->providerIndex
++)
1016 return enumerator
->providerIndex
< providerTable
->numProviders
?
1017 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1020 /* "Passes through" call to the next provider that supports the enumeration
1022 * FIXME: if one call to a provider's enumerator succeeds while there's still
1023 * space in lpBuffer, I don't call to the next provider. The caller may not
1024 * expect that it should call EnumResourceW again with a return value of
1025 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1026 * may have to be moved around a bit, ick.
1028 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1029 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1034 return WN_BAD_POINTER
;
1035 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1036 return WN_BAD_VALUE
;
1038 return WN_BAD_POINTER
;
1040 return WN_BAD_POINTER
;
1042 return WN_BAD_POINTER
;
1043 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1044 return WN_MORE_DATA
;
1046 ret
= _globalEnumeratorAdvance(enumerator
);
1047 if (ret
== WN_SUCCESS
)
1049 ret
= providerTable
->table
[enumerator
->providerIndex
].
1050 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1051 enumerator
->dwUsage
, enumerator
->lpNet
,
1052 &enumerator
->handle
);
1053 if (ret
== WN_SUCCESS
)
1055 ret
= providerTable
->table
[enumerator
->providerIndex
].
1056 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1058 if (ret
!= WN_MORE_DATA
)
1059 enumerator
->providerDone
= TRUE
;
1062 TRACE("Returning %d\n", ret
);
1066 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1067 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1072 return WN_BAD_POINTER
;
1073 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1074 return WN_BAD_VALUE
;
1076 return WN_BAD_POINTER
;
1078 return WN_BAD_POINTER
;
1080 return WN_BAD_POINTER
;
1081 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1082 return WN_MORE_DATA
;
1084 return WN_NO_NETWORK
;
1086 switch (enumerator
->dwScope
)
1088 case RESOURCE_GLOBALNET
:
1089 if (enumerator
->lpNet
)
1090 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1091 lpBuffer
, lpBufferSize
);
1093 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1096 case RESOURCE_CONTEXT
:
1097 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1101 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1102 ret
= WN_NO_MORE_ENTRIES
;
1104 TRACE("Returning %d\n", ret
);
1108 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1109 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1112 return WN_BAD_POINTER
;
1113 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1114 return WN_BAD_VALUE
;
1115 if (!enumerator
->handle
)
1116 return WN_BAD_VALUE
;
1118 return WN_BAD_POINTER
;
1120 return WN_BAD_POINTER
;
1122 return WN_BAD_POINTER
;
1124 return WN_NO_NETWORK
;
1125 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1126 return WN_NO_MORE_ENTRIES
;
1127 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1128 return WN_BAD_VALUE
;
1129 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1130 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1133 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1134 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1137 size_t cchEntireNetworkLen
, bytesNeeded
;
1140 return WN_BAD_POINTER
;
1141 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
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
;
1152 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1153 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1154 if (*lpBufferSize
< bytesNeeded
)
1156 *lpBufferSize
= bytesNeeded
;
1161 LPNETRESOURCEW lpNet
= lpBuffer
;
1163 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1164 lpNet
->dwType
= enumerator
->dwType
;
1165 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1166 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1167 lpNet
->lpLocalName
= NULL
;
1168 lpNet
->lpRemoteName
= NULL
;
1169 lpNet
->lpProvider
= NULL
;
1170 /* odd, but correct: put comment at end of buffer, so it won't get
1171 * overwritten by subsequent calls to a provider's enumResource
1173 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1174 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1175 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1178 if (ret
== WN_SUCCESS
)
1180 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1182 /* "Entire Network" entry enumerated--morph this into a global
1183 * enumerator. enumerator->lpNet continues to be NULL, since it has
1184 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1186 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1187 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1188 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1189 if (ret
== WN_SUCCESS
)
1191 /* reflect the fact that we already enumerated "Entire Network" */
1193 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1197 /* the provider enumeration failed, but we already succeeded in
1198 * enumerating "Entire Network"--leave type as global to allow a
1199 * retry, but indicate success with a count of one.
1203 *lpBufferSize
= bytesNeeded
;
1206 TRACE("Returning %d\n", ret
);
1210 /*********************************************************************
1211 * WNetEnumResourceW [MPR.@]
1213 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1214 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1218 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1221 ret
= WN_BAD_POINTER
;
1223 ret
= WN_BAD_POINTER
;
1225 ret
= WN_BAD_POINTER
;
1226 else if (!lpBufferSize
)
1227 ret
= WN_BAD_POINTER
;
1228 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1230 *lpBufferSize
= sizeof(NETRESOURCEW
);
1235 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1237 switch (enumerator
->enumType
)
1239 case WNET_ENUMERATOR_TYPE_NULL
:
1240 ret
= WN_NO_MORE_ENTRIES
;
1242 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1243 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1246 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1247 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1250 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1251 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1255 WARN("bogus enumerator type!\n");
1256 ret
= WN_NO_NETWORK
;
1261 TRACE("Returning %d\n", ret
);
1265 /*********************************************************************
1266 * WNetCloseEnum [MPR.@]
1268 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1272 TRACE( "(%p)\n", hEnum
);
1276 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1278 switch (enumerator
->enumType
)
1280 case WNET_ENUMERATOR_TYPE_NULL
:
1283 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1284 if (enumerator
->lpNet
)
1285 _freeEnumNetResource(enumerator
->lpNet
);
1286 if (enumerator
->handle
)
1287 providerTable
->table
[enumerator
->providerIndex
].
1288 closeEnum(enumerator
->handle
);
1291 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1292 if (enumerator
->handle
)
1293 providerTable
->table
[enumerator
->providerIndex
].
1294 closeEnum(enumerator
->handle
);
1298 WARN("bogus enumerator type!\n");
1299 ret
= WN_BAD_HANDLE
;
1301 HeapFree(GetProcessHeap(), 0, hEnum
);
1304 ret
= WN_BAD_HANDLE
;
1307 TRACE("Returning %d\n", ret
);
1311 /*********************************************************************
1312 * WNetGetResourceInformationA [MPR.@]
1314 * See WNetGetResourceInformationW
1316 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1317 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1322 TRACE( "(%p, %p, %p, %p)\n",
1323 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1325 if (!providerTable
|| providerTable
->numProviders
== 0)
1326 ret
= WN_NO_NETWORK
;
1327 else if (lpNetResource
)
1329 LPNETRESOURCEW lpNetResourceW
= NULL
;
1330 DWORD size
= 1024, count
= 1;
1333 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1334 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1335 if (ret
== WN_MORE_DATA
)
1337 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1338 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1340 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1341 &count
, lpNetResourceW
, &size
);
1343 ret
= WN_OUT_OF_MEMORY
;
1345 if (ret
== WN_SUCCESS
)
1347 LPWSTR lpSystemW
= NULL
;
1350 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1353 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1354 lpBufferW
, &size
, &lpSystemW
);
1355 if (ret
== WN_MORE_DATA
)
1357 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1358 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1360 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1361 lpBufferW
, &size
, &lpSystemW
);
1363 ret
= WN_OUT_OF_MEMORY
;
1365 if (ret
== WN_SUCCESS
)
1367 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1368 &count
, lpBuffer
, cbBuffer
);
1369 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1370 lpNetResourceW
= lpBufferW
;
1371 size
= sizeof(NETRESOURCEA
);
1372 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1373 -1, NULL
, 0, NULL
, NULL
);
1374 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1375 -1, NULL
, 0, NULL
, NULL
);
1377 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1378 -1, NULL
, 0, NULL
, NULL
);
1379 if ((len
) && ( size
+ len
< *cbBuffer
))
1381 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1382 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1383 *lplpSystem
, len
, NULL
, NULL
);
1390 ret
= WN_OUT_OF_MEMORY
;
1391 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1394 ret
= WN_OUT_OF_MEMORY
;
1395 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1397 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1400 ret
= WN_NO_NETWORK
;
1404 TRACE("Returning %d\n", ret
);
1408 /*********************************************************************
1409 * WNetGetResourceInformationW [MPR.@]
1411 * WNetGetResourceInformationW function identifies the network provider
1412 * that owns the resource and gets information about the type of the resource.
1415 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1416 * defines a network resource.
1417 * lpBuffer [ O] the pointer to buffer, containing result. It
1418 * contains NETRESOURCEW structure and strings to
1419 * which the members of the NETRESOURCEW structure
1421 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1423 * lplpSystem [ O] the pointer to string in the output buffer,
1424 * containing the part of the resource name without
1425 * names of the server and share.
1428 * NO_ERROR if the function succeeds. System error code if the function fails.
1431 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1432 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1433 LPWSTR
*lplpSystem
)
1435 DWORD ret
= WN_NO_NETWORK
;
1438 TRACE( "(%p, %p, %p, %p)\n",
1439 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1442 ret
= WN_OUT_OF_MEMORY
;
1443 else if (providerTable
!= NULL
)
1445 /* FIXME: For function value of a variable is indifferent, it does
1446 * search of all providers in a network.
1448 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1450 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1451 WNNC_DLG_GETRESOURCEINFORMATION
)
1453 if (providerTable
->table
[index
].getResourceInformation
)
1454 ret
= providerTable
->table
[index
].getResourceInformation(
1455 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1457 ret
= WN_NO_NETWORK
;
1458 if (ret
== WN_SUCCESS
)
1468 /*********************************************************************
1469 * WNetGetResourceParentA [MPR.@]
1471 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1472 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1474 FIXME( "(%p, %p, %p): stub\n",
1475 lpNetResource
, lpBuffer
, lpBufferSize
);
1477 SetLastError(WN_NO_NETWORK
);
1478 return WN_NO_NETWORK
;
1481 /*********************************************************************
1482 * WNetGetResourceParentW [MPR.@]
1484 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1485 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1487 FIXME( "(%p, %p, %p): stub\n",
1488 lpNetResource
, lpBuffer
, lpBufferSize
);
1490 SetLastError(WN_NO_NETWORK
);
1491 return WN_NO_NETWORK
;
1497 * Connection Functions
1500 /*********************************************************************
1501 * WNetAddConnectionA [MPR.@]
1503 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1504 LPCSTR lpLocalName
)
1506 NETRESOURCEA resourcesA
;
1508 memset(&resourcesA
, 0, sizeof(resourcesA
));
1509 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
1510 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
1511 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1514 /*********************************************************************
1515 * WNetAddConnectionW [MPR.@]
1517 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1518 LPCWSTR lpLocalName
)
1520 NETRESOURCEW resourcesW
;
1522 memset(&resourcesW
, 0, sizeof(resourcesW
));
1523 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
1524 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
1525 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1528 /*********************************************************************
1529 * WNetAddConnection2A [MPR.@]
1531 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1532 LPCSTR lpPassword
, LPCSTR lpUserID
,
1535 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1539 /*********************************************************************
1540 * WNetAddConnection2W [MPR.@]
1542 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1543 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1546 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1550 /*********************************************************************
1551 * WNetAddConnection3A [MPR.@]
1553 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1554 LPCSTR lpPassword
, LPCSTR lpUserID
,
1557 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1558 dwFlags
, NULL
, 0, NULL
);
1561 /*********************************************************************
1562 * WNetAddConnection3W [MPR.@]
1564 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1565 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1568 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1569 dwFlags
, NULL
, 0, NULL
);
1572 struct use_connection_context
1575 NETRESOURCEW
*resource
;
1576 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
1583 DWORD (*pre_set_accessname
)(struct use_connection_context
*);
1584 void (*set_accessname
)(struct use_connection_context
*);
1587 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
)
1589 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1593 if (ctxt
->resource
->lpLocalName
)
1594 len
= strlenW(ctxt
->resource
->lpLocalName
);
1596 len
= strlenW(ctxt
->resource
->lpRemoteName
);
1598 if (++len
> *ctxt
->buffer_size
)
1600 *ctxt
->buffer_size
= len
;
1601 return ERROR_MORE_DATA
;
1605 ctxt
->accessname
= NULL
;
1607 return ERROR_SUCCESS
;
1610 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
)
1612 WCHAR
*accessname
= ctxt
->accessname
;
1613 if (ctxt
->resource
->lpLocalName
)
1614 strcpyW(accessname
, ctxt
->resource
->lpLocalName
);
1616 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1618 strcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
1621 static WCHAR
* select_provider(struct use_connection_context
*ctxt
)
1623 DWORD ret
, prov_size
= 0x1000, len
;
1624 LPNETRESOURCEW provider
;
1627 provider
= HeapAlloc(GetProcessHeap(), 0, prov_size
);
1633 ret
= WNetGetResourceInformationW(ctxt
->resource
, provider
, &prov_size
, &system
);
1634 if (ret
== ERROR_MORE_DATA
)
1636 HeapFree(GetProcessHeap(), 0, provider
);
1637 provider
= HeapAlloc(GetProcessHeap(), 0, prov_size
);
1643 ret
= WNetGetResourceInformationW(ctxt
->resource
, provider
, &prov_size
, &system
);
1646 if (ret
!= NO_ERROR
)
1648 HeapFree(GetProcessHeap(), 0, provider
);
1652 len
= WideCharToMultiByte(CP_ACP
, 0, provider
->lpProvider
, -1, NULL
, 0, NULL
, NULL
);
1653 ctxt
->resource
->lpProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1654 if (ctxt
->resource
->lpProvider
)
1655 memcpy(ctxt
->resource
->lpProvider
, provider
->lpProvider
, len
* sizeof(WCHAR
));
1657 HeapFree(GetProcessHeap(), 0, provider
);
1659 return ctxt
->resource
->lpProvider
;
1662 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
1664 WNetProvider
*provider
;
1665 DWORD index
, ret
, caps
;
1666 BOOLEAN redirect
= FALSE
, prov
= FALSE
;
1667 WCHAR letter
[3] = {'z', ':', 0};
1669 if (!providerTable
|| providerTable
->numProviders
== 0)
1670 return WN_NO_NETWORK
;
1672 if (!ctxt
->resource
)
1673 return ERROR_INVALID_PARAMETER
;
1675 if (!ctxt
->resource
->lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
1677 if (ctxt
->resource
->dwType
!= RESOURCETYPE_DISK
&& ctxt
->resource
->dwType
!= RESOURCETYPE_PRINT
)
1679 return ERROR_BAD_DEV_TYPE
;
1682 if (ctxt
->resource
->dwType
== RESOURCETYPE_PRINT
)
1684 FIXME("Locale device selection is not implemented for printers.\n");
1685 return WN_NO_NETWORK
;
1689 ctxt
->resource
->lpLocalName
= letter
;
1692 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
1694 ret
= ERROR_BAD_NET_NAME
;
1698 if (!ctxt
->resource
->lpProvider
)
1700 ctxt
->resource
->lpProvider
= select_provider(ctxt
);
1701 if (!ctxt
->resource
->lpProvider
)
1703 ret
= ERROR_NO_NET_OR_BAD_PATH
;
1710 index
= _findProviderIndexW(ctxt
->resource
->lpProvider
);
1711 if (index
== BAD_PROVIDER_INDEX
)
1713 ret
= ERROR_BAD_PROVIDER
;
1717 provider
= &providerTable
->table
[index
];
1718 caps
= provider
->getCaps(WNNC_CONNECTION
);
1719 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
1721 ret
= ERROR_BAD_PROVIDER
;
1725 if ((ret
= ctxt
->pre_set_accessname(ctxt
)))
1730 ret
= WN_ACCESS_DENIED
;
1733 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
1734 ret
= provider
->addConnection3(ctxt
->hwndOwner
, ctxt
->resource
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
1735 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
1736 ret
= provider
->addConnection(ctxt
->resource
, ctxt
->password
, ctxt
->userid
);
1740 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& letter
[0] >= 'c');
1742 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
1743 ctxt
->set_accessname(ctxt
);
1748 HeapFree(GetProcessHeap(), 0, ctxt
->resource
->lpProvider
);
1749 ctxt
->resource
->lpProvider
= NULL
;
1753 ctxt
->resource
->lpLocalName
= NULL
;
1758 /*****************************************************************
1759 * WNetUseConnectionW [MPR.@]
1761 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
1762 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
1764 struct use_connection_context ctxt
;
1766 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1767 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
1768 accessname
, buffer_size
, result
);
1770 ctxt
.hwndOwner
= hwndOwner
;
1771 ctxt
.resource
= resource
;
1772 ctxt
.resourceA
= NULL
;
1773 ctxt
.password
= (WCHAR
*)password
;
1774 ctxt
.userid
= (WCHAR
*)userid
;
1776 ctxt
.accessname
= accessname
;
1777 ctxt
.buffer_size
= buffer_size
;
1778 ctxt
.result
= result
;
1779 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
1780 ctxt
.set_accessname
= use_connection_set_accessnameW
;
1782 return wnet_use_connection(&ctxt
);
1785 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
)
1787 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1791 if (ctxt
->resourceA
->lpLocalName
)
1792 len
= strlen(ctxt
->resourceA
->lpLocalName
);
1794 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
1796 if (++len
> *ctxt
->buffer_size
)
1798 *ctxt
->buffer_size
= len
;
1799 return ERROR_MORE_DATA
;
1803 ctxt
->accessname
= NULL
;
1805 return ERROR_SUCCESS
;
1808 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
)
1810 char *accessname
= ctxt
->accessname
;
1811 if (ctxt
->resourceA
->lpLocalName
)
1812 strcpy(accessname
, ctxt
->resourceA
->lpLocalName
);
1814 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1816 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
1819 static LPWSTR
strdupAtoW( LPCSTR str
)
1824 if (!str
) return NULL
;
1825 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
1826 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1827 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
1831 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
1833 resourceW
->dwScope
= resourceA
->dwScope
;
1834 resourceW
->dwType
= resourceA
->dwType
;
1835 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
1836 resourceW
->dwUsage
= resourceA
->dwUsage
;
1837 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
1838 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
1839 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
1840 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
1843 static void free_netresourceW( NETRESOURCEW
*resource
)
1845 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
1846 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
1847 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
1848 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
1851 /*****************************************************************
1852 * WNetUseConnectionA [MPR.@]
1854 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
1855 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
1856 DWORD
*buffer_size
, DWORD
*result
)
1858 struct use_connection_context ctxt
;
1859 NETRESOURCEW resourceW
;
1862 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
1863 accessname
, buffer_size
, result
);
1865 netresource_a_to_w(resource
, &resourceW
);
1867 ctxt
.hwndOwner
= hwndOwner
;
1868 ctxt
.resource
= &resourceW
;
1869 ctxt
.resourceA
= resource
;
1870 ctxt
.password
= strdupAtoW(password
);
1871 ctxt
.userid
= strdupAtoW(userid
);
1873 ctxt
.accessname
= accessname
;
1874 ctxt
.buffer_size
= buffer_size
;
1875 ctxt
.result
= result
;
1876 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
1877 ctxt
.set_accessname
= use_connection_set_accessnameA
;
1879 ret
= wnet_use_connection(&ctxt
);
1881 free_netresourceW(&resourceW
);
1882 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
1883 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
1888 /*********************************************************************
1889 * WNetCancelConnectionA [MPR.@]
1891 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
1893 return WNetCancelConnection2A(lpName
, 0, fForce
);
1896 /*********************************************************************
1897 * WNetCancelConnectionW [MPR.@]
1899 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
1901 return WNetCancelConnection2W(lpName
, 0, fForce
);
1904 /*********************************************************************
1905 * WNetCancelConnection2A [MPR.@]
1907 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1910 WCHAR
* name
= strdupAtoW(lpName
);
1912 return ERROR_NOT_CONNECTED
;
1914 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
1915 HeapFree(GetProcessHeap(), 0, name
);
1920 /*********************************************************************
1921 * WNetCancelConnection2W [MPR.@]
1923 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1925 DWORD ret
= WN_NO_NETWORK
;
1928 if (providerTable
!= NULL
)
1930 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1932 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
1933 WNNC_CON_GETCONNECTIONS
)
1935 if (providerTable
->table
[index
].cancelConnection
)
1936 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
1938 ret
= WN_NO_NETWORK
;
1939 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
1947 /*****************************************************************
1948 * WNetRestoreConnectionA [MPR.@]
1950 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
1952 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
1954 SetLastError(WN_NO_NETWORK
);
1955 return WN_NO_NETWORK
;
1958 /*****************************************************************
1959 * WNetRestoreConnectionW [MPR.@]
1961 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
1963 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
1965 SetLastError(WN_NO_NETWORK
);
1966 return WN_NO_NETWORK
;
1969 /**************************************************************************
1970 * WNetGetConnectionA [MPR.@]
1973 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1974 * - WN_NOT_CONNECTED drive is a local drive
1975 * - WN_MORE_DATA buffer isn't big enough
1976 * - WN_SUCCESS success (net path in buffer)
1978 * FIXME: need to test return values under different errors
1980 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
1981 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
1986 ret
= WN_BAD_POINTER
;
1987 else if (!lpBufferSize
)
1988 ret
= WN_BAD_POINTER
;
1989 else if (!lpRemoteName
&& *lpBufferSize
)
1990 ret
= WN_BAD_POINTER
;
1993 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
1997 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2001 WCHAR wideRemoteStatic
[MAX_PATH
];
2002 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
2004 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
2006 /* try once without memory allocation */
2007 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
2009 if (ret
== WN_SUCCESS
)
2011 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2012 -1, NULL
, 0, NULL
, NULL
);
2014 if (len
<= *lpBufferSize
)
2016 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
2017 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2022 *lpBufferSize
= len
;
2026 else if (ret
== WN_MORE_DATA
)
2028 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2029 wideRemoteSize
* sizeof(WCHAR
));
2033 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2035 if (ret
== WN_SUCCESS
)
2037 if (len
<= *lpBufferSize
)
2039 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2040 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2045 *lpBufferSize
= len
;
2049 HeapFree(GetProcessHeap(), 0, wideRemote
);
2052 ret
= WN_OUT_OF_MEMORY
;
2054 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2057 ret
= WN_OUT_OF_MEMORY
;
2060 ret
= WN_BAD_LOCALNAME
;
2064 TRACE("Returning %d\n", ret
);
2068 /* find the network connection for a given drive; helper for WNetGetConnection */
2069 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2073 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2075 DWORD ret
= WN_NOT_CONNECTED
;
2076 DWORD bytes_returned
;
2078 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2079 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2080 0, 0 )) == INVALID_HANDLE_VALUE
)
2082 ERR( "failed to open mount manager err %u\n", GetLastError() );
2085 memset( data
, 0, sizeof(*data
) );
2086 data
->letter
= letter
;
2087 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2088 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2090 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2093 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2096 mount_point
[0] = '\\';
2097 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2099 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2107 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2115 DWORD ret
= WN_NO_NETWORK
;
2117 WCHAR local
[3] = {letter
, ':', 0};
2119 if (providerTable
!= NULL
)
2121 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2123 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2124 WNNC_CON_GETCONNECTIONS
)
2126 if (providerTable
->table
[index
].getConnection
)
2127 ret
= providerTable
->table
[index
].getConnection(
2128 local
, remote
, size
);
2130 ret
= WN_NO_NETWORK
;
2131 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2142 /**************************************************************************
2143 * WNetGetConnectionW [MPR.@]
2145 * FIXME: need to test return values under different errors
2147 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2148 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2152 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2156 ret
= WN_BAD_POINTER
;
2157 else if (!lpBufferSize
)
2158 ret
= WN_BAD_POINTER
;
2159 else if (!lpRemoteName
&& *lpBufferSize
)
2160 ret
= WN_BAD_POINTER
;
2161 else if (!lpLocalName
[0])
2162 ret
= WN_BAD_LOCALNAME
;
2165 if (lpLocalName
[1] == ':')
2167 switch(GetDriveTypeW(lpLocalName
))
2170 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2172 case DRIVE_REMOVABLE
:
2175 TRACE("file is local\n");
2176 ret
= WN_NOT_CONNECTED
;
2179 ret
= WN_BAD_LOCALNAME
;
2183 ret
= WN_BAD_LOCALNAME
;
2187 TRACE("Returning %d\n", ret
);
2191 /**************************************************************************
2192 * WNetSetConnectionA [MPR.@]
2194 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2197 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2199 SetLastError(WN_NO_NETWORK
);
2200 return WN_NO_NETWORK
;
2203 /**************************************************************************
2204 * WNetSetConnectionW [MPR.@]
2206 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2209 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2211 SetLastError(WN_NO_NETWORK
);
2212 return WN_NO_NETWORK
;
2215 /*****************************************************************
2216 * WNetGetUniversalNameA [MPR.@]
2218 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2219 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2223 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2224 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2226 switch (dwInfoLevel
)
2228 case UNIVERSAL_NAME_INFO_LEVEL
:
2230 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2232 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2234 err
= ERROR_NOT_CONNECTED
;
2238 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2239 if (*lpBufferSize
< size
)
2244 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2245 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2249 case REMOTE_NAME_INFO_LEVEL
:
2250 err
= WN_NOT_CONNECTED
;
2262 /*****************************************************************
2263 * WNetGetUniversalNameW [MPR.@]
2265 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2266 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2270 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2271 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2273 switch (dwInfoLevel
)
2275 case UNIVERSAL_NAME_INFO_LEVEL
:
2277 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2279 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2281 err
= ERROR_NOT_CONNECTED
;
2285 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2286 if (*lpBufferSize
< size
)
2291 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2292 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2296 case REMOTE_NAME_INFO_LEVEL
:
2297 err
= WN_NO_NETWORK
;
2305 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2315 /**************************************************************************
2316 * WNetGetUserA [MPR.@]
2318 * FIXME: we should not return ourselves, but the owner of the drive lpName
2320 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2322 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2323 return GetLastError();
2326 /*****************************************************************
2327 * WNetGetUserW [MPR.@]
2329 * FIXME: we should not return ourselves, but the owner of the drive lpName
2331 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2333 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2334 return GetLastError();
2337 /*********************************************************************
2338 * WNetConnectionDialog [MPR.@]
2340 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2342 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2344 SetLastError(WN_NO_NETWORK
);
2345 return WN_NO_NETWORK
;
2348 /*********************************************************************
2349 * WNetConnectionDialog1A [MPR.@]
2351 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2353 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2355 SetLastError(WN_NO_NETWORK
);
2356 return WN_NO_NETWORK
;
2359 /*********************************************************************
2360 * WNetConnectionDialog1W [MPR.@]
2362 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2364 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2366 SetLastError(WN_NO_NETWORK
);
2367 return WN_NO_NETWORK
;
2370 /*********************************************************************
2371 * WNetDisconnectDialog [MPR.@]
2373 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2375 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2377 SetLastError(WN_NO_NETWORK
);
2378 return WN_NO_NETWORK
;
2381 /*********************************************************************
2382 * WNetDisconnectDialog1A [MPR.@]
2384 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2386 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2388 SetLastError(WN_NO_NETWORK
);
2389 return WN_NO_NETWORK
;
2392 /*********************************************************************
2393 * WNetDisconnectDialog1W [MPR.@]
2395 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2397 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2399 SetLastError(WN_NO_NETWORK
);
2400 return WN_NO_NETWORK
;
2403 /*********************************************************************
2404 * WNetGetLastErrorA [MPR.@]
2406 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2407 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2408 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2410 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2411 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2413 SetLastError(WN_NO_NETWORK
);
2414 return WN_NO_NETWORK
;
2417 /*********************************************************************
2418 * WNetGetLastErrorW [MPR.@]
2420 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2421 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2422 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2424 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2425 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2427 SetLastError(WN_NO_NETWORK
);
2428 return WN_NO_NETWORK
;
2431 /*********************************************************************
2432 * WNetGetNetworkInformationA [MPR.@]
2434 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2435 LPNETINFOSTRUCT lpNetInfoStruct
)
2439 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2442 ret
= WN_BAD_POINTER
;
2447 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2450 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2454 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2456 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2457 HeapFree(GetProcessHeap(), 0, wideProvider
);
2460 ret
= WN_OUT_OF_MEMORY
;
2463 ret
= GetLastError();
2467 TRACE("Returning %d\n", ret
);
2471 /*********************************************************************
2472 * WNetGetNetworkInformationW [MPR.@]
2474 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2475 LPNETINFOSTRUCT lpNetInfoStruct
)
2479 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2482 ret
= WN_BAD_POINTER
;
2483 else if (!lpNetInfoStruct
)
2484 ret
= WN_BAD_POINTER
;
2485 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2489 if (providerTable
&& providerTable
->numProviders
)
2491 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2493 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2495 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2496 lpNetInfoStruct
->dwProviderVersion
=
2497 providerTable
->table
[providerIndex
].dwSpecVersion
;
2498 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2499 lpNetInfoStruct
->dwCharacteristics
= 0;
2500 lpNetInfoStruct
->dwHandle
= 0;
2501 lpNetInfoStruct
->wNetType
=
2502 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2503 lpNetInfoStruct
->dwPrinters
= -1;
2504 lpNetInfoStruct
->dwDrives
= -1;
2508 ret
= WN_BAD_PROVIDER
;
2511 ret
= WN_NO_NETWORK
;
2515 TRACE("Returning %d\n", ret
);
2519 /*****************************************************************
2520 * WNetGetProviderNameA [MPR.@]
2522 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2523 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2527 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2531 ret
= WN_BAD_POINTER
;
2532 else if (!lpBufferSize
)
2533 ret
= WN_BAD_POINTER
;
2540 ret
= WN_NO_NETWORK
;
2541 for (i
= 0; i
< providerTable
->numProviders
&&
2542 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2545 if (i
< providerTable
->numProviders
)
2547 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2548 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2550 if (*lpBufferSize
< sizeNeeded
)
2552 *lpBufferSize
= sizeNeeded
;
2557 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2558 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2560 /* FIXME: is *lpBufferSize set to the number of characters
2566 ret
= WN_NO_NETWORK
;
2570 TRACE("Returning %d\n", ret
);
2574 /*****************************************************************
2575 * WNetGetProviderNameW [MPR.@]
2577 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2578 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2582 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2586 ret
= WN_BAD_POINTER
;
2587 else if (!lpBufferSize
)
2588 ret
= WN_BAD_POINTER
;
2595 ret
= WN_NO_NETWORK
;
2596 for (i
= 0; i
< providerTable
->numProviders
&&
2597 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2600 if (i
< providerTable
->numProviders
)
2602 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2604 if (*lpBufferSize
< sizeNeeded
)
2606 *lpBufferSize
= sizeNeeded
;
2611 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2613 /* FIXME: is *lpBufferSize set to the number of characters
2619 ret
= WN_NO_NETWORK
;
2623 TRACE("Returning %d\n", ret
);