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
;
52 PF_NPGetConnection getConnection
;
54 } WNetProvider
, *PWNetProvider
;
56 typedef struct _WNetProviderTable
61 WNetProvider table
[1];
62 } WNetProviderTable
, *PWNetProviderTable
;
64 #define WNET_ENUMERATOR_TYPE_NULL 0
65 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
66 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
67 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
69 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
70 * the enumeration; it represents one of the following types:
71 * - a 'null' enumeration, one that contains no members
72 * - a global enumeration, one that's executed across all providers
73 * - a provider-specific enumeration, one that's only executed by a single
75 * - a context enumeration. I know this contradicts what I just said about
76 * there being no correspondence between the scope and the type, but it's
77 * necessary for the special case that a "Entire Network" entry needs to
78 * be enumerated in an enumeration of the context scope. Thus an enumeration
79 * of the context scope results in a context type enumerator, which morphs
80 * into a global enumeration (so the enumeration continues across all
83 typedef struct _WNetEnumerator
93 } WNetEnumerator
, *PWNetEnumerator
;
95 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
97 /* Returns an index (into the global WNetProviderTable) of the provider with
98 * the given name, or BAD_PROVIDER_INDEX if not found.
100 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
102 static PWNetProviderTable providerTable
;
105 * Global provider table functions
108 static void _tryLoadProvider(PCWSTR provider
)
110 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
111 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
112 'S','e','r','v','i','c','e','s','\\',0 };
113 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
114 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
115 WCHAR serviceName
[MAX_PATH
];
118 TRACE("%s\n", debugstr_w(provider
));
119 snprintfW(serviceName
, sizeof(serviceName
) / sizeof(WCHAR
), serviceFmt
,
120 servicePrefix
, provider
);
121 serviceName
[sizeof(serviceName
) / sizeof(WCHAR
) - 1] = '\0';
122 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
125 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
127 WCHAR providerPath
[MAX_PATH
];
128 DWORD type
, size
= sizeof(providerPath
);
130 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
131 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
133 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
136 if (type
== REG_EXPAND_SZ
)
138 WCHAR path
[MAX_PATH
];
139 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
143 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
146 name
= HeapAlloc(GetProcessHeap(), 0, size
);
147 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
148 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
150 HeapFree(GetProcessHeap(), 0, name
);
156 HMODULE hLib
= LoadLibraryW(providerPath
);
160 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
162 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
164 TRACE("loaded lib %p\n", hLib
);
167 PWNetProvider provider
=
168 &providerTable
->table
[providerTable
->numProviders
];
170 provider
->hLib
= hLib
;
171 provider
->name
= name
;
172 TRACE("name is %s\n", debugstr_w(name
));
173 provider
->getCaps
= getCaps
;
174 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
175 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
176 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
177 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
178 if (provider
->dwEnumScopes
)
180 TRACE("supports enumeration\n");
181 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
182 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
183 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
184 TRACE("NPEnumResource %p\n", provider
->enumResource
);
185 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
186 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
187 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
188 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
189 if (!provider
->openEnum
||
190 !provider
->enumResource
||
191 !provider
->closeEnum
)
193 provider
->openEnum
= NULL
;
194 provider
->enumResource
= NULL
;
195 provider
->closeEnum
= NULL
;
196 provider
->dwEnumScopes
= 0;
197 WARN("Couldn't load enumeration functions\n");
200 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
201 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
203 provider
->getConnection
= MPR_GETPROC(NPGetConnection
);
205 TRACE("NPAddConnection %p\n", provider
->addConnection
);
206 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
207 providerTable
->numProviders
++;
211 WARN("Provider %s didn't export NPGetCaps\n",
212 debugstr_w(provider
));
213 HeapFree(GetProcessHeap(), 0, name
);
221 WARN("Couldn't load library %s for provider %s\n",
222 debugstr_w(providerPath
), debugstr_w(provider
));
223 HeapFree(GetProcessHeap(), 0, name
);
228 WARN("Couldn't get provider name for provider %s\n",
229 debugstr_w(provider
));
233 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
237 WARN("Couldn't open service key for provider %s\n",
238 debugstr_w(provider
));
241 void wnetInit(HINSTANCE hInstDll
)
243 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
244 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
245 'C','o','n','t','r','o','l','\\',
246 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
247 'O','r','d','e','r',0 };
248 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
249 'O','r','d','e','r',0 };
252 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
257 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
260 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
266 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
267 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
272 TRACE("provider order is %s\n", debugstr_w(providers
));
273 /* first count commas as a heuristic for how many to
274 * allocate space for */
275 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
277 ptr
= strchrW(ptr
, ',');
284 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
285 sizeof(WNetProviderTable
)
286 + (numToAllocate
- 1) * sizeof(WNetProvider
));
290 int entireNetworkLen
;
291 LPCWSTR stringresource
;
293 entireNetworkLen
= LoadStringW(hInstDll
,
294 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
295 providerTable
->entireNetwork
= HeapAlloc(
296 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
298 if (providerTable
->entireNetwork
)
300 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
301 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
303 providerTable
->numAllocated
= numToAllocate
;
304 for (ptr
= providers
; ptr
; )
307 ptr
= strchrW(ptr
, ',');
310 _tryLoadProvider(ptrPrev
);
314 HeapFree(GetProcessHeap(), 0, providers
);
327 for (i
= 0; i
< providerTable
->numProviders
; i
++)
329 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
330 FreeModule(providerTable
->table
[i
].hLib
);
332 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
333 HeapFree(GetProcessHeap(), 0, providerTable
);
334 providerTable
= NULL
;
338 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
340 DWORD ret
= BAD_PROVIDER_INDEX
;
342 if (providerTable
&& providerTable
->numProviders
)
346 for (i
= 0; i
< providerTable
->numProviders
&&
347 ret
== BAD_PROVIDER_INDEX
; i
++)
348 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
358 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
364 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
370 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
371 if (lpNet
->lpRemoteName
)
373 len
= strlenW(lpNet
->lpRemoteName
) + 1;
374 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
375 if (ret
->lpRemoteName
)
376 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
385 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
389 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
390 HeapFree(GetProcessHeap(), 0, lpNet
);
394 static PWNetEnumerator
_createNullEnumerator(void)
396 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
397 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
400 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
404 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
405 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
407 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
408 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
412 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
413 ret
->dwScope
= dwScope
;
414 ret
->dwType
= dwType
;
415 ret
->dwUsage
= dwUsage
;
416 ret
->lpNet
= _copyNetResourceForEnumW(lpNet
);
421 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
422 DWORD dwUsage
, DWORD index
, HANDLE handle
)
426 if (!providerTable
|| index
>= providerTable
->numProviders
)
430 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
433 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
434 ret
->providerIndex
= index
;
435 ret
->dwScope
= dwScope
;
436 ret
->dwType
= dwType
;
437 ret
->dwUsage
= dwUsage
;
438 ret
->handle
= handle
;
444 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
447 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
448 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
452 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
453 ret
->dwScope
= dwScope
;
454 ret
->dwType
= dwType
;
455 ret
->dwUsage
= dwUsage
;
460 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
461 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
462 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
463 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
464 * if not all members of the array could be thunked, and something else on
467 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
468 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
470 DWORD i
, numToThunk
, totalBytes
, ret
;
474 return WN_BAD_POINTER
;
476 return WN_BAD_POINTER
;
480 return WN_BAD_POINTER
;
482 return WN_BAD_POINTER
;
484 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
486 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
488 totalBytes
+= sizeof(NETRESOURCEA
);
489 if (lpNet
->lpLocalName
)
490 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
491 -1, NULL
, 0, NULL
, NULL
);
492 if (lpNet
->lpRemoteName
)
493 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
494 -1, NULL
, 0, NULL
, NULL
);
495 if (lpNet
->lpComment
)
496 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
497 -1, NULL
, 0, NULL
, NULL
);
498 if (lpNet
->lpProvider
)
499 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
500 -1, NULL
, 0, NULL
, NULL
);
501 if (totalBytes
< *lpBufferSize
)
504 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
505 for (i
= 0; i
< numToThunk
; i
++)
507 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
508 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
510 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
511 /* lie about string lengths, we already verified how many
512 * we have space for above
514 if (lpNetIn
->lpLocalName
)
516 lpNetOut
->lpLocalName
= strNext
;
517 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
518 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
520 if (lpNetIn
->lpRemoteName
)
522 lpNetOut
->lpRemoteName
= strNext
;
523 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
524 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
526 if (lpNetIn
->lpComment
)
528 lpNetOut
->lpComment
= strNext
;
529 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
530 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
532 if (lpNetIn
->lpProvider
)
534 lpNetOut
->lpProvider
= strNext
;
535 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
536 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
539 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
540 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
545 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
546 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
547 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
548 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
549 * if not all members of the array could be thunked, and something else on
552 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
553 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
555 DWORD i
, numToThunk
, totalBytes
, ret
;
559 return WN_BAD_POINTER
;
561 return WN_BAD_POINTER
;
565 return WN_BAD_POINTER
;
567 return WN_BAD_POINTER
;
569 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
571 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
573 totalBytes
+= sizeof(NETRESOURCEW
);
574 if (lpNet
->lpLocalName
)
575 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
576 -1, NULL
, 0) * sizeof(WCHAR
);
577 if (lpNet
->lpRemoteName
)
578 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
579 -1, NULL
, 0) * sizeof(WCHAR
);
580 if (lpNet
->lpComment
)
581 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
582 -1, NULL
, 0) * sizeof(WCHAR
);
583 if (lpNet
->lpProvider
)
584 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
585 -1, NULL
, 0) * sizeof(WCHAR
);
586 if (totalBytes
< *lpBufferSize
)
589 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
590 for (i
= 0; i
< numToThunk
; i
++)
592 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
593 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
595 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
596 /* lie about string lengths, we already verified how many
597 * we have space for above
599 if (lpNetIn
->lpLocalName
)
601 lpNetOut
->lpLocalName
= strNext
;
602 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
603 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
605 if (lpNetIn
->lpRemoteName
)
607 lpNetOut
->lpRemoteName
= strNext
;
608 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
609 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
611 if (lpNetIn
->lpComment
)
613 lpNetOut
->lpComment
= strNext
;
614 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
615 -1, lpNetOut
->lpComment
, *lpBufferSize
);
617 if (lpNetIn
->lpProvider
)
619 lpNetOut
->lpProvider
= strNext
;
620 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
621 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
624 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
625 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
630 /*********************************************************************
631 * WNetOpenEnumA [MPR.@]
633 * See comments for WNetOpenEnumW.
635 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
636 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
640 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
641 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
644 ret
= WN_BAD_POINTER
;
645 else if (!providerTable
|| providerTable
->numProviders
== 0)
654 LPNETRESOURCEW lpNetWide
= NULL
;
656 DWORD size
= sizeof(buf
), count
= 1;
657 BOOL allocated
= FALSE
;
659 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
660 if (ret
== WN_MORE_DATA
)
662 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
666 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
671 ret
= WN_OUT_OF_MEMORY
;
673 else if (ret
== WN_SUCCESS
)
674 lpNetWide
= (LPNETRESOURCEW
)buf
;
675 if (ret
== WN_SUCCESS
)
676 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
679 HeapFree(GetProcessHeap(), 0, lpNetWide
);
682 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
686 TRACE("Returning %d\n", ret
);
690 /*********************************************************************
691 * WNetOpenEnumW [MPR.@]
693 * Network enumeration has way too many parameters, so I'm not positive I got
694 * them right. What I've got so far:
696 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
697 * all the network providers should be enumerated.
699 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
700 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
701 * lpProvider is set, all the network providers should be enumerated.
702 * (This means the enumeration is a list of network providers, not that the
703 * enumeration is passed on to the providers.)
705 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
706 * resource matches the "Entire Network" resource (no remote name, no
707 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
708 * enumeration is done on every network provider.
710 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
711 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
712 * only to the given network provider.
714 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
715 * no lpProvider is set, enumeration will be tried on every network provider,
716 * in the order in which they're loaded.
718 * - The LPNETRESOURCE should be disregarded for scopes besides
719 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
720 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
722 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
723 * resource in the enumerated list, as well as any machines in your
724 * workgroup. The machines in your workgroup come from doing a
725 * RESOURCE_CONTEXT enumeration of every Network Provider.
727 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
728 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
732 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
733 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
736 ret
= WN_BAD_POINTER
;
737 else if (!providerTable
|| providerTable
->numProviders
== 0)
746 case RESOURCE_GLOBALNET
:
749 if (lpNet
->lpProvider
)
751 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
753 if (index
!= BAD_PROVIDER_INDEX
)
755 if (providerTable
->table
[index
].openEnum
&&
756 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
759 PWSTR RemoteName
= lpNet
->lpRemoteName
;
761 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
762 RemoteName
&& !strcmpW(RemoteName
, lpNet
->lpProvider
))
763 lpNet
->lpRemoteName
= NULL
;
765 ret
= providerTable
->table
[index
].openEnum(
766 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
767 if (ret
== WN_SUCCESS
)
769 *lphEnum
= _createProviderEnumerator(
770 dwScope
, dwType
, dwUsage
, index
, handle
);
771 ret
= *lphEnum
? WN_SUCCESS
:
775 lpNet
->lpRemoteName
= RemoteName
;
778 ret
= WN_NOT_SUPPORTED
;
781 ret
= WN_BAD_PROVIDER
;
783 else if (lpNet
->lpRemoteName
)
785 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
786 dwType
, dwUsage
, lpNet
);
787 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
791 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
792 providerTable
->entireNetwork
))
794 /* comment matches the "Entire Network", enumerate
795 * global scope of every provider
797 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
798 dwType
, dwUsage
, lpNet
);
802 /* this is the same as not having passed lpNet */
803 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
804 dwType
, dwUsage
, NULL
);
806 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
811 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
813 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
816 case RESOURCE_CONTEXT
:
817 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
818 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
820 case RESOURCE_REMEMBERED
:
821 case RESOURCE_CONNECTED
:
822 *lphEnum
= _createNullEnumerator();
823 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
826 WARN("unknown scope 0x%08x\n", dwScope
);
832 TRACE("Returning %d\n", ret
);
836 /*********************************************************************
837 * WNetEnumResourceA [MPR.@]
839 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
840 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
844 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
847 ret
= WN_BAD_POINTER
;
849 ret
= WN_BAD_POINTER
;
851 ret
= WN_BAD_POINTER
;
852 else if (!lpBufferSize
)
853 ret
= WN_BAD_POINTER
;
854 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
856 *lpBufferSize
= sizeof(NETRESOURCEA
);
861 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
862 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
866 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
868 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
870 /* FIXME: this isn't necessarily going to work in the case of
871 * WN_MORE_DATA, because our enumerator may have moved on to
872 * the next provider. MSDN states that a large (16KB) buffer
873 * size is the appropriate usage of this function, so
874 * hopefully it won't be an issue.
876 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
877 lpBuffer
, lpBufferSize
);
878 *lpcCount
= localCount
;
880 HeapFree(GetProcessHeap(), 0, localBuffer
);
883 ret
= WN_OUT_OF_MEMORY
;
887 TRACE("Returning %d\n", ret
);
891 static DWORD
_countProviderBytesW(PWNetProvider provider
)
897 ret
= sizeof(NETRESOURCEW
);
898 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
905 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
906 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
911 return WN_BAD_POINTER
;
912 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
915 return WN_BAD_POINTER
;
917 return WN_BAD_POINTER
;
919 return WN_BAD_POINTER
;
920 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
923 if (!providerTable
|| enumerator
->providerIndex
>=
924 providerTable
->numProviders
)
925 ret
= WN_NO_MORE_ENTRIES
;
928 DWORD bytes
= 0, count
= 0, countLimit
, i
;
929 LPNETRESOURCEW resource
;
932 countLimit
= *lpcCount
== -1 ?
933 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
934 while (count
< countLimit
&& bytes
< *lpBufferSize
)
936 DWORD bytesNext
= _countProviderBytesW(
937 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
939 if (bytes
+ bytesNext
< *lpBufferSize
)
945 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
946 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
948 resource
->dwScope
= RESOURCE_GLOBALNET
;
949 resource
->dwType
= RESOURCETYPE_ANY
;
950 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
951 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
952 RESOURCEUSAGE_RESERVED
;
953 resource
->lpLocalName
= NULL
;
954 resource
->lpRemoteName
= strNext
;
955 strcpyW(resource
->lpRemoteName
,
956 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
957 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
958 resource
->lpComment
= NULL
;
959 resource
->lpProvider
= strNext
;
960 strcpyW(resource
->lpProvider
,
961 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
962 strNext
+= strlenW(resource
->lpProvider
) + 1;
964 enumerator
->providerIndex
+= count
;
966 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
968 TRACE("Returning %d\n", ret
);
972 /* Advances the enumerator (assumed to be a global enumerator) to the next
973 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
974 * not open a handle with the next provider.
975 * If the existing handle is NULL, may leave the enumerator unchanged, since
976 * the current provider may support the desired scope.
977 * If the existing handle is not NULL, closes it before moving on.
978 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
979 * provider, and another error on failure.
981 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
984 return WN_BAD_POINTER
;
985 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
987 if (!providerTable
|| enumerator
->providerIndex
>=
988 providerTable
->numProviders
)
989 return WN_NO_MORE_ENTRIES
;
991 if (enumerator
->providerDone
)
994 enumerator
->providerDone
= FALSE
;
995 if (enumerator
->handle
)
997 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
999 enumerator
->handle
= NULL
;
1000 enumerator
->providerIndex
++;
1002 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1003 dwEnum
= WNNC_ENUM_LOCAL
;
1004 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1005 dwEnum
= WNNC_ENUM_GLOBAL
;
1006 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1007 dwEnum
= WNNC_ENUM_CONTEXT
;
1008 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1009 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1010 & dwEnum
); enumerator
->providerIndex
++)
1013 return enumerator
->providerIndex
< providerTable
->numProviders
?
1014 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1017 /* "Passes through" call to the next provider that supports the enumeration
1019 * FIXME: if one call to a provider's enumerator succeeds while there's still
1020 * space in lpBuffer, I don't call to the next provider. The caller may not
1021 * expect that it should call EnumResourceW again with a return value of
1022 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1023 * may have to be moved around a bit, ick.
1025 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1026 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1031 return WN_BAD_POINTER
;
1032 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1033 return WN_BAD_VALUE
;
1035 return WN_BAD_POINTER
;
1037 return WN_BAD_POINTER
;
1039 return WN_BAD_POINTER
;
1040 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1041 return WN_MORE_DATA
;
1043 ret
= _globalEnumeratorAdvance(enumerator
);
1044 if (ret
== WN_SUCCESS
)
1046 ret
= providerTable
->table
[enumerator
->providerIndex
].
1047 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1048 enumerator
->dwUsage
, enumerator
->lpNet
,
1049 &enumerator
->handle
);
1050 if (ret
== WN_SUCCESS
)
1052 ret
= providerTable
->table
[enumerator
->providerIndex
].
1053 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1055 if (ret
!= WN_MORE_DATA
)
1056 enumerator
->providerDone
= TRUE
;
1059 TRACE("Returning %d\n", ret
);
1063 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1064 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1069 return WN_BAD_POINTER
;
1070 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1071 return WN_BAD_VALUE
;
1073 return WN_BAD_POINTER
;
1075 return WN_BAD_POINTER
;
1077 return WN_BAD_POINTER
;
1078 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1079 return WN_MORE_DATA
;
1081 return WN_NO_NETWORK
;
1083 switch (enumerator
->dwScope
)
1085 case RESOURCE_GLOBALNET
:
1086 if (enumerator
->lpNet
)
1087 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1088 lpBuffer
, lpBufferSize
);
1090 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1093 case RESOURCE_CONTEXT
:
1094 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1098 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1099 ret
= WN_NO_MORE_ENTRIES
;
1101 TRACE("Returning %d\n", ret
);
1105 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1106 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1109 return WN_BAD_POINTER
;
1110 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1111 return WN_BAD_VALUE
;
1112 if (!enumerator
->handle
)
1113 return WN_BAD_VALUE
;
1115 return WN_BAD_POINTER
;
1117 return WN_BAD_POINTER
;
1119 return WN_BAD_POINTER
;
1121 return WN_NO_NETWORK
;
1122 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1123 return WN_NO_MORE_ENTRIES
;
1124 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1125 return WN_BAD_VALUE
;
1126 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1127 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1130 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1131 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1134 size_t cchEntireNetworkLen
, bytesNeeded
;
1137 return WN_BAD_POINTER
;
1138 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1139 return WN_BAD_VALUE
;
1141 return WN_BAD_POINTER
;
1143 return WN_BAD_POINTER
;
1145 return WN_BAD_POINTER
;
1147 return WN_NO_NETWORK
;
1149 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1150 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1151 if (*lpBufferSize
< bytesNeeded
)
1153 *lpBufferSize
= bytesNeeded
;
1158 LPNETRESOURCEW lpNet
= lpBuffer
;
1160 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1161 lpNet
->dwType
= enumerator
->dwType
;
1162 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1163 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1164 lpNet
->lpLocalName
= NULL
;
1165 lpNet
->lpRemoteName
= NULL
;
1166 lpNet
->lpProvider
= NULL
;
1167 /* odd, but correct: put comment at end of buffer, so it won't get
1168 * overwritten by subsequent calls to a provider's enumResource
1170 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1171 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1172 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1175 if (ret
== WN_SUCCESS
)
1177 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1179 /* "Entire Network" entry enumerated--morph this into a global
1180 * enumerator. enumerator->lpNet continues to be NULL, since it has
1181 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1183 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1184 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1185 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1186 if (ret
== WN_SUCCESS
)
1188 /* reflect the fact that we already enumerated "Entire Network" */
1190 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1194 /* the provider enumeration failed, but we already succeeded in
1195 * enumerating "Entire Network"--leave type as global to allow a
1196 * retry, but indicate success with a count of one.
1200 *lpBufferSize
= bytesNeeded
;
1203 TRACE("Returning %d\n", ret
);
1207 /*********************************************************************
1208 * WNetEnumResourceW [MPR.@]
1210 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1211 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1215 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1218 ret
= WN_BAD_POINTER
;
1220 ret
= WN_BAD_POINTER
;
1222 ret
= WN_BAD_POINTER
;
1223 else if (!lpBufferSize
)
1224 ret
= WN_BAD_POINTER
;
1225 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1227 *lpBufferSize
= sizeof(NETRESOURCEW
);
1232 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1234 switch (enumerator
->enumType
)
1236 case WNET_ENUMERATOR_TYPE_NULL
:
1237 ret
= WN_NO_MORE_ENTRIES
;
1239 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1240 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1243 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1244 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1247 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1248 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1252 WARN("bogus enumerator type!\n");
1253 ret
= WN_NO_NETWORK
;
1258 TRACE("Returning %d\n", ret
);
1262 /*********************************************************************
1263 * WNetCloseEnum [MPR.@]
1265 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1269 TRACE( "(%p)\n", hEnum
);
1273 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1275 switch (enumerator
->enumType
)
1277 case WNET_ENUMERATOR_TYPE_NULL
:
1280 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1281 if (enumerator
->lpNet
)
1282 _freeEnumNetResource(enumerator
->lpNet
);
1283 if (enumerator
->handle
)
1284 providerTable
->table
[enumerator
->providerIndex
].
1285 closeEnum(enumerator
->handle
);
1288 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1289 if (enumerator
->handle
)
1290 providerTable
->table
[enumerator
->providerIndex
].
1291 closeEnum(enumerator
->handle
);
1295 WARN("bogus enumerator type!\n");
1296 ret
= WN_BAD_HANDLE
;
1298 HeapFree(GetProcessHeap(), 0, hEnum
);
1301 ret
= WN_BAD_HANDLE
;
1304 TRACE("Returning %d\n", ret
);
1308 /*********************************************************************
1309 * WNetGetResourceInformationA [MPR.@]
1311 * See WNetGetResourceInformationW
1313 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1314 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1319 TRACE( "(%p, %p, %p, %p)\n",
1320 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1322 if (!providerTable
|| providerTable
->numProviders
== 0)
1323 ret
= WN_NO_NETWORK
;
1324 else if (lpNetResource
)
1326 LPNETRESOURCEW lpNetResourceW
= NULL
;
1327 DWORD size
= 1024, count
= 1;
1330 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1331 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1332 if (ret
== WN_MORE_DATA
)
1334 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1335 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1337 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1338 &count
, lpNetResourceW
, &size
);
1340 ret
= WN_OUT_OF_MEMORY
;
1342 if (ret
== WN_SUCCESS
)
1344 LPWSTR lpSystemW
= NULL
;
1347 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1350 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1351 lpBufferW
, &size
, &lpSystemW
);
1352 if (ret
== WN_MORE_DATA
)
1354 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1355 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1357 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1358 lpBufferW
, &size
, &lpSystemW
);
1360 ret
= WN_OUT_OF_MEMORY
;
1362 if (ret
== WN_SUCCESS
)
1364 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1365 &count
, lpBuffer
, cbBuffer
);
1366 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1367 lpNetResourceW
= lpBufferW
;
1368 size
= sizeof(NETRESOURCEA
);
1369 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1370 -1, NULL
, 0, NULL
, NULL
);
1371 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1372 -1, NULL
, 0, NULL
, NULL
);
1374 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1375 -1, NULL
, 0, NULL
, NULL
);
1376 if ((len
) && ( size
+ len
< *cbBuffer
))
1378 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1379 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1380 *lplpSystem
, len
, NULL
, NULL
);
1387 ret
= WN_OUT_OF_MEMORY
;
1388 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1391 ret
= WN_OUT_OF_MEMORY
;
1392 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1394 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1397 ret
= WN_NO_NETWORK
;
1401 TRACE("Returning %d\n", ret
);
1405 /*********************************************************************
1406 * WNetGetResourceInformationW [MPR.@]
1408 * WNetGetResourceInformationW function identifies the network provider
1409 * that owns the resource and gets information about the type of the resource.
1412 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1413 * defines a network resource.
1414 * lpBuffer [ O] the pointer to buffer, containing result. It
1415 * contains NETRESOURCEW structure and strings to
1416 * which the members of the NETRESOURCEW structure
1418 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1420 * lplpSystem [ O] the pointer to string in the output buffer,
1421 * containing the part of the resource name without
1422 * names of the server and share.
1425 * NO_ERROR if the function succeeds. System error code if the function fails.
1428 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1429 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1430 LPWSTR
*lplpSystem
)
1432 DWORD ret
= WN_NO_NETWORK
;
1435 TRACE( "(%p, %p, %p, %p)\n",
1436 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1439 ret
= WN_OUT_OF_MEMORY
;
1440 else if (providerTable
!= NULL
)
1442 /* FIXME: For function value of a variable is indifferent, it does
1443 * search of all providers in a network.
1445 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1447 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1448 WNNC_DLG_GETRESOURCEINFORMATION
)
1450 if (providerTable
->table
[index
].getResourceInformation
)
1451 ret
= providerTable
->table
[index
].getResourceInformation(
1452 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1454 ret
= WN_NO_NETWORK
;
1455 if (ret
== WN_SUCCESS
)
1465 /*********************************************************************
1466 * WNetGetResourceParentA [MPR.@]
1468 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1469 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1471 FIXME( "(%p, %p, %p): stub\n",
1472 lpNetResource
, lpBuffer
, lpBufferSize
);
1474 SetLastError(WN_NO_NETWORK
);
1475 return WN_NO_NETWORK
;
1478 /*********************************************************************
1479 * WNetGetResourceParentW [MPR.@]
1481 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1482 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1484 FIXME( "(%p, %p, %p): stub\n",
1485 lpNetResource
, lpBuffer
, lpBufferSize
);
1487 SetLastError(WN_NO_NETWORK
);
1488 return WN_NO_NETWORK
;
1494 * Connection Functions
1497 /*********************************************************************
1498 * WNetAddConnectionA [MPR.@]
1500 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1501 LPCSTR lpLocalName
)
1503 NETRESOURCEA resourcesA
;
1505 memset(&resourcesA
, 0, sizeof(resourcesA
));
1506 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
1507 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
1508 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1511 /*********************************************************************
1512 * WNetAddConnectionW [MPR.@]
1514 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1515 LPCWSTR lpLocalName
)
1517 NETRESOURCEW resourcesW
;
1519 memset(&resourcesW
, 0, sizeof(resourcesW
));
1520 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
1521 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
1522 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1525 /*********************************************************************
1526 * WNetAddConnection2A [MPR.@]
1528 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1529 LPCSTR lpPassword
, LPCSTR lpUserID
,
1532 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1536 /*********************************************************************
1537 * WNetAddConnection2W [MPR.@]
1539 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1540 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1543 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1547 /*********************************************************************
1548 * WNetAddConnection3A [MPR.@]
1550 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1551 LPCSTR lpPassword
, LPCSTR lpUserID
,
1554 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1555 dwFlags
, NULL
, 0, NULL
);
1558 /*********************************************************************
1559 * WNetAddConnection3W [MPR.@]
1561 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1562 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1565 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1566 dwFlags
, NULL
, 0, NULL
);
1569 struct use_connection_context
1572 NETRESOURCEW
*resource
;
1573 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
1580 DWORD (*pre_set_accessname
)(struct use_connection_context
*);
1581 void (*set_accessname
)(struct use_connection_context
*);
1584 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
)
1586 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1590 if (ctxt
->resource
->lpLocalName
)
1591 len
= strlenW(ctxt
->resource
->lpLocalName
);
1593 len
= strlenW(ctxt
->resource
->lpRemoteName
);
1595 if (++len
> *ctxt
->buffer_size
)
1597 *ctxt
->buffer_size
= len
;
1598 return ERROR_MORE_DATA
;
1602 ctxt
->accessname
= NULL
;
1604 return ERROR_SUCCESS
;
1607 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
)
1609 WCHAR
*accessname
= ctxt
->accessname
;
1610 if (ctxt
->resource
->lpLocalName
)
1611 strcpyW(accessname
, ctxt
->resource
->lpLocalName
);
1613 strcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
1616 static WCHAR
* select_provider(struct use_connection_context
*ctxt
)
1618 DWORD ret
, prov_size
= 0x1000, len
;
1619 LPNETRESOURCEW provider
;
1622 provider
= HeapAlloc(GetProcessHeap(), 0, prov_size
);
1628 ret
= WNetGetResourceInformationW(ctxt
->resource
, provider
, &prov_size
, &system
);
1629 if (ret
== ERROR_MORE_DATA
)
1631 HeapFree(GetProcessHeap(), 0, provider
);
1632 provider
= HeapAlloc(GetProcessHeap(), 0, prov_size
);
1638 ret
= WNetGetResourceInformationW(ctxt
->resource
, provider
, &prov_size
, &system
);
1641 if (ret
!= NO_ERROR
)
1643 HeapFree(GetProcessHeap(), 0, provider
);
1647 len
= WideCharToMultiByte(CP_ACP
, 0, provider
->lpProvider
, -1, NULL
, 0, NULL
, NULL
);
1648 ctxt
->resource
->lpProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1649 if (ctxt
->resource
->lpProvider
)
1650 memcpy(ctxt
->resource
->lpProvider
, provider
->lpProvider
, len
* sizeof(WCHAR
));
1652 HeapFree(GetProcessHeap(), 0, provider
);
1654 return ctxt
->resource
->lpProvider
;
1657 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
1659 WNetProvider
*provider
;
1660 DWORD index
, ret
, caps
;
1661 BOOLEAN redirect
= FALSE
, prov
= FALSE
;
1662 WCHAR letter
[3] = {'z', ':', 0};
1664 if (!providerTable
|| providerTable
->numProviders
== 0)
1665 return WN_NO_NETWORK
;
1667 if (!ctxt
->resource
)
1668 return ERROR_INVALID_PARAMETER
;
1670 if (!ctxt
->resource
->lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
1672 if (ctxt
->resource
->dwType
!= RESOURCETYPE_DISK
&& ctxt
->resource
->dwType
!= RESOURCETYPE_PRINT
)
1674 return ERROR_BAD_DEV_TYPE
;
1677 if (ctxt
->resource
->dwType
== RESOURCETYPE_PRINT
)
1679 FIXME("Locale device selection is not implemented for printers.\n");
1680 return WN_NO_NETWORK
;
1684 ctxt
->resource
->lpLocalName
= letter
;
1687 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
1689 ret
= ERROR_BAD_NET_NAME
;
1693 if (!ctxt
->resource
->lpProvider
)
1695 ctxt
->resource
->lpProvider
= select_provider(ctxt
);
1696 if (!ctxt
->resource
->lpProvider
)
1698 ret
= ERROR_NO_NET_OR_BAD_PATH
;
1705 index
= _findProviderIndexW(ctxt
->resource
->lpProvider
);
1706 if (index
== BAD_PROVIDER_INDEX
)
1708 ret
= ERROR_BAD_PROVIDER
;
1712 provider
= &providerTable
->table
[index
];
1713 caps
= provider
->getCaps(WNNC_CONNECTION
);
1714 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
1716 ret
= ERROR_BAD_PROVIDER
;
1720 if ((ret
= ctxt
->pre_set_accessname(ctxt
)))
1725 ret
= WN_ACCESS_DENIED
;
1728 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
1729 ret
= provider
->addConnection3(ctxt
->hwndOwner
, ctxt
->resource
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
1730 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
1731 ret
= provider
->addConnection(ctxt
->resource
, ctxt
->password
, ctxt
->userid
);
1735 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& letter
[0] >= 'c');
1737 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
1738 ctxt
->set_accessname(ctxt
);
1743 HeapFree(GetProcessHeap(), 0, ctxt
->resource
->lpProvider
);
1744 ctxt
->resource
->lpProvider
= NULL
;
1748 ctxt
->resource
->lpLocalName
= NULL
;
1753 /*****************************************************************
1754 * WNetUseConnectionW [MPR.@]
1756 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
1757 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
1759 struct use_connection_context ctxt
;
1761 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1762 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
1763 accessname
, buffer_size
, result
);
1765 ctxt
.hwndOwner
= hwndOwner
;
1766 ctxt
.resource
= resource
;
1767 ctxt
.resourceA
= NULL
;
1768 ctxt
.password
= (WCHAR
*)password
;
1769 ctxt
.userid
= (WCHAR
*)userid
;
1771 ctxt
.accessname
= accessname
;
1772 ctxt
.buffer_size
= buffer_size
;
1773 ctxt
.result
= result
;
1774 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
1775 ctxt
.set_accessname
= use_connection_set_accessnameW
;
1777 return wnet_use_connection(&ctxt
);
1780 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
)
1782 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1786 if (ctxt
->resourceA
->lpLocalName
)
1787 len
= strlen(ctxt
->resourceA
->lpLocalName
);
1789 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
1791 if (++len
> *ctxt
->buffer_size
)
1793 *ctxt
->buffer_size
= len
;
1794 return ERROR_MORE_DATA
;
1798 ctxt
->accessname
= NULL
;
1800 return ERROR_SUCCESS
;
1803 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
)
1805 char *accessname
= ctxt
->accessname
;
1806 if (ctxt
->resourceA
->lpLocalName
)
1807 strcpy(accessname
, ctxt
->resourceA
->lpLocalName
);
1809 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
1812 static LPWSTR
strdupAtoW( LPCSTR str
)
1817 if (!str
) return NULL
;
1818 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
1819 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1820 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
1824 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
1826 resourceW
->dwScope
= resourceA
->dwScope
;
1827 resourceW
->dwType
= resourceA
->dwType
;
1828 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
1829 resourceW
->dwUsage
= resourceA
->dwUsage
;
1830 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
1831 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
1832 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
1833 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
1836 static void free_netresourceW( NETRESOURCEW
*resource
)
1838 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
1839 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
1840 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
1841 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
1844 /*****************************************************************
1845 * WNetUseConnectionA [MPR.@]
1847 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
1848 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
1849 DWORD
*buffer_size
, DWORD
*result
)
1851 struct use_connection_context ctxt
;
1852 NETRESOURCEW resourceW
;
1855 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
1856 accessname
, buffer_size
, result
);
1858 netresource_a_to_w(resource
, &resourceW
);
1860 ctxt
.hwndOwner
= hwndOwner
;
1861 ctxt
.resource
= &resourceW
;
1862 ctxt
.resourceA
= resource
;
1863 ctxt
.password
= strdupAtoW(password
);
1864 ctxt
.userid
= strdupAtoW(userid
);
1866 ctxt
.accessname
= accessname
;
1867 ctxt
.buffer_size
= buffer_size
;
1868 ctxt
.result
= result
;
1869 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
1870 ctxt
.set_accessname
= use_connection_set_accessnameA
;
1872 ret
= wnet_use_connection(&ctxt
);
1874 free_netresourceW(&resourceW
);
1875 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
1876 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
1881 /*********************************************************************
1882 * WNetCancelConnectionA [MPR.@]
1884 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
1886 FIXME( "(%s, %d), stub\n", debugstr_a(lpName
), fForce
);
1891 /*********************************************************************
1892 * WNetCancelConnectionW [MPR.@]
1894 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
1896 FIXME( "(%s, %d), stub\n", debugstr_w(lpName
), fForce
);
1901 /*********************************************************************
1902 * WNetCancelConnection2A [MPR.@]
1904 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1906 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName
), dwFlags
, fForce
);
1911 /*********************************************************************
1912 * WNetCancelConnection2W [MPR.@]
1914 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1916 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName
), dwFlags
, fForce
);
1921 /*****************************************************************
1922 * WNetRestoreConnectionA [MPR.@]
1924 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
1926 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
1928 SetLastError(WN_NO_NETWORK
);
1929 return WN_NO_NETWORK
;
1932 /*****************************************************************
1933 * WNetRestoreConnectionW [MPR.@]
1935 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
1937 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
1939 SetLastError(WN_NO_NETWORK
);
1940 return WN_NO_NETWORK
;
1943 /**************************************************************************
1944 * WNetGetConnectionA [MPR.@]
1947 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1948 * - WN_NOT_CONNECTED drive is a local drive
1949 * - WN_MORE_DATA buffer isn't big enough
1950 * - WN_SUCCESS success (net path in buffer)
1952 * FIXME: need to test return values under different errors
1954 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
1955 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
1960 ret
= WN_BAD_POINTER
;
1961 else if (!lpBufferSize
)
1962 ret
= WN_BAD_POINTER
;
1963 else if (!lpRemoteName
&& *lpBufferSize
)
1964 ret
= WN_BAD_POINTER
;
1967 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
1971 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1975 WCHAR wideRemoteStatic
[MAX_PATH
];
1976 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
1978 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
1980 /* try once without memory allocation */
1981 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
1983 if (ret
== WN_SUCCESS
)
1985 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1986 -1, NULL
, 0, NULL
, NULL
);
1988 if (len
<= *lpBufferSize
)
1990 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
1991 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1996 *lpBufferSize
= len
;
2000 else if (ret
== WN_MORE_DATA
)
2002 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
2003 wideRemoteSize
* sizeof(WCHAR
));
2007 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
2009 if (ret
== WN_SUCCESS
)
2011 if (len
<= *lpBufferSize
)
2013 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
2014 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2019 *lpBufferSize
= len
;
2023 HeapFree(GetProcessHeap(), 0, wideRemote
);
2026 ret
= WN_OUT_OF_MEMORY
;
2028 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2031 ret
= WN_OUT_OF_MEMORY
;
2034 ret
= WN_BAD_LOCALNAME
;
2038 TRACE("Returning %d\n", ret
);
2042 /* find the network connection for a given drive; helper for WNetGetConnection */
2043 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2047 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2049 DWORD ret
= WN_NOT_CONNECTED
;
2050 DWORD bytes_returned
;
2052 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2053 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2054 0, 0 )) == INVALID_HANDLE_VALUE
)
2056 ERR( "failed to open mount manager err %u\n", GetLastError() );
2059 memset( data
, 0, sizeof(*data
) );
2060 data
->letter
= letter
;
2061 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2062 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2064 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2067 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2070 mount_point
[0] = '\\';
2071 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2073 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2081 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2089 DWORD ret
= WN_NO_NETWORK
;
2091 WCHAR local
[3] = {letter
, ':', 0};
2093 if (providerTable
!= NULL
)
2095 for (index
= 0; index
< providerTable
->numProviders
; index
++)
2097 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
2098 WNNC_CON_GETCONNECTIONS
)
2100 if (providerTable
->table
[index
].getConnection
)
2101 ret
= providerTable
->table
[index
].getConnection(
2102 local
, remote
, size
);
2104 ret
= WN_NO_NETWORK
;
2105 if (ret
== WN_SUCCESS
|| ret
== WN_MORE_DATA
)
2116 /**************************************************************************
2117 * WNetGetConnectionW [MPR.@]
2119 * FIXME: need to test return values under different errors
2121 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2122 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2126 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2130 ret
= WN_BAD_POINTER
;
2131 else if (!lpBufferSize
)
2132 ret
= WN_BAD_POINTER
;
2133 else if (!lpRemoteName
&& *lpBufferSize
)
2134 ret
= WN_BAD_POINTER
;
2135 else if (!lpLocalName
[0])
2136 ret
= WN_BAD_LOCALNAME
;
2139 if (lpLocalName
[1] == ':')
2141 switch(GetDriveTypeW(lpLocalName
))
2144 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2146 case DRIVE_REMOVABLE
:
2149 TRACE("file is local\n");
2150 ret
= WN_NOT_CONNECTED
;
2153 ret
= WN_BAD_LOCALNAME
;
2157 ret
= WN_BAD_LOCALNAME
;
2161 TRACE("Returning %d\n", ret
);
2165 /**************************************************************************
2166 * WNetSetConnectionA [MPR.@]
2168 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2171 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2173 SetLastError(WN_NO_NETWORK
);
2174 return WN_NO_NETWORK
;
2177 /**************************************************************************
2178 * WNetSetConnectionW [MPR.@]
2180 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2183 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2185 SetLastError(WN_NO_NETWORK
);
2186 return WN_NO_NETWORK
;
2189 /*****************************************************************
2190 * WNetGetUniversalNameA [MPR.@]
2192 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2193 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2197 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2198 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2200 switch (dwInfoLevel
)
2202 case UNIVERSAL_NAME_INFO_LEVEL
:
2204 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2206 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2208 err
= ERROR_NOT_CONNECTED
;
2212 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2213 if (*lpBufferSize
< size
)
2218 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2219 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2223 case REMOTE_NAME_INFO_LEVEL
:
2224 err
= WN_NOT_CONNECTED
;
2236 /*****************************************************************
2237 * WNetGetUniversalNameW [MPR.@]
2239 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2240 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2244 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2245 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2247 switch (dwInfoLevel
)
2249 case UNIVERSAL_NAME_INFO_LEVEL
:
2251 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2253 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2255 err
= ERROR_NOT_CONNECTED
;
2259 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2260 if (*lpBufferSize
< size
)
2265 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2266 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2270 case REMOTE_NAME_INFO_LEVEL
:
2271 err
= WN_NO_NETWORK
;
2279 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2289 /**************************************************************************
2290 * WNetGetUserA [MPR.@]
2292 * FIXME: we should not return ourselves, but the owner of the drive lpName
2294 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2296 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2297 return GetLastError();
2300 /*****************************************************************
2301 * WNetGetUserW [MPR.@]
2303 * FIXME: we should not return ourselves, but the owner of the drive lpName
2305 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2307 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2308 return GetLastError();
2311 /*********************************************************************
2312 * WNetConnectionDialog [MPR.@]
2314 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2316 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2318 SetLastError(WN_NO_NETWORK
);
2319 return WN_NO_NETWORK
;
2322 /*********************************************************************
2323 * WNetConnectionDialog1A [MPR.@]
2325 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2327 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2329 SetLastError(WN_NO_NETWORK
);
2330 return WN_NO_NETWORK
;
2333 /*********************************************************************
2334 * WNetConnectionDialog1W [MPR.@]
2336 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2338 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2340 SetLastError(WN_NO_NETWORK
);
2341 return WN_NO_NETWORK
;
2344 /*********************************************************************
2345 * WNetDisconnectDialog [MPR.@]
2347 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2349 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2351 SetLastError(WN_NO_NETWORK
);
2352 return WN_NO_NETWORK
;
2355 /*********************************************************************
2356 * WNetDisconnectDialog1A [MPR.@]
2358 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2360 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2362 SetLastError(WN_NO_NETWORK
);
2363 return WN_NO_NETWORK
;
2366 /*********************************************************************
2367 * WNetDisconnectDialog1W [MPR.@]
2369 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2371 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2373 SetLastError(WN_NO_NETWORK
);
2374 return WN_NO_NETWORK
;
2377 /*********************************************************************
2378 * WNetGetLastErrorA [MPR.@]
2380 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2381 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2382 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2384 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2385 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2387 SetLastError(WN_NO_NETWORK
);
2388 return WN_NO_NETWORK
;
2391 /*********************************************************************
2392 * WNetGetLastErrorW [MPR.@]
2394 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2395 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2396 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2398 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2399 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2401 SetLastError(WN_NO_NETWORK
);
2402 return WN_NO_NETWORK
;
2405 /*********************************************************************
2406 * WNetGetNetworkInformationA [MPR.@]
2408 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2409 LPNETINFOSTRUCT lpNetInfoStruct
)
2413 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2416 ret
= WN_BAD_POINTER
;
2421 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2424 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2428 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2430 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2431 HeapFree(GetProcessHeap(), 0, wideProvider
);
2434 ret
= WN_OUT_OF_MEMORY
;
2437 ret
= GetLastError();
2441 TRACE("Returning %d\n", ret
);
2445 /*********************************************************************
2446 * WNetGetNetworkInformationW [MPR.@]
2448 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2449 LPNETINFOSTRUCT lpNetInfoStruct
)
2453 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2456 ret
= WN_BAD_POINTER
;
2457 else if (!lpNetInfoStruct
)
2458 ret
= WN_BAD_POINTER
;
2459 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2463 if (providerTable
&& providerTable
->numProviders
)
2465 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2467 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2469 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2470 lpNetInfoStruct
->dwProviderVersion
=
2471 providerTable
->table
[providerIndex
].dwSpecVersion
;
2472 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2473 lpNetInfoStruct
->dwCharacteristics
= 0;
2474 lpNetInfoStruct
->dwHandle
= 0;
2475 lpNetInfoStruct
->wNetType
=
2476 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2477 lpNetInfoStruct
->dwPrinters
= -1;
2478 lpNetInfoStruct
->dwDrives
= -1;
2482 ret
= WN_BAD_PROVIDER
;
2485 ret
= WN_NO_NETWORK
;
2489 TRACE("Returning %d\n", ret
);
2493 /*****************************************************************
2494 * WNetGetProviderNameA [MPR.@]
2496 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2497 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2501 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2505 ret
= WN_BAD_POINTER
;
2506 else if (!lpBufferSize
)
2507 ret
= WN_BAD_POINTER
;
2514 ret
= WN_NO_NETWORK
;
2515 for (i
= 0; i
< providerTable
->numProviders
&&
2516 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2519 if (i
< providerTable
->numProviders
)
2521 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2522 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2524 if (*lpBufferSize
< sizeNeeded
)
2526 *lpBufferSize
= sizeNeeded
;
2531 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2532 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2534 /* FIXME: is *lpBufferSize set to the number of characters
2540 ret
= WN_NO_NETWORK
;
2544 TRACE("Returning %d\n", ret
);
2548 /*****************************************************************
2549 * WNetGetProviderNameW [MPR.@]
2551 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2552 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2556 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2560 ret
= WN_BAD_POINTER
;
2561 else if (!lpBufferSize
)
2562 ret
= WN_BAD_POINTER
;
2569 ret
= WN_NO_NETWORK
;
2570 for (i
= 0; i
< providerTable
->numProviders
&&
2571 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2574 if (i
< providerTable
->numProviders
)
2576 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2578 if (*lpBufferSize
< sizeNeeded
)
2580 *lpBufferSize
= sizeNeeded
;
2585 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2587 /* FIXME: is *lpBufferSize set to the number of characters
2593 ret
= WN_NO_NETWORK
;
2597 TRACE("Returning %d\n", ret
);