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
23 #define WIN32_NO_STATUS
27 //#include "winbase.h"
33 //#include "winuser.h"
34 #define WINE_MOUNTMGR_EXTENSIONS
35 #include <ddk/mountmgr.h>
36 #include <wine/debug.h>
37 #include <wine/unicode.h>
39 //#include "wnetpriv.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(mpr
);
43 /* Data structures representing network service providers. Assumes only one
44 * thread creates them, and that they are constant for the life of the process
45 * (and therefore doesn't synchronize access).
46 * FIXME: only basic provider data and enumeration-related data are implemented
47 * so far, need to implement the rest too.
49 typedef struct _WNetProvider
57 PF_NPOpenEnum openEnum
;
58 PF_NPEnumResource enumResource
;
59 PF_NPCloseEnum closeEnum
;
60 PF_NPGetResourceInformation getResourceInformation
;
61 } WNetProvider
, *PWNetProvider
;
63 typedef struct _WNetProviderTable
68 WNetProvider table
[1];
69 } WNetProviderTable
, *PWNetProviderTable
;
71 #define WNET_ENUMERATOR_TYPE_NULL 0
72 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
73 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
74 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
76 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
77 * the enumeration; it represents one of the following types:
78 * - a 'null' enumeration, one that contains no members
79 * - a global enumeration, one that's executed across all providers
80 * - a provider-specific enumeration, one that's only executed by a single
82 * - a context enumeration. I know this contradicts what I just said about
83 * there being no correspondence between the scope and the type, but it's
84 * necessary for the special case that a "Entire Network" entry needs to
85 * be enumerated in an enumeration of the context scope. Thus an enumeration
86 * of the context scope results in a context type enumerator, which morphs
87 * into a global enumeration (so the enumeration continues across all
90 typedef struct _WNetEnumerator
100 } WNetEnumerator
, *PWNetEnumerator
;
102 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
104 /* Returns an index (into the global WNetProviderTable) of the provider with
105 * the given name, or BAD_PROVIDER_INDEX if not found.
107 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
109 static PWNetProviderTable providerTable
;
112 * Global provider table functions
115 static void _tryLoadProvider(PCWSTR provider
)
117 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
118 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
119 'S','e','r','v','i','c','e','s','\\',0 };
120 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
121 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
122 WCHAR serviceName
[MAX_PATH
];
125 TRACE("%s\n", debugstr_w(provider
));
126 snprintfW(serviceName
, sizeof(serviceName
) / sizeof(WCHAR
), serviceFmt
,
127 servicePrefix
, provider
);
128 serviceName
[sizeof(serviceName
) / sizeof(WCHAR
) - 1] = '\0';
129 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
132 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
134 WCHAR providerPath
[MAX_PATH
];
135 DWORD type
, size
= sizeof(providerPath
);
137 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
138 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
140 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
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 PF_NPGetCaps getCaps
= (PF_NPGetCaps
)GetProcAddress(hLib
,
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
= (PF_NPOpenEnum
)
182 GetProcAddress(hLib
, "NPOpenEnum");
183 TRACE("openEnum is %p\n", provider
->openEnum
);
184 provider
->enumResource
= (PF_NPEnumResource
)
185 GetProcAddress(hLib
, "NPEnumResource");
186 TRACE("enumResource is %p\n",
187 provider
->enumResource
);
188 provider
->closeEnum
= (PF_NPCloseEnum
)
189 GetProcAddress(hLib
, "NPCloseEnum");
190 TRACE("closeEnum is %p\n", provider
->closeEnum
);
191 provider
->getResourceInformation
= (PF_NPGetResourceInformation
)
192 GetProcAddress(hLib
, "NPGetResourceInformation");
193 TRACE("getResourceInformation is %p\n",
194 provider
->getResourceInformation
);
195 if (!provider
->openEnum
|| !provider
->enumResource
196 || !provider
->closeEnum
)
198 provider
->openEnum
= NULL
;
199 provider
->enumResource
= NULL
;
200 provider
->closeEnum
= NULL
;
201 provider
->dwEnumScopes
= 0;
202 WARN("Couldn't load enumeration functions\n");
205 providerTable
->numProviders
++;
209 WARN("Provider %s didn't export NPGetCaps\n",
210 debugstr_w(provider
));
211 HeapFree(GetProcessHeap(), 0, name
);
217 WARN("Couldn't load library %s for provider %s\n",
218 debugstr_w(providerPath
), debugstr_w(provider
));
219 HeapFree(GetProcessHeap(), 0, name
);
224 WARN("Couldn't get provider name for provider %s\n",
225 debugstr_w(provider
));
229 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
233 WARN("Couldn't open service key for provider %s\n",
234 debugstr_w(provider
));
237 void wnetInit(HINSTANCE hInstDll
)
239 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
240 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
241 'C','o','n','t','r','o','l','\\',
242 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
243 'O','r','d','e','r',0 };
244 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
245 'O','r','d','e','r',0 };
248 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
253 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
256 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
262 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
263 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
268 TRACE("provider order is %s\n", debugstr_w(providers
));
269 /* first count commas as a heuristic for how many to
270 * allocate space for */
271 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
273 ptr
= strchrW(ptr
, ',');
280 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
281 sizeof(WNetProviderTable
)
282 + (numToAllocate
- 1) * sizeof(WNetProvider
));
286 int entireNetworkLen
;
287 LPCWSTR stringresource
;
289 entireNetworkLen
= LoadStringW(hInstDll
,
290 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
291 providerTable
->entireNetwork
= HeapAlloc(
292 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
294 if (providerTable
->entireNetwork
)
296 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
297 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
299 providerTable
->numAllocated
= numToAllocate
;
300 for (ptr
= providers
; ptr
; )
303 ptr
= strchrW(ptr
, ',');
306 _tryLoadProvider(ptrPrev
);
310 HeapFree(GetProcessHeap(), 0, providers
);
323 for (i
= 0; i
< providerTable
->numProviders
; i
++)
325 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
326 FreeModule(providerTable
->table
[i
].hLib
);
328 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
329 HeapFree(GetProcessHeap(), 0, providerTable
);
330 providerTable
= NULL
;
334 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
336 DWORD ret
= BAD_PROVIDER_INDEX
;
338 if (providerTable
&& providerTable
->numProviders
)
342 for (i
= 0; i
< providerTable
->numProviders
&&
343 ret
== BAD_PROVIDER_INDEX
; i
++)
344 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
354 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
360 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
366 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
367 if (lpNet
->lpRemoteName
)
369 len
= strlenW(lpNet
->lpRemoteName
) + 1;
370 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
371 if (ret
->lpRemoteName
)
372 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
381 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
385 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
386 HeapFree(GetProcessHeap(), 0, lpNet
);
390 static PWNetEnumerator
_createNullEnumerator(void)
392 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
393 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
396 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
400 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
401 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
403 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
404 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
408 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
409 ret
->dwScope
= dwScope
;
410 ret
->dwType
= dwType
;
411 ret
->dwUsage
= dwUsage
;
412 ret
->lpNet
= _copyNetResourceForEnumW(lpNet
);
417 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
418 DWORD dwUsage
, DWORD index
, HANDLE handle
)
422 if (!providerTable
|| index
>= providerTable
->numProviders
)
426 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
429 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
430 ret
->providerIndex
= index
;
431 ret
->dwScope
= dwScope
;
432 ret
->dwType
= dwType
;
433 ret
->dwUsage
= dwUsage
;
434 ret
->handle
= handle
;
440 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
443 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
444 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
448 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
449 ret
->dwScope
= dwScope
;
450 ret
->dwType
= dwType
;
451 ret
->dwUsage
= dwUsage
;
456 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
457 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
458 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
459 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
460 * if not all members of the array could be thunked, and something else on
463 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
464 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
466 DWORD i
, numToThunk
, totalBytes
, ret
;
470 return WN_BAD_POINTER
;
472 return WN_BAD_POINTER
;
476 return WN_BAD_POINTER
;
478 return WN_BAD_POINTER
;
480 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
482 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
484 totalBytes
+= sizeof(NETRESOURCEA
);
485 if (lpNet
->lpLocalName
)
486 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
487 -1, NULL
, 0, NULL
, NULL
);
488 if (lpNet
->lpRemoteName
)
489 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
490 -1, NULL
, 0, NULL
, NULL
);
491 if (lpNet
->lpComment
)
492 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
493 -1, NULL
, 0, NULL
, NULL
);
494 if (lpNet
->lpProvider
)
495 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
496 -1, NULL
, 0, NULL
, NULL
);
497 if (totalBytes
< *lpBufferSize
)
500 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
501 for (i
= 0; i
< numToThunk
; i
++)
503 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
504 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
506 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
507 /* lie about string lengths, we already verified how many
508 * we have space for above
510 if (lpNetIn
->lpLocalName
)
512 lpNetOut
->lpLocalName
= strNext
;
513 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
514 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
516 if (lpNetIn
->lpRemoteName
)
518 lpNetOut
->lpRemoteName
= strNext
;
519 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
520 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
522 if (lpNetIn
->lpComment
)
524 lpNetOut
->lpComment
= strNext
;
525 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
526 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
528 if (lpNetIn
->lpProvider
)
530 lpNetOut
->lpProvider
= strNext
;
531 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
532 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
535 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
536 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
541 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
542 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
543 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
544 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
545 * if not all members of the array could be thunked, and something else on
548 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
549 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
551 DWORD i
, numToThunk
, totalBytes
, ret
;
555 return WN_BAD_POINTER
;
557 return WN_BAD_POINTER
;
561 return WN_BAD_POINTER
;
563 return WN_BAD_POINTER
;
565 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
567 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
569 totalBytes
+= sizeof(NETRESOURCEW
);
570 if (lpNet
->lpLocalName
)
571 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
572 -1, NULL
, 0) * sizeof(WCHAR
);
573 if (lpNet
->lpRemoteName
)
574 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
575 -1, NULL
, 0) * sizeof(WCHAR
);
576 if (lpNet
->lpComment
)
577 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
578 -1, NULL
, 0) * sizeof(WCHAR
);
579 if (lpNet
->lpProvider
)
580 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
581 -1, NULL
, 0) * sizeof(WCHAR
);
582 if (totalBytes
< *lpBufferSize
)
585 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
586 for (i
= 0; i
< numToThunk
; i
++)
588 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
589 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
591 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
592 /* lie about string lengths, we already verified how many
593 * we have space for above
595 if (lpNetIn
->lpLocalName
)
597 lpNetOut
->lpLocalName
= strNext
;
598 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
599 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
601 if (lpNetIn
->lpRemoteName
)
603 lpNetOut
->lpRemoteName
= strNext
;
604 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
605 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
607 if (lpNetIn
->lpComment
)
609 lpNetOut
->lpComment
= strNext
;
610 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
611 -1, lpNetOut
->lpComment
, *lpBufferSize
);
613 if (lpNetIn
->lpProvider
)
615 lpNetOut
->lpProvider
= strNext
;
616 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
617 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
620 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
621 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
626 /*********************************************************************
627 * WNetOpenEnumA [MPR.@]
629 * See comments for WNetOpenEnumW.
631 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
632 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
636 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
637 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
640 ret
= WN_BAD_POINTER
;
641 else if (!providerTable
|| providerTable
->numProviders
== 0)
650 LPNETRESOURCEW lpNetWide
= NULL
;
652 DWORD size
= sizeof(buf
), count
= 1;
653 BOOL allocated
= FALSE
;
655 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
656 if (ret
== WN_MORE_DATA
)
658 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
662 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
667 ret
= WN_OUT_OF_MEMORY
;
669 else if (ret
== WN_SUCCESS
)
670 lpNetWide
= (LPNETRESOURCEW
)buf
;
671 if (ret
== WN_SUCCESS
)
672 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
675 HeapFree(GetProcessHeap(), 0, lpNetWide
);
678 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
682 TRACE("Returning %d\n", ret
);
686 /*********************************************************************
687 * WNetOpenEnumW [MPR.@]
689 * Network enumeration has way too many parameters, so I'm not positive I got
690 * them right. What I've got so far:
692 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
693 * all the network providers should be enumerated.
695 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
696 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
697 * lpProvider is set, all the network providers should be enumerated.
698 * (This means the enumeration is a list of network providers, not that the
699 * enumeration is passed on to the providers.)
701 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
702 * resource matches the "Entire Network" resource (no remote name, no
703 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
704 * enumeration is done on every network provider.
706 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
707 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
708 * only to the given network provider.
710 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
711 * no lpProvider is set, enumeration will be tried on every network provider,
712 * in the order in which they're loaded.
714 * - The LPNETRESOURCE should be disregarded for scopes besides
715 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
716 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
718 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
719 * resource in the enumerated list, as well as any machines in your
720 * workgroup. The machines in your workgroup come from doing a
721 * RESOURCE_CONTEXT enumeration of every Network Provider.
723 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
724 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
728 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
729 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
732 ret
= WN_BAD_POINTER
;
733 else if (!providerTable
|| providerTable
->numProviders
== 0)
742 case RESOURCE_GLOBALNET
:
745 if (lpNet
->lpProvider
)
747 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
749 if (index
!= BAD_PROVIDER_INDEX
)
751 if (providerTable
->table
[index
].openEnum
&&
752 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
756 ret
= providerTable
->table
[index
].openEnum(
757 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
758 if (ret
== WN_SUCCESS
)
760 *lphEnum
= _createProviderEnumerator(
761 dwScope
, dwType
, dwUsage
, index
, handle
);
762 ret
= *lphEnum
? WN_SUCCESS
:
767 ret
= WN_NOT_SUPPORTED
;
770 ret
= WN_BAD_PROVIDER
;
772 else if (lpNet
->lpRemoteName
)
774 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
775 dwType
, dwUsage
, lpNet
);
776 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
780 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
781 providerTable
->entireNetwork
))
783 /* comment matches the "Entire Network", enumerate
784 * global scope of every provider
786 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
787 dwType
, dwUsage
, lpNet
);
791 /* this is the same as not having passed lpNet */
792 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
793 dwType
, dwUsage
, NULL
);
795 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
800 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
802 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
805 case RESOURCE_CONTEXT
:
806 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
807 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
809 case RESOURCE_REMEMBERED
:
810 case RESOURCE_CONNECTED
:
811 *lphEnum
= _createNullEnumerator();
812 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
815 WARN("unknown scope 0x%08x\n", dwScope
);
821 TRACE("Returning %d\n", ret
);
825 /*********************************************************************
826 * WNetEnumResourceA [MPR.@]
828 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
829 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
833 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
836 ret
= WN_BAD_POINTER
;
838 ret
= WN_BAD_POINTER
;
840 ret
= WN_BAD_POINTER
;
841 else if (!lpBufferSize
)
842 ret
= WN_BAD_POINTER
;
843 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
845 *lpBufferSize
= sizeof(NETRESOURCEA
);
850 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
851 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
855 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
857 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
859 /* FIXME: this isn't necessarily going to work in the case of
860 * WN_MORE_DATA, because our enumerator may have moved on to
861 * the next provider. MSDN states that a large (16KB) buffer
862 * size is the appropriate usage of this function, so
863 * hopefully it won't be an issue.
865 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
866 lpBuffer
, lpBufferSize
);
867 *lpcCount
= localCount
;
869 HeapFree(GetProcessHeap(), 0, localBuffer
);
872 ret
= WN_OUT_OF_MEMORY
;
876 TRACE("Returning %d\n", ret
);
880 static DWORD
_countProviderBytesW(PWNetProvider provider
)
886 ret
= sizeof(NETRESOURCEW
);
887 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
894 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
895 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
900 return WN_BAD_POINTER
;
901 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
904 return WN_BAD_POINTER
;
906 return WN_BAD_POINTER
;
908 return WN_BAD_POINTER
;
909 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
912 if (!providerTable
|| enumerator
->providerIndex
>=
913 providerTable
->numProviders
)
914 ret
= WN_NO_MORE_ENTRIES
;
917 DWORD bytes
= 0, count
= 0, countLimit
, i
;
918 LPNETRESOURCEW resource
;
921 countLimit
= *lpcCount
== -1 ?
922 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
923 while (count
< countLimit
&& bytes
< *lpBufferSize
)
925 DWORD bytesNext
= _countProviderBytesW(
926 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
928 if (bytes
+ bytesNext
< *lpBufferSize
)
934 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
935 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
937 resource
->dwScope
= RESOURCE_GLOBALNET
;
938 resource
->dwType
= RESOURCETYPE_ANY
;
939 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
940 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
941 RESOURCEUSAGE_RESERVED
;
942 resource
->lpLocalName
= NULL
;
943 resource
->lpRemoteName
= strNext
;
944 strcpyW(resource
->lpRemoteName
,
945 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
946 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
947 resource
->lpComment
= NULL
;
948 resource
->lpProvider
= strNext
;
949 strcpyW(resource
->lpProvider
,
950 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
951 strNext
+= strlenW(resource
->lpProvider
) + 1;
953 enumerator
->providerIndex
+= count
;
955 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
957 TRACE("Returning %d\n", ret
);
961 /* Advances the enumerator (assumed to be a global enumerator) to the next
962 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
963 * not open a handle with the next provider.
964 * If the existing handle is NULL, may leave the enumerator unchanged, since
965 * the current provider may support the desired scope.
966 * If the existing handle is not NULL, closes it before moving on.
967 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
968 * provider, and another error on failure.
970 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
973 return WN_BAD_POINTER
;
974 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
976 if (!providerTable
|| enumerator
->providerIndex
>=
977 providerTable
->numProviders
)
978 return WN_NO_MORE_ENTRIES
;
980 if (enumerator
->providerDone
)
983 enumerator
->providerDone
= FALSE
;
984 if (enumerator
->handle
)
986 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
988 enumerator
->handle
= NULL
;
989 enumerator
->providerIndex
++;
991 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
992 dwEnum
= WNNC_ENUM_LOCAL
;
993 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
994 dwEnum
= WNNC_ENUM_GLOBAL
;
995 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
996 dwEnum
= WNNC_ENUM_CONTEXT
;
997 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
998 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
999 & dwEnum
); enumerator
->providerIndex
++)
1002 return enumerator
->providerIndex
< providerTable
->numProviders
?
1003 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1006 /* "Passes through" call to the next provider that supports the enumeration
1008 * FIXME: if one call to a provider's enumerator succeeds while there's still
1009 * space in lpBuffer, I don't call to the next provider. The caller may not
1010 * expect that it should call EnumResourceW again with a return value of
1011 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1012 * may have to be moved around a bit, ick.
1014 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1015 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1020 return WN_BAD_POINTER
;
1021 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1022 return WN_BAD_VALUE
;
1024 return WN_BAD_POINTER
;
1026 return WN_BAD_POINTER
;
1028 return WN_BAD_POINTER
;
1029 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1030 return WN_MORE_DATA
;
1032 ret
= _globalEnumeratorAdvance(enumerator
);
1033 if (ret
== WN_SUCCESS
)
1035 ret
= providerTable
->table
[enumerator
->providerIndex
].
1036 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1037 enumerator
->dwUsage
, enumerator
->lpNet
,
1038 &enumerator
->handle
);
1039 if (ret
== WN_SUCCESS
)
1041 ret
= providerTable
->table
[enumerator
->providerIndex
].
1042 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1044 if (ret
!= WN_MORE_DATA
)
1045 enumerator
->providerDone
= TRUE
;
1048 TRACE("Returning %d\n", ret
);
1052 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1053 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1058 return WN_BAD_POINTER
;
1059 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1060 return WN_BAD_VALUE
;
1062 return WN_BAD_POINTER
;
1064 return WN_BAD_POINTER
;
1066 return WN_BAD_POINTER
;
1067 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1068 return WN_MORE_DATA
;
1070 return WN_NO_NETWORK
;
1072 switch (enumerator
->dwScope
)
1074 case RESOURCE_GLOBALNET
:
1075 if (enumerator
->lpNet
)
1076 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1077 lpBuffer
, lpBufferSize
);
1079 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1082 case RESOURCE_CONTEXT
:
1083 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1087 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1088 ret
= WN_NO_MORE_ENTRIES
;
1090 TRACE("Returning %d\n", ret
);
1094 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1095 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1098 return WN_BAD_POINTER
;
1099 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1100 return WN_BAD_VALUE
;
1101 if (!enumerator
->handle
)
1102 return WN_BAD_VALUE
;
1104 return WN_BAD_POINTER
;
1106 return WN_BAD_POINTER
;
1108 return WN_BAD_POINTER
;
1110 return WN_NO_NETWORK
;
1111 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1112 return WN_NO_MORE_ENTRIES
;
1113 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1114 return WN_BAD_VALUE
;
1115 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1116 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1119 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1120 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1123 size_t cchEntireNetworkLen
, bytesNeeded
;
1126 return WN_BAD_POINTER
;
1127 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1128 return WN_BAD_VALUE
;
1130 return WN_BAD_POINTER
;
1132 return WN_BAD_POINTER
;
1134 return WN_BAD_POINTER
;
1136 return WN_NO_NETWORK
;
1138 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1139 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1140 if (*lpBufferSize
< bytesNeeded
)
1142 *lpBufferSize
= bytesNeeded
;
1147 LPNETRESOURCEW lpNet
= lpBuffer
;
1149 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1150 lpNet
->dwType
= enumerator
->dwType
;
1151 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1152 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1153 lpNet
->lpLocalName
= NULL
;
1154 lpNet
->lpRemoteName
= NULL
;
1155 lpNet
->lpProvider
= NULL
;
1156 /* odd, but correct: put comment at end of buffer, so it won't get
1157 * overwritten by subsequent calls to a provider's enumResource
1159 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1160 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1161 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1164 if (ret
== WN_SUCCESS
)
1166 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1168 /* "Entire Network" entry enumerated--morph this into a global
1169 * enumerator. enumerator->lpNet continues to be NULL, since it has
1170 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1172 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1173 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1174 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1175 if (ret
== WN_SUCCESS
)
1177 /* reflect the fact that we already enumerated "Entire Network" */
1179 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1183 /* the provider enumeration failed, but we already succeeded in
1184 * enumerating "Entire Network"--leave type as global to allow a
1185 * retry, but indicate success with a count of one.
1189 *lpBufferSize
= bytesNeeded
;
1192 TRACE("Returning %d\n", ret
);
1196 /*********************************************************************
1197 * WNetEnumResourceW [MPR.@]
1199 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1200 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1204 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1207 ret
= WN_BAD_POINTER
;
1209 ret
= WN_BAD_POINTER
;
1211 ret
= WN_BAD_POINTER
;
1212 else if (!lpBufferSize
)
1213 ret
= WN_BAD_POINTER
;
1214 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1216 *lpBufferSize
= sizeof(NETRESOURCEW
);
1221 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1223 switch (enumerator
->enumType
)
1225 case WNET_ENUMERATOR_TYPE_NULL
:
1226 ret
= WN_NO_MORE_ENTRIES
;
1228 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1229 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1232 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1233 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1236 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1237 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1241 WARN("bogus enumerator type!\n");
1242 ret
= WN_NO_NETWORK
;
1247 TRACE("Returning %d\n", ret
);
1251 /*********************************************************************
1252 * WNetCloseEnum [MPR.@]
1254 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1258 TRACE( "(%p)\n", hEnum
);
1262 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1264 switch (enumerator
->enumType
)
1266 case WNET_ENUMERATOR_TYPE_NULL
:
1269 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1270 if (enumerator
->lpNet
)
1271 _freeEnumNetResource(enumerator
->lpNet
);
1272 if (enumerator
->handle
)
1273 providerTable
->table
[enumerator
->providerIndex
].
1274 closeEnum(enumerator
->handle
);
1277 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1278 if (enumerator
->handle
)
1279 providerTable
->table
[enumerator
->providerIndex
].
1280 closeEnum(enumerator
->handle
);
1284 WARN("bogus enumerator type!\n");
1285 ret
= WN_BAD_HANDLE
;
1287 HeapFree(GetProcessHeap(), 0, hEnum
);
1290 ret
= WN_BAD_HANDLE
;
1293 TRACE("Returning %d\n", ret
);
1297 /*********************************************************************
1298 * WNetGetResourceInformationA [MPR.@]
1300 * See WNetGetResourceInformationW
1302 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1303 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1308 TRACE( "(%p, %p, %p, %p)\n",
1309 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1311 if (!providerTable
|| providerTable
->numProviders
== 0)
1312 ret
= WN_NO_NETWORK
;
1313 else if (lpNetResource
)
1315 LPNETRESOURCEW lpNetResourceW
= NULL
;
1316 DWORD size
= 1024, count
= 1;
1319 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1320 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1321 if (ret
== WN_MORE_DATA
)
1323 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1324 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1326 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1327 &count
, lpNetResourceW
, &size
);
1329 ret
= WN_OUT_OF_MEMORY
;
1331 if (ret
== WN_SUCCESS
)
1333 LPWSTR lpSystemW
= NULL
;
1336 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1339 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1340 lpBufferW
, &size
, &lpSystemW
);
1341 if (ret
== WN_MORE_DATA
)
1343 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1344 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1346 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1347 lpBufferW
, &size
, &lpSystemW
);
1349 ret
= WN_OUT_OF_MEMORY
;
1351 if (ret
== WN_SUCCESS
)
1353 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1354 &count
, lpBuffer
, cbBuffer
);
1355 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1356 lpNetResourceW
= lpBufferW
;
1357 size
= sizeof(NETRESOURCEA
);
1358 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1359 -1, NULL
, 0, NULL
, NULL
);
1360 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1361 -1, NULL
, 0, NULL
, NULL
);
1363 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1364 -1, NULL
, 0, NULL
, NULL
);
1365 if ((len
) && ( size
+ len
< *cbBuffer
))
1367 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1368 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1369 *lplpSystem
, len
, NULL
, NULL
);
1376 ret
= WN_OUT_OF_MEMORY
;
1377 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1380 ret
= WN_OUT_OF_MEMORY
;
1381 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1383 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1386 ret
= WN_NO_NETWORK
;
1390 TRACE("Returning %d\n", ret
);
1394 /*********************************************************************
1395 * WNetGetResourceInformationW [MPR.@]
1397 * WNetGetResourceInformationW function identifies the network provider
1398 * that owns the resource and gets information about the type of the resource.
1401 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1402 * defines a network resource.
1403 * lpBuffer [ O] the pointer to buffer, containing result. It
1404 * contains NETRESOURCEW structure and strings to
1405 * which the members of the NETRESOURCEW structure
1407 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1409 * lplpSystem [ O] the pointer to string in the output buffer,
1410 * containing the part of the resource name without
1411 * names of the server and share.
1414 * NO_ERROR if the function succeeds. System error code if the function fails.
1417 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1418 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1419 LPWSTR
*lplpSystem
)
1421 DWORD ret
= WN_NO_NETWORK
;
1424 TRACE( "(%p, %p, %p, %p)\n",
1425 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1428 ret
= WN_OUT_OF_MEMORY
;
1429 else if (providerTable
!= NULL
)
1431 /* FIXME: For function value of a variable is indifferent, it does
1432 * search of all providers in a network.
1434 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1436 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1437 WNNC_DLG_GETRESOURCEINFORMATION
)
1439 if (providerTable
->table
[index
].getResourceInformation
)
1440 ret
= providerTable
->table
[index
].getResourceInformation(
1441 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1443 ret
= WN_NO_NETWORK
;
1444 if (ret
== WN_SUCCESS
)
1454 /*********************************************************************
1455 * WNetGetResourceParentA [MPR.@]
1457 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1458 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1460 FIXME( "(%p, %p, %p): stub\n",
1461 lpNetResource
, lpBuffer
, lpBufferSize
);
1463 SetLastError(WN_NO_NETWORK
);
1464 return WN_NO_NETWORK
;
1467 /*********************************************************************
1468 * WNetGetResourceParentW [MPR.@]
1470 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1471 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1473 FIXME( "(%p, %p, %p): stub\n",
1474 lpNetResource
, lpBuffer
, lpBufferSize
);
1476 SetLastError(WN_NO_NETWORK
);
1477 return WN_NO_NETWORK
;
1483 * Connection Functions
1486 /*********************************************************************
1487 * WNetAddConnectionA [MPR.@]
1489 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1490 LPCSTR lpLocalName
)
1492 FIXME( "(%s, %p, %s): stub\n",
1493 debugstr_a(lpRemoteName
), lpPassword
, debugstr_a(lpLocalName
) );
1495 SetLastError(WN_NO_NETWORK
);
1496 return WN_NO_NETWORK
;
1499 /*********************************************************************
1500 * WNetAddConnectionW [MPR.@]
1502 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1503 LPCWSTR lpLocalName
)
1505 FIXME( "(%s, %p, %s): stub\n",
1506 debugstr_w(lpRemoteName
), lpPassword
, debugstr_w(lpLocalName
) );
1508 SetLastError(WN_NO_NETWORK
);
1509 return WN_NO_NETWORK
;
1512 /*********************************************************************
1513 * WNetAddConnection2A [MPR.@]
1515 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1516 LPCSTR lpPassword
, LPCSTR lpUserID
,
1519 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1520 lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
);
1522 SetLastError(WN_NO_NETWORK
);
1523 return WN_NO_NETWORK
;
1526 /*********************************************************************
1527 * WNetAddConnection2W [MPR.@]
1529 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1530 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1533 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1534 lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
);
1536 SetLastError(WN_NO_NETWORK
);
1537 return WN_NO_NETWORK
;
1540 /*********************************************************************
1541 * WNetAddConnection3A [MPR.@]
1543 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1544 LPCSTR lpPassword
, LPCSTR lpUserID
,
1547 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1548 hwndOwner
, lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
);
1550 SetLastError(WN_NO_NETWORK
);
1551 return WN_NO_NETWORK
;
1554 /*********************************************************************
1555 * WNetAddConnection3W [MPR.@]
1557 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1558 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1561 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1562 hwndOwner
, lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
);
1564 SetLastError(WN_NO_NETWORK
);
1565 return WN_NO_NETWORK
;
1568 /*****************************************************************
1569 * WNetUseConnectionA [MPR.@]
1571 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1572 LPCSTR lpPassword
, LPCSTR lpUserID
, DWORD dwFlags
,
1573 LPSTR lpAccessName
, LPDWORD lpBufferSize
,
1576 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1577 hwndOwner
, lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
,
1578 debugstr_a(lpAccessName
), lpBufferSize
, lpResult
);
1580 SetLastError(WN_NO_NETWORK
);
1581 return WN_NO_NETWORK
;
1584 /*****************************************************************
1585 * WNetUseConnectionW [MPR.@]
1587 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1588 LPCWSTR lpPassword
, LPCWSTR lpUserID
, DWORD dwFlags
,
1589 LPWSTR lpAccessName
, LPDWORD lpBufferSize
,
1592 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1593 hwndOwner
, lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
,
1594 debugstr_w(lpAccessName
), lpBufferSize
, lpResult
);
1596 SetLastError(WN_NO_NETWORK
);
1597 return WN_NO_NETWORK
;
1600 /*********************************************************************
1601 * WNetCancelConnectionA [MPR.@]
1603 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
1605 FIXME( "(%s, %d), stub\n", debugstr_a(lpName
), fForce
);
1610 /*********************************************************************
1611 * WNetCancelConnectionW [MPR.@]
1613 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
1615 FIXME( "(%s, %d), stub\n", debugstr_w(lpName
), fForce
);
1620 /*********************************************************************
1621 * WNetCancelConnection2A [MPR.@]
1623 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1625 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName
), dwFlags
, fForce
);
1630 /*********************************************************************
1631 * WNetCancelConnection2W [MPR.@]
1633 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1635 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName
), dwFlags
, fForce
);
1640 /*****************************************************************
1641 * WNetRestoreConnectionA [MPR.@]
1643 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
1645 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
1647 SetLastError(WN_NO_NETWORK
);
1648 return WN_NO_NETWORK
;
1651 /*****************************************************************
1652 * WNetRestoreConnectionW [MPR.@]
1654 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
1656 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
1658 SetLastError(WN_NO_NETWORK
);
1659 return WN_NO_NETWORK
;
1662 /**************************************************************************
1663 * WNetGetConnectionA [MPR.@]
1666 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1667 * - WN_NOT_CONNECTED drive is a local drive
1668 * - WN_MORE_DATA buffer isn't big enough
1669 * - WN_SUCCESS success (net path in buffer)
1671 * FIXME: need to test return values under different errors
1673 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
1674 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
1679 ret
= WN_BAD_POINTER
;
1680 else if (!lpBufferSize
)
1681 ret
= WN_BAD_POINTER
;
1682 else if (!lpRemoteName
&& *lpBufferSize
)
1683 ret
= WN_BAD_POINTER
;
1686 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
1690 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1694 WCHAR wideRemoteStatic
[MAX_PATH
];
1695 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
1697 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
1699 /* try once without memory allocation */
1700 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
1702 if (ret
== WN_SUCCESS
)
1704 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1705 -1, NULL
, 0, NULL
, NULL
);
1707 if (len
<= *lpBufferSize
)
1709 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
1710 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1715 *lpBufferSize
= len
;
1719 else if (ret
== WN_MORE_DATA
)
1721 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
1722 wideRemoteSize
* sizeof(WCHAR
));
1726 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
1728 if (ret
== WN_SUCCESS
)
1730 if (len
<= *lpBufferSize
)
1732 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1733 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1738 *lpBufferSize
= len
;
1742 HeapFree(GetProcessHeap(), 0, wideRemote
);
1745 ret
= WN_OUT_OF_MEMORY
;
1747 HeapFree(GetProcessHeap(), 0, wideLocalName
);
1750 ret
= WN_OUT_OF_MEMORY
;
1753 ret
= WN_BAD_LOCALNAME
;
1757 TRACE("Returning %d\n", ret
);
1761 /* find the network connection for a given drive; helper for WNetGetConnection */
1762 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
1765 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
1767 DWORD ret
= WN_NOT_CONNECTED
;
1769 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
1770 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
1771 0, 0 )) == INVALID_HANDLE_VALUE
)
1773 ERR( "failed to open mount manager err %u\n", GetLastError() );
1776 memset( data
, 0, sizeof(*data
) );
1777 data
->letter
= letter
;
1778 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
1779 data
, sizeof(buffer
), NULL
, NULL
))
1781 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
1784 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
1787 mount_point
[0] = '\\';
1788 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
1790 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
1798 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
1807 /**************************************************************************
1808 * WNetGetConnectionW [MPR.@]
1810 * FIXME: need to test return values under different errors
1812 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
1813 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
1817 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
1821 ret
= WN_BAD_POINTER
;
1822 else if (!lpBufferSize
)
1823 ret
= WN_BAD_POINTER
;
1824 else if (!lpRemoteName
&& *lpBufferSize
)
1825 ret
= WN_BAD_POINTER
;
1826 else if (!lpLocalName
[0])
1827 ret
= WN_BAD_LOCALNAME
;
1830 if (lpLocalName
[1] == ':')
1832 switch(GetDriveTypeW(lpLocalName
))
1835 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
1837 case DRIVE_REMOVABLE
:
1840 TRACE("file is local\n");
1841 ret
= WN_NOT_CONNECTED
;
1844 ret
= WN_BAD_LOCALNAME
;
1848 ret
= WN_BAD_LOCALNAME
;
1852 TRACE("Returning %d\n", ret
);
1856 /**************************************************************************
1857 * WNetSetConnectionA [MPR.@]
1859 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
1862 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
1864 SetLastError(WN_NO_NETWORK
);
1865 return WN_NO_NETWORK
;
1868 /**************************************************************************
1869 * WNetSetConnectionW [MPR.@]
1871 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
1874 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
1876 SetLastError(WN_NO_NETWORK
);
1877 return WN_NO_NETWORK
;
1880 /*****************************************************************
1881 * WNetGetUniversalNameA [MPR.@]
1883 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
1884 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1888 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1889 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
1891 switch (dwInfoLevel
)
1893 case UNIVERSAL_NAME_INFO_LEVEL
:
1895 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
1897 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
1898 if (*lpBufferSize
< size
)
1903 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
1904 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
1905 *lpBufferSize
= size
;
1909 case REMOTE_NAME_INFO_LEVEL
:
1910 err
= WN_NO_NETWORK
;
1922 /*****************************************************************
1923 * WNetGetUniversalNameW [MPR.@]
1925 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
1926 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1930 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1931 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
1933 switch (dwInfoLevel
)
1935 case UNIVERSAL_NAME_INFO_LEVEL
:
1937 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
1939 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
1940 if (*lpBufferSize
< size
)
1945 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
1946 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
1947 *lpBufferSize
= size
;
1951 case REMOTE_NAME_INFO_LEVEL
:
1952 err
= WN_NO_NETWORK
;
1960 if (err
!= WN_NO_ERROR
) SetLastError(err
);
1970 /**************************************************************************
1971 * WNetGetUserA [MPR.@]
1973 * FIXME: we should not return ourselves, but the owner of the drive lpName
1975 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
1977 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
1978 return GetLastError();
1981 /*****************************************************************
1982 * WNetGetUserW [MPR.@]
1984 * FIXME: we should not return ourselves, but the owner of the drive lpName
1986 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
1988 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
1989 return GetLastError();
1992 /*********************************************************************
1993 * WNetConnectionDialog [MPR.@]
1995 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
1997 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
1999 SetLastError(WN_NO_NETWORK
);
2000 return WN_NO_NETWORK
;
2003 /*********************************************************************
2004 * WNetConnectionDialog1A [MPR.@]
2006 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2008 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2010 SetLastError(WN_NO_NETWORK
);
2011 return WN_NO_NETWORK
;
2014 /*********************************************************************
2015 * WNetConnectionDialog1W [MPR.@]
2017 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2019 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2021 SetLastError(WN_NO_NETWORK
);
2022 return WN_NO_NETWORK
;
2025 /*********************************************************************
2026 * WNetDisconnectDialog [MPR.@]
2028 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2030 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2032 SetLastError(WN_NO_NETWORK
);
2033 return WN_NO_NETWORK
;
2036 /*********************************************************************
2037 * WNetDisconnectDialog1A [MPR.@]
2039 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2041 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2043 SetLastError(WN_NO_NETWORK
);
2044 return WN_NO_NETWORK
;
2047 /*********************************************************************
2048 * WNetDisconnectDialog1W [MPR.@]
2050 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2052 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2054 SetLastError(WN_NO_NETWORK
);
2055 return WN_NO_NETWORK
;
2058 /*********************************************************************
2059 * WNetGetLastErrorA [MPR.@]
2061 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2062 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2063 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2065 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2066 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2068 SetLastError(WN_NO_NETWORK
);
2069 return WN_NO_NETWORK
;
2072 /*********************************************************************
2073 * WNetGetLastErrorW [MPR.@]
2075 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2076 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2077 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2079 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2080 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2082 SetLastError(WN_NO_NETWORK
);
2083 return WN_NO_NETWORK
;
2086 /*********************************************************************
2087 * WNetGetNetworkInformationA [MPR.@]
2089 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2090 LPNETINFOSTRUCT lpNetInfoStruct
)
2094 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2097 ret
= WN_BAD_POINTER
;
2102 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2105 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2109 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2111 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2112 HeapFree(GetProcessHeap(), 0, wideProvider
);
2115 ret
= WN_OUT_OF_MEMORY
;
2118 ret
= GetLastError();
2122 TRACE("Returning %d\n", ret
);
2126 /*********************************************************************
2127 * WNetGetNetworkInformationW [MPR.@]
2129 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2130 LPNETINFOSTRUCT lpNetInfoStruct
)
2134 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2137 ret
= WN_BAD_POINTER
;
2138 else if (!lpNetInfoStruct
)
2139 ret
= WN_BAD_POINTER
;
2140 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2144 if (providerTable
&& providerTable
->numProviders
)
2146 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2148 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2150 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2151 lpNetInfoStruct
->dwProviderVersion
=
2152 providerTable
->table
[providerIndex
].dwSpecVersion
;
2153 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2154 lpNetInfoStruct
->dwCharacteristics
= 0;
2155 lpNetInfoStruct
->dwHandle
= 0;
2156 lpNetInfoStruct
->wNetType
=
2157 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2158 lpNetInfoStruct
->dwPrinters
= -1;
2159 lpNetInfoStruct
->dwDrives
= -1;
2163 ret
= WN_BAD_PROVIDER
;
2166 ret
= WN_NO_NETWORK
;
2170 TRACE("Returning %d\n", ret
);
2174 /*****************************************************************
2175 * WNetGetProviderNameA [MPR.@]
2177 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2178 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2182 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2186 ret
= WN_BAD_POINTER
;
2187 else if (!lpBufferSize
)
2188 ret
= WN_BAD_POINTER
;
2195 ret
= WN_NO_NETWORK
;
2196 for (i
= 0; i
< providerTable
->numProviders
&&
2197 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2200 if (i
< providerTable
->numProviders
)
2202 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2203 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2205 if (*lpBufferSize
< sizeNeeded
)
2207 *lpBufferSize
= sizeNeeded
;
2212 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2213 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2215 /* FIXME: is *lpBufferSize set to the number of characters
2221 ret
= WN_NO_NETWORK
;
2225 TRACE("Returning %d\n", ret
);
2229 /*****************************************************************
2230 * WNetGetProviderNameW [MPR.@]
2232 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2233 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2237 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2241 ret
= WN_BAD_POINTER
;
2242 else if (!lpBufferSize
)
2243 ret
= WN_BAD_POINTER
;
2250 ret
= WN_NO_NETWORK
;
2251 for (i
= 0; i
< providerTable
->numProviders
&&
2252 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2255 if (i
< providerTable
->numProviders
)
2257 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2259 if (*lpBufferSize
< sizeNeeded
)
2261 *lpBufferSize
= sizeNeeded
;
2266 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2268 /* FIXME: is *lpBufferSize set to the number of characters
2274 ret
= WN_NO_NETWORK
;
2278 TRACE("Returning %d\n", ret
);