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 } WNetProvider
, *PWNetProvider
;
51 typedef struct _WNetProviderTable
56 WNetProvider table
[1];
57 } WNetProviderTable
, *PWNetProviderTable
;
59 #define WNET_ENUMERATOR_TYPE_NULL 0
60 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
61 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
62 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
64 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
65 * the enumeration; it represents one of the following types:
66 * - a 'null' enumeration, one that contains no members
67 * - a global enumeration, one that's executed across all providers
68 * - a provider-specific enumeration, one that's only executed by a single
70 * - a context enumeration. I know this contradicts what I just said about
71 * there being no correspondence between the scope and the type, but it's
72 * necessary for the special case that a "Entire Network" entry needs to
73 * be enumerated in an enumeration of the context scope. Thus an enumeration
74 * of the context scope results in a context type enumerator, which morphs
75 * into a global enumeration (so the enumeration continues across all
78 typedef struct _WNetEnumerator
88 } WNetEnumerator
, *PWNetEnumerator
;
90 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
92 /* Returns an index (into the global WNetProviderTable) of the provider with
93 * the given name, or BAD_PROVIDER_INDEX if not found.
95 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
97 static PWNetProviderTable providerTable
;
100 * Global provider table functions
103 static void _tryLoadProvider(PCWSTR provider
)
105 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
106 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
107 'S','e','r','v','i','c','e','s','\\',0 };
108 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
109 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
110 WCHAR serviceName
[MAX_PATH
];
113 TRACE("%s\n", debugstr_w(provider
));
114 snprintfW(serviceName
, sizeof(serviceName
) / sizeof(WCHAR
), serviceFmt
,
115 servicePrefix
, provider
);
116 serviceName
[sizeof(serviceName
) / sizeof(WCHAR
) - 1] = '\0';
117 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
120 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
122 WCHAR providerPath
[MAX_PATH
];
123 DWORD type
, size
= sizeof(providerPath
);
125 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
126 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
128 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
132 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
135 name
= HeapAlloc(GetProcessHeap(), 0, size
);
136 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
137 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
139 HeapFree(GetProcessHeap(), 0, name
);
145 HMODULE hLib
= LoadLibraryW(providerPath
);
149 PF_NPGetCaps getCaps
= (PF_NPGetCaps
)GetProcAddress(hLib
,
152 TRACE("loaded lib %p\n", hLib
);
155 PWNetProvider provider
=
156 &providerTable
->table
[providerTable
->numProviders
];
158 provider
->hLib
= hLib
;
159 provider
->name
= name
;
160 TRACE("name is %s\n", debugstr_w(name
));
161 provider
->getCaps
= getCaps
;
162 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
163 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
164 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
165 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
166 if (provider
->dwEnumScopes
)
168 TRACE("supports enumeration\n");
169 provider
->openEnum
= (PF_NPOpenEnum
)
170 GetProcAddress(hLib
, "NPOpenEnum");
171 TRACE("openEnum is %p\n", provider
->openEnum
);
172 provider
->enumResource
= (PF_NPEnumResource
)
173 GetProcAddress(hLib
, "NPEnumResource");
174 TRACE("enumResource is %p\n",
175 provider
->enumResource
);
176 provider
->closeEnum
= (PF_NPCloseEnum
)
177 GetProcAddress(hLib
, "NPCloseEnum");
178 TRACE("closeEnum is %p\n", provider
->closeEnum
);
179 provider
->getResourceInformation
= (PF_NPGetResourceInformation
)
180 GetProcAddress(hLib
, "NPGetResourceInformation");
181 TRACE("getResourceInformation is %p\n",
182 provider
->getResourceInformation
);
183 if (!provider
->openEnum
|| !provider
->enumResource
184 || !provider
->closeEnum
)
186 provider
->openEnum
= NULL
;
187 provider
->enumResource
= NULL
;
188 provider
->closeEnum
= NULL
;
189 provider
->dwEnumScopes
= 0;
190 WARN("Couldn't load enumeration functions\n");
193 providerTable
->numProviders
++;
197 WARN("Provider %s didn't export NPGetCaps\n",
198 debugstr_w(provider
));
199 HeapFree(GetProcessHeap(), 0, name
);
205 WARN("Couldn't load library %s for provider %s\n",
206 debugstr_w(providerPath
), debugstr_w(provider
));
207 HeapFree(GetProcessHeap(), 0, name
);
212 WARN("Couldn't get provider name for provider %s\n",
213 debugstr_w(provider
));
217 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
221 WARN("Couldn't open service key for provider %s\n",
222 debugstr_w(provider
));
225 void wnetInit(HINSTANCE hInstDll
)
227 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
228 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
229 'C','o','n','t','r','o','l','\\',
230 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
231 'O','r','d','e','r',0 };
232 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
233 'O','r','d','e','r',0 };
236 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
241 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
244 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
250 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
251 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
256 TRACE("provider order is %s\n", debugstr_w(providers
));
257 /* first count commas as a heuristic for how many to
258 * allocate space for */
259 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
261 ptr
= strchrW(ptr
, ',');
268 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
269 sizeof(WNetProviderTable
)
270 + (numToAllocate
- 1) * sizeof(WNetProvider
));
274 int entireNetworkLen
;
275 LPCWSTR stringresource
;
277 entireNetworkLen
= LoadStringW(hInstDll
,
278 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
279 providerTable
->entireNetwork
= HeapAlloc(
280 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
282 if (providerTable
->entireNetwork
)
284 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
285 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
287 providerTable
->numAllocated
= numToAllocate
;
288 for (ptr
= providers
; ptr
; )
291 ptr
= strchrW(ptr
, ',');
294 _tryLoadProvider(ptrPrev
);
298 HeapFree(GetProcessHeap(), 0, providers
);
311 for (i
= 0; i
< providerTable
->numProviders
; i
++)
313 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
314 FreeModule(providerTable
->table
[i
].hLib
);
316 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
317 HeapFree(GetProcessHeap(), 0, providerTable
);
318 providerTable
= NULL
;
322 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
324 DWORD ret
= BAD_PROVIDER_INDEX
;
326 if (providerTable
&& providerTable
->numProviders
)
330 for (i
= 0; i
< providerTable
->numProviders
&&
331 ret
== BAD_PROVIDER_INDEX
; i
++)
332 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
342 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
348 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
354 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
355 if (lpNet
->lpRemoteName
)
357 len
= strlenW(lpNet
->lpRemoteName
) + 1;
358 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
359 if (ret
->lpRemoteName
)
360 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
369 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
373 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
374 HeapFree(GetProcessHeap(), 0, lpNet
);
378 static PWNetEnumerator
_createNullEnumerator(void)
380 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
381 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
384 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
388 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
389 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
391 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
392 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
396 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
397 ret
->dwScope
= dwScope
;
398 ret
->dwType
= dwType
;
399 ret
->dwUsage
= dwUsage
;
400 ret
->lpNet
= _copyNetResourceForEnumW(lpNet
);
405 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
406 DWORD dwUsage
, DWORD index
, HANDLE handle
)
410 if (!providerTable
|| index
>= providerTable
->numProviders
)
414 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
417 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
418 ret
->providerIndex
= index
;
419 ret
->dwScope
= dwScope
;
420 ret
->dwType
= dwType
;
421 ret
->dwUsage
= dwUsage
;
422 ret
->handle
= handle
;
428 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
431 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
432 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
436 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
437 ret
->dwScope
= dwScope
;
438 ret
->dwType
= dwType
;
439 ret
->dwUsage
= dwUsage
;
444 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
445 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
446 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
447 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
448 * if not all members of the array could be thunked, and something else on
451 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
452 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
454 DWORD i
, numToThunk
, totalBytes
, ret
;
458 return WN_BAD_POINTER
;
460 return WN_BAD_POINTER
;
464 return WN_BAD_POINTER
;
466 return WN_BAD_POINTER
;
468 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
470 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
472 totalBytes
+= sizeof(NETRESOURCEA
);
473 if (lpNet
->lpLocalName
)
474 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
475 -1, NULL
, 0, NULL
, NULL
);
476 if (lpNet
->lpRemoteName
)
477 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
478 -1, NULL
, 0, NULL
, NULL
);
479 if (lpNet
->lpComment
)
480 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
481 -1, NULL
, 0, NULL
, NULL
);
482 if (lpNet
->lpProvider
)
483 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
484 -1, NULL
, 0, NULL
, NULL
);
485 if (totalBytes
< *lpBufferSize
)
488 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
489 for (i
= 0; i
< numToThunk
; i
++)
491 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
492 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
494 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
495 /* lie about string lengths, we already verified how many
496 * we have space for above
498 if (lpNetIn
->lpLocalName
)
500 lpNetOut
->lpLocalName
= strNext
;
501 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
502 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
504 if (lpNetIn
->lpRemoteName
)
506 lpNetOut
->lpRemoteName
= strNext
;
507 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
508 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
510 if (lpNetIn
->lpComment
)
512 lpNetOut
->lpComment
= strNext
;
513 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
514 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
516 if (lpNetIn
->lpProvider
)
518 lpNetOut
->lpProvider
= strNext
;
519 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
520 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
523 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
524 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
529 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
530 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
531 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
532 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
533 * if not all members of the array could be thunked, and something else on
536 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
537 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
539 DWORD i
, numToThunk
, totalBytes
, ret
;
543 return WN_BAD_POINTER
;
545 return WN_BAD_POINTER
;
549 return WN_BAD_POINTER
;
551 return WN_BAD_POINTER
;
553 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
555 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
557 totalBytes
+= sizeof(NETRESOURCEW
);
558 if (lpNet
->lpLocalName
)
559 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
560 -1, NULL
, 0) * sizeof(WCHAR
);
561 if (lpNet
->lpRemoteName
)
562 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
563 -1, NULL
, 0) * sizeof(WCHAR
);
564 if (lpNet
->lpComment
)
565 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
566 -1, NULL
, 0) * sizeof(WCHAR
);
567 if (lpNet
->lpProvider
)
568 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
569 -1, NULL
, 0) * sizeof(WCHAR
);
570 if (totalBytes
< *lpBufferSize
)
573 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
574 for (i
= 0; i
< numToThunk
; i
++)
576 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
577 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
579 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
580 /* lie about string lengths, we already verified how many
581 * we have space for above
583 if (lpNetIn
->lpLocalName
)
585 lpNetOut
->lpLocalName
= strNext
;
586 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
587 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
589 if (lpNetIn
->lpRemoteName
)
591 lpNetOut
->lpRemoteName
= strNext
;
592 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
593 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
595 if (lpNetIn
->lpComment
)
597 lpNetOut
->lpComment
= strNext
;
598 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
599 -1, lpNetOut
->lpComment
, *lpBufferSize
);
601 if (lpNetIn
->lpProvider
)
603 lpNetOut
->lpProvider
= strNext
;
604 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
605 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
608 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
609 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
614 /*********************************************************************
615 * WNetOpenEnumA [MPR.@]
617 * See comments for WNetOpenEnumW.
619 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
620 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
624 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
625 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
628 ret
= WN_BAD_POINTER
;
629 else if (!providerTable
|| providerTable
->numProviders
== 0)
638 LPNETRESOURCEW lpNetWide
= NULL
;
640 DWORD size
= sizeof(buf
), count
= 1;
641 BOOL allocated
= FALSE
;
643 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
644 if (ret
== WN_MORE_DATA
)
646 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
650 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
655 ret
= WN_OUT_OF_MEMORY
;
657 else if (ret
== WN_SUCCESS
)
658 lpNetWide
= (LPNETRESOURCEW
)buf
;
659 if (ret
== WN_SUCCESS
)
660 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
663 HeapFree(GetProcessHeap(), 0, lpNetWide
);
666 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
670 TRACE("Returning %d\n", ret
);
674 /*********************************************************************
675 * WNetOpenEnumW [MPR.@]
677 * Network enumeration has way too many parameters, so I'm not positive I got
678 * them right. What I've got so far:
680 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
681 * all the network providers should be enumerated.
683 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
684 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
685 * lpProvider is set, all the network providers should be enumerated.
686 * (This means the enumeration is a list of network providers, not that the
687 * enumeration is passed on to the providers.)
689 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
690 * resource matches the "Entire Network" resource (no remote name, no
691 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
692 * enumeration is done on every network provider.
694 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
695 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
696 * only to the given network provider.
698 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
699 * no lpProvider is set, enumeration will be tried on every network provider,
700 * in the order in which they're loaded.
702 * - The LPNETRESOURCE should be disregarded for scopes besides
703 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
704 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
706 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
707 * resource in the enumerated list, as well as any machines in your
708 * workgroup. The machines in your workgroup come from doing a
709 * RESOURCE_CONTEXT enumeration of every Network Provider.
711 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
712 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
716 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
717 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
720 ret
= WN_BAD_POINTER
;
721 else if (!providerTable
|| providerTable
->numProviders
== 0)
730 case RESOURCE_GLOBALNET
:
733 if (lpNet
->lpProvider
)
735 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
737 if (index
!= BAD_PROVIDER_INDEX
)
739 if (providerTable
->table
[index
].openEnum
&&
740 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
744 ret
= providerTable
->table
[index
].openEnum(
745 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
746 if (ret
== WN_SUCCESS
)
748 *lphEnum
= _createProviderEnumerator(
749 dwScope
, dwType
, dwUsage
, index
, handle
);
750 ret
= *lphEnum
? WN_SUCCESS
:
755 ret
= WN_NOT_SUPPORTED
;
758 ret
= WN_BAD_PROVIDER
;
760 else if (lpNet
->lpRemoteName
)
762 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
763 dwType
, dwUsage
, lpNet
);
764 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
768 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
769 providerTable
->entireNetwork
))
771 /* comment matches the "Entire Network", enumerate
772 * global scope of every provider
774 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
775 dwType
, dwUsage
, lpNet
);
779 /* this is the same as not having passed lpNet */
780 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
781 dwType
, dwUsage
, NULL
);
783 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
788 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
790 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
793 case RESOURCE_CONTEXT
:
794 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
795 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
797 case RESOURCE_REMEMBERED
:
798 case RESOURCE_CONNECTED
:
799 *lphEnum
= _createNullEnumerator();
800 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
803 WARN("unknown scope 0x%08x\n", dwScope
);
809 TRACE("Returning %d\n", ret
);
813 /*********************************************************************
814 * WNetEnumResourceA [MPR.@]
816 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
817 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
821 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
824 ret
= WN_BAD_POINTER
;
826 ret
= WN_BAD_POINTER
;
828 ret
= WN_BAD_POINTER
;
829 else if (!lpBufferSize
)
830 ret
= WN_BAD_POINTER
;
831 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
833 *lpBufferSize
= sizeof(NETRESOURCEA
);
838 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
839 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
843 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
845 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
847 /* FIXME: this isn't necessarily going to work in the case of
848 * WN_MORE_DATA, because our enumerator may have moved on to
849 * the next provider. MSDN states that a large (16KB) buffer
850 * size is the appropriate usage of this function, so
851 * hopefully it won't be an issue.
853 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
854 lpBuffer
, lpBufferSize
);
855 *lpcCount
= localCount
;
857 HeapFree(GetProcessHeap(), 0, localBuffer
);
860 ret
= WN_OUT_OF_MEMORY
;
864 TRACE("Returning %d\n", ret
);
868 static DWORD
_countProviderBytesW(PWNetProvider provider
)
874 ret
= sizeof(NETRESOURCEW
);
875 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
882 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
883 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
888 return WN_BAD_POINTER
;
889 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
892 return WN_BAD_POINTER
;
894 return WN_BAD_POINTER
;
896 return WN_BAD_POINTER
;
897 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
900 if (!providerTable
|| enumerator
->providerIndex
>=
901 providerTable
->numProviders
)
902 ret
= WN_NO_MORE_ENTRIES
;
905 DWORD bytes
= 0, count
= 0, countLimit
, i
;
906 LPNETRESOURCEW resource
;
909 countLimit
= *lpcCount
== -1 ?
910 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
911 while (count
< countLimit
&& bytes
< *lpBufferSize
)
913 DWORD bytesNext
= _countProviderBytesW(
914 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
916 if (bytes
+ bytesNext
< *lpBufferSize
)
922 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
923 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
925 resource
->dwScope
= RESOURCE_GLOBALNET
;
926 resource
->dwType
= RESOURCETYPE_ANY
;
927 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
928 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
929 RESOURCEUSAGE_RESERVED
;
930 resource
->lpLocalName
= NULL
;
931 resource
->lpRemoteName
= strNext
;
932 strcpyW(resource
->lpRemoteName
,
933 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
934 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
935 resource
->lpComment
= NULL
;
936 resource
->lpProvider
= strNext
;
937 strcpyW(resource
->lpProvider
,
938 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
939 strNext
+= strlenW(resource
->lpProvider
) + 1;
941 enumerator
->providerIndex
+= count
;
943 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
945 TRACE("Returning %d\n", ret
);
949 /* Advances the enumerator (assumed to be a global enumerator) to the next
950 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
951 * not open a handle with the next provider.
952 * If the existing handle is NULL, may leave the enumerator unchanged, since
953 * the current provider may support the desired scope.
954 * If the existing handle is not NULL, closes it before moving on.
955 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
956 * provider, and another error on failure.
958 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
961 return WN_BAD_POINTER
;
962 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
964 if (!providerTable
|| enumerator
->providerIndex
>=
965 providerTable
->numProviders
)
966 return WN_NO_MORE_ENTRIES
;
968 if (enumerator
->providerDone
)
971 enumerator
->providerDone
= FALSE
;
972 if (enumerator
->handle
)
974 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
976 enumerator
->handle
= NULL
;
977 enumerator
->providerIndex
++;
979 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
980 dwEnum
= WNNC_ENUM_LOCAL
;
981 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
982 dwEnum
= WNNC_ENUM_GLOBAL
;
983 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
984 dwEnum
= WNNC_ENUM_CONTEXT
;
985 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
986 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
987 & dwEnum
); enumerator
->providerIndex
++)
990 return enumerator
->providerIndex
< providerTable
->numProviders
?
991 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
994 /* "Passes through" call to the next provider that supports the enumeration
996 * FIXME: if one call to a provider's enumerator succeeds while there's still
997 * space in lpBuffer, I don't call to the next provider. The caller may not
998 * expect that it should call EnumResourceW again with a return value of
999 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1000 * may have to be moved around a bit, ick.
1002 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1003 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1008 return WN_BAD_POINTER
;
1009 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1010 return WN_BAD_VALUE
;
1012 return WN_BAD_POINTER
;
1014 return WN_BAD_POINTER
;
1016 return WN_BAD_POINTER
;
1017 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1018 return WN_MORE_DATA
;
1020 ret
= _globalEnumeratorAdvance(enumerator
);
1021 if (ret
== WN_SUCCESS
)
1023 ret
= providerTable
->table
[enumerator
->providerIndex
].
1024 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1025 enumerator
->dwUsage
, enumerator
->lpNet
,
1026 &enumerator
->handle
);
1027 if (ret
== WN_SUCCESS
)
1029 ret
= providerTable
->table
[enumerator
->providerIndex
].
1030 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1032 if (ret
!= WN_MORE_DATA
)
1033 enumerator
->providerDone
= TRUE
;
1036 TRACE("Returning %d\n", ret
);
1040 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1041 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1046 return WN_BAD_POINTER
;
1047 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1048 return WN_BAD_VALUE
;
1050 return WN_BAD_POINTER
;
1052 return WN_BAD_POINTER
;
1054 return WN_BAD_POINTER
;
1055 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1056 return WN_MORE_DATA
;
1058 return WN_NO_NETWORK
;
1060 switch (enumerator
->dwScope
)
1062 case RESOURCE_GLOBALNET
:
1063 if (enumerator
->lpNet
)
1064 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1065 lpBuffer
, lpBufferSize
);
1067 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1070 case RESOURCE_CONTEXT
:
1071 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1075 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1076 ret
= WN_NO_MORE_ENTRIES
;
1078 TRACE("Returning %d\n", ret
);
1082 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1083 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1086 return WN_BAD_POINTER
;
1087 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1088 return WN_BAD_VALUE
;
1089 if (!enumerator
->handle
)
1090 return WN_BAD_VALUE
;
1092 return WN_BAD_POINTER
;
1094 return WN_BAD_POINTER
;
1096 return WN_BAD_POINTER
;
1098 return WN_NO_NETWORK
;
1099 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1100 return WN_NO_MORE_ENTRIES
;
1101 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1102 return WN_BAD_VALUE
;
1103 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1104 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1107 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1108 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1111 size_t cchEntireNetworkLen
, bytesNeeded
;
1114 return WN_BAD_POINTER
;
1115 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1116 return WN_BAD_VALUE
;
1118 return WN_BAD_POINTER
;
1120 return WN_BAD_POINTER
;
1122 return WN_BAD_POINTER
;
1124 return WN_NO_NETWORK
;
1126 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1127 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1128 if (*lpBufferSize
< bytesNeeded
)
1130 *lpBufferSize
= bytesNeeded
;
1135 LPNETRESOURCEW lpNet
= lpBuffer
;
1137 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1138 lpNet
->dwType
= enumerator
->dwType
;
1139 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1140 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1141 lpNet
->lpLocalName
= NULL
;
1142 lpNet
->lpRemoteName
= NULL
;
1143 lpNet
->lpProvider
= NULL
;
1144 /* odd, but correct: put comment at end of buffer, so it won't get
1145 * overwritten by subsequent calls to a provider's enumResource
1147 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1148 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1149 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1152 if (ret
== WN_SUCCESS
)
1154 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1156 /* "Entire Network" entry enumerated--morph this into a global
1157 * enumerator. enumerator->lpNet continues to be NULL, since it has
1158 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1160 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1161 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1162 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1163 if (ret
== WN_SUCCESS
)
1165 /* reflect the fact that we already enumerated "Entire Network" */
1167 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1171 /* the provider enumeration failed, but we already succeeded in
1172 * enumerating "Entire Network"--leave type as global to allow a
1173 * retry, but indicate success with a count of one.
1177 *lpBufferSize
= bytesNeeded
;
1180 TRACE("Returning %d\n", ret
);
1184 /*********************************************************************
1185 * WNetEnumResourceW [MPR.@]
1187 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1188 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1192 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1195 ret
= WN_BAD_POINTER
;
1197 ret
= WN_BAD_POINTER
;
1199 ret
= WN_BAD_POINTER
;
1200 else if (!lpBufferSize
)
1201 ret
= WN_BAD_POINTER
;
1202 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1204 *lpBufferSize
= sizeof(NETRESOURCEW
);
1209 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1211 switch (enumerator
->enumType
)
1213 case WNET_ENUMERATOR_TYPE_NULL
:
1214 ret
= WN_NO_MORE_ENTRIES
;
1216 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1217 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1220 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1221 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1224 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1225 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1229 WARN("bogus enumerator type!\n");
1230 ret
= WN_NO_NETWORK
;
1235 TRACE("Returning %d\n", ret
);
1239 /*********************************************************************
1240 * WNetCloseEnum [MPR.@]
1242 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1246 TRACE( "(%p)\n", hEnum
);
1250 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1252 switch (enumerator
->enumType
)
1254 case WNET_ENUMERATOR_TYPE_NULL
:
1257 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1258 if (enumerator
->lpNet
)
1259 _freeEnumNetResource(enumerator
->lpNet
);
1260 if (enumerator
->handle
)
1261 providerTable
->table
[enumerator
->providerIndex
].
1262 closeEnum(enumerator
->handle
);
1265 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1266 if (enumerator
->handle
)
1267 providerTable
->table
[enumerator
->providerIndex
].
1268 closeEnum(enumerator
->handle
);
1272 WARN("bogus enumerator type!\n");
1273 ret
= WN_BAD_HANDLE
;
1275 HeapFree(GetProcessHeap(), 0, hEnum
);
1278 ret
= WN_BAD_HANDLE
;
1281 TRACE("Returning %d\n", ret
);
1285 /*********************************************************************
1286 * WNetGetResourceInformationA [MPR.@]
1288 * See WNetGetResourceInformationW
1290 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1291 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1296 TRACE( "(%p, %p, %p, %p)\n",
1297 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1299 if (!providerTable
|| providerTable
->numProviders
== 0)
1300 ret
= WN_NO_NETWORK
;
1301 else if (lpNetResource
)
1303 LPNETRESOURCEW lpNetResourceW
= NULL
;
1304 DWORD size
= 1024, count
= 1;
1307 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1308 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1309 if (ret
== WN_MORE_DATA
)
1311 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1312 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1314 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1315 &count
, lpNetResourceW
, &size
);
1317 ret
= WN_OUT_OF_MEMORY
;
1319 if (ret
== WN_SUCCESS
)
1321 LPWSTR lpSystemW
= NULL
;
1324 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1327 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1328 lpBufferW
, &size
, &lpSystemW
);
1329 if (ret
== WN_MORE_DATA
)
1331 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1332 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1334 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1335 lpBufferW
, &size
, &lpSystemW
);
1337 ret
= WN_OUT_OF_MEMORY
;
1339 if (ret
== WN_SUCCESS
)
1341 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1342 &count
, lpBuffer
, cbBuffer
);
1343 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1344 lpNetResourceW
= lpBufferW
;
1345 size
= sizeof(NETRESOURCEA
);
1346 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1347 -1, NULL
, 0, NULL
, NULL
);
1348 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1349 -1, NULL
, 0, NULL
, NULL
);
1351 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1352 -1, NULL
, 0, NULL
, NULL
);
1353 if ((len
) && ( size
+ len
< *cbBuffer
))
1355 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1356 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1357 *lplpSystem
, len
, NULL
, NULL
);
1364 ret
= WN_OUT_OF_MEMORY
;
1365 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1368 ret
= WN_OUT_OF_MEMORY
;
1369 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1371 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1374 ret
= WN_NO_NETWORK
;
1378 TRACE("Returning %d\n", ret
);
1382 /*********************************************************************
1383 * WNetGetResourceInformationW [MPR.@]
1385 * WNetGetResourceInformationW function identifies the network provider
1386 * that owns the resource and gets information about the type of the resource.
1389 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1390 * defines a network resource.
1391 * lpBuffer [ O] the pointer to buffer, containing result. It
1392 * contains NETRESOURCEW structure and strings to
1393 * which the members of the NETRESOURCEW structure
1395 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1397 * lplpSystem [ O] the pointer to string in the output buffer,
1398 * containing the part of the resource name without
1399 * names of the server and share.
1402 * NO_ERROR if the function succeeds. System error code if the function fails.
1405 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1406 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1407 LPWSTR
*lplpSystem
)
1409 DWORD ret
= WN_NO_NETWORK
;
1412 TRACE( "(%p, %p, %p, %p)\n",
1413 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1416 ret
= WN_OUT_OF_MEMORY
;
1417 else if (providerTable
!= NULL
)
1419 /* FIXME: For function value of a variable is indifferent, it does
1420 * search of all providers in a network.
1422 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1424 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1425 WNNC_DLG_GETRESOURCEINFORMATION
)
1427 if (providerTable
->table
[index
].getResourceInformation
)
1428 ret
= providerTable
->table
[index
].getResourceInformation(
1429 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1431 ret
= WN_NO_NETWORK
;
1432 if (ret
== WN_SUCCESS
)
1442 /*********************************************************************
1443 * WNetGetResourceParentA [MPR.@]
1445 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1446 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1448 FIXME( "(%p, %p, %p): stub\n",
1449 lpNetResource
, lpBuffer
, lpBufferSize
);
1451 SetLastError(WN_NO_NETWORK
);
1452 return WN_NO_NETWORK
;
1455 /*********************************************************************
1456 * WNetGetResourceParentW [MPR.@]
1458 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1459 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1461 FIXME( "(%p, %p, %p): stub\n",
1462 lpNetResource
, lpBuffer
, lpBufferSize
);
1464 SetLastError(WN_NO_NETWORK
);
1465 return WN_NO_NETWORK
;
1471 * Connection Functions
1474 /*********************************************************************
1475 * WNetAddConnectionA [MPR.@]
1477 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1478 LPCSTR lpLocalName
)
1480 FIXME( "(%s, %p, %s): stub\n",
1481 debugstr_a(lpRemoteName
), lpPassword
, debugstr_a(lpLocalName
) );
1483 SetLastError(WN_NO_NETWORK
);
1484 return WN_NO_NETWORK
;
1487 /*********************************************************************
1488 * WNetAddConnectionW [MPR.@]
1490 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1491 LPCWSTR lpLocalName
)
1493 FIXME( "(%s, %p, %s): stub\n",
1494 debugstr_w(lpRemoteName
), lpPassword
, debugstr_w(lpLocalName
) );
1496 SetLastError(WN_NO_NETWORK
);
1497 return WN_NO_NETWORK
;
1500 /*********************************************************************
1501 * WNetAddConnection2A [MPR.@]
1503 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1504 LPCSTR lpPassword
, LPCSTR lpUserID
,
1507 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1508 lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
);
1510 SetLastError(WN_NO_NETWORK
);
1511 return WN_NO_NETWORK
;
1514 /*********************************************************************
1515 * WNetAddConnection2W [MPR.@]
1517 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1518 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1521 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1522 lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
);
1524 SetLastError(WN_NO_NETWORK
);
1525 return WN_NO_NETWORK
;
1528 /*********************************************************************
1529 * WNetAddConnection3A [MPR.@]
1531 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1532 LPCSTR lpPassword
, LPCSTR lpUserID
,
1535 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1536 hwndOwner
, lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
);
1538 SetLastError(WN_NO_NETWORK
);
1539 return WN_NO_NETWORK
;
1542 /*********************************************************************
1543 * WNetAddConnection3W [MPR.@]
1545 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1546 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1549 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1550 hwndOwner
, lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
);
1552 SetLastError(WN_NO_NETWORK
);
1553 return WN_NO_NETWORK
;
1556 /*****************************************************************
1557 * WNetUseConnectionA [MPR.@]
1559 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1560 LPCSTR lpPassword
, LPCSTR lpUserID
, DWORD dwFlags
,
1561 LPSTR lpAccessName
, LPDWORD lpBufferSize
,
1564 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1565 hwndOwner
, lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
,
1566 debugstr_a(lpAccessName
), lpBufferSize
, lpResult
);
1568 SetLastError(WN_NO_NETWORK
);
1569 return WN_NO_NETWORK
;
1572 /*****************************************************************
1573 * WNetUseConnectionW [MPR.@]
1575 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1576 LPCWSTR lpPassword
, LPCWSTR lpUserID
, DWORD dwFlags
,
1577 LPWSTR lpAccessName
, LPDWORD lpBufferSize
,
1580 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1581 hwndOwner
, lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
,
1582 debugstr_w(lpAccessName
), lpBufferSize
, lpResult
);
1584 SetLastError(WN_NO_NETWORK
);
1585 return WN_NO_NETWORK
;
1588 /*********************************************************************
1589 * WNetCancelConnectionA [MPR.@]
1591 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
1593 FIXME( "(%s, %d), stub\n", debugstr_a(lpName
), fForce
);
1598 /*********************************************************************
1599 * WNetCancelConnectionW [MPR.@]
1601 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
1603 FIXME( "(%s, %d), stub\n", debugstr_w(lpName
), fForce
);
1608 /*********************************************************************
1609 * WNetCancelConnection2A [MPR.@]
1611 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1613 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName
), dwFlags
, fForce
);
1618 /*********************************************************************
1619 * WNetCancelConnection2W [MPR.@]
1621 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1623 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName
), dwFlags
, fForce
);
1628 /*****************************************************************
1629 * WNetRestoreConnectionA [MPR.@]
1631 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
1633 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
1635 SetLastError(WN_NO_NETWORK
);
1636 return WN_NO_NETWORK
;
1639 /*****************************************************************
1640 * WNetRestoreConnectionW [MPR.@]
1642 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
1644 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
1646 SetLastError(WN_NO_NETWORK
);
1647 return WN_NO_NETWORK
;
1650 /**************************************************************************
1651 * WNetGetConnectionA [MPR.@]
1654 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1655 * - WN_NOT_CONNECTED drive is a local drive
1656 * - WN_MORE_DATA buffer isn't big enough
1657 * - WN_SUCCESS success (net path in buffer)
1659 * FIXME: need to test return values under different errors
1661 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
1662 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
1667 ret
= WN_BAD_POINTER
;
1668 else if (!lpBufferSize
)
1669 ret
= WN_BAD_POINTER
;
1670 else if (!lpRemoteName
&& *lpBufferSize
)
1671 ret
= WN_BAD_POINTER
;
1674 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
1678 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1682 WCHAR wideRemoteStatic
[MAX_PATH
];
1683 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
1685 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
1687 /* try once without memory allocation */
1688 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
1690 if (ret
== WN_SUCCESS
)
1692 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1693 -1, NULL
, 0, NULL
, NULL
);
1695 if (len
<= *lpBufferSize
)
1697 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
1698 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1703 *lpBufferSize
= len
;
1707 else if (ret
== WN_MORE_DATA
)
1709 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
1710 wideRemoteSize
* sizeof(WCHAR
));
1714 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
1716 if (ret
== WN_SUCCESS
)
1718 if (len
<= *lpBufferSize
)
1720 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1721 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1726 *lpBufferSize
= len
;
1730 HeapFree(GetProcessHeap(), 0, wideRemote
);
1733 ret
= WN_OUT_OF_MEMORY
;
1735 HeapFree(GetProcessHeap(), 0, wideLocalName
);
1738 ret
= WN_OUT_OF_MEMORY
;
1741 ret
= WN_BAD_LOCALNAME
;
1745 TRACE("Returning %d\n", ret
);
1749 /* find the network connection for a given drive; helper for WNetGetConnection */
1750 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
1753 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
1755 DWORD ret
= WN_NOT_CONNECTED
;
1756 DWORD bytes_returned
;
1758 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
1759 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
1760 0, 0 )) == INVALID_HANDLE_VALUE
)
1762 ERR( "failed to open mount manager err %u\n", GetLastError() );
1765 memset( data
, 0, sizeof(*data
) );
1766 data
->letter
= letter
;
1767 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
1768 data
, sizeof(buffer
), &bytes_returned
, NULL
))
1770 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
1773 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
1776 mount_point
[0] = '\\';
1777 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
1779 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
1787 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
1796 /**************************************************************************
1797 * WNetGetConnectionW [MPR.@]
1799 * FIXME: need to test return values under different errors
1801 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
1802 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
1806 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
1810 ret
= WN_BAD_POINTER
;
1811 else if (!lpBufferSize
)
1812 ret
= WN_BAD_POINTER
;
1813 else if (!lpRemoteName
&& *lpBufferSize
)
1814 ret
= WN_BAD_POINTER
;
1815 else if (!lpLocalName
[0])
1816 ret
= WN_BAD_LOCALNAME
;
1819 if (lpLocalName
[1] == ':')
1821 switch(GetDriveTypeW(lpLocalName
))
1824 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
1826 case DRIVE_REMOVABLE
:
1829 TRACE("file is local\n");
1830 ret
= WN_NOT_CONNECTED
;
1833 ret
= WN_BAD_LOCALNAME
;
1837 ret
= WN_BAD_LOCALNAME
;
1841 TRACE("Returning %d\n", ret
);
1845 /**************************************************************************
1846 * WNetSetConnectionA [MPR.@]
1848 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
1851 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
1853 SetLastError(WN_NO_NETWORK
);
1854 return WN_NO_NETWORK
;
1857 /**************************************************************************
1858 * WNetSetConnectionW [MPR.@]
1860 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
1863 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
1865 SetLastError(WN_NO_NETWORK
);
1866 return WN_NO_NETWORK
;
1869 /*****************************************************************
1870 * WNetGetUniversalNameA [MPR.@]
1872 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
1873 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1877 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1878 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
1880 switch (dwInfoLevel
)
1882 case UNIVERSAL_NAME_INFO_LEVEL
:
1884 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
1886 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
1888 err
= ERROR_NOT_CONNECTED
;
1892 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
1893 if (*lpBufferSize
< size
)
1898 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
1899 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
1903 case REMOTE_NAME_INFO_LEVEL
:
1904 err
= WN_NO_NETWORK
;
1916 /*****************************************************************
1917 * WNetGetUniversalNameW [MPR.@]
1919 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
1920 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1924 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1925 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
1927 switch (dwInfoLevel
)
1929 case UNIVERSAL_NAME_INFO_LEVEL
:
1931 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
1933 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
1935 err
= ERROR_NOT_CONNECTED
;
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
);
1950 case REMOTE_NAME_INFO_LEVEL
:
1951 err
= WN_NO_NETWORK
;
1959 if (err
!= WN_NO_ERROR
) SetLastError(err
);
1969 /**************************************************************************
1970 * WNetGetUserA [MPR.@]
1972 * FIXME: we should not return ourselves, but the owner of the drive lpName
1974 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
1976 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
1977 return GetLastError();
1980 /*****************************************************************
1981 * WNetGetUserW [MPR.@]
1983 * FIXME: we should not return ourselves, but the owner of the drive lpName
1985 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
1987 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
1988 return GetLastError();
1991 /*********************************************************************
1992 * WNetConnectionDialog [MPR.@]
1994 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
1996 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
1998 SetLastError(WN_NO_NETWORK
);
1999 return WN_NO_NETWORK
;
2002 /*********************************************************************
2003 * WNetConnectionDialog1A [MPR.@]
2005 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2007 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2009 SetLastError(WN_NO_NETWORK
);
2010 return WN_NO_NETWORK
;
2013 /*********************************************************************
2014 * WNetConnectionDialog1W [MPR.@]
2016 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2018 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2020 SetLastError(WN_NO_NETWORK
);
2021 return WN_NO_NETWORK
;
2024 /*********************************************************************
2025 * WNetDisconnectDialog [MPR.@]
2027 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2029 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2031 SetLastError(WN_NO_NETWORK
);
2032 return WN_NO_NETWORK
;
2035 /*********************************************************************
2036 * WNetDisconnectDialog1A [MPR.@]
2038 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2040 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2042 SetLastError(WN_NO_NETWORK
);
2043 return WN_NO_NETWORK
;
2046 /*********************************************************************
2047 * WNetDisconnectDialog1W [MPR.@]
2049 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2051 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2053 SetLastError(WN_NO_NETWORK
);
2054 return WN_NO_NETWORK
;
2057 /*********************************************************************
2058 * WNetGetLastErrorA [MPR.@]
2060 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2061 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2062 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2064 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2065 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2067 SetLastError(WN_NO_NETWORK
);
2068 return WN_NO_NETWORK
;
2071 /*********************************************************************
2072 * WNetGetLastErrorW [MPR.@]
2074 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2075 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2076 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2078 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2079 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2081 SetLastError(WN_NO_NETWORK
);
2082 return WN_NO_NETWORK
;
2085 /*********************************************************************
2086 * WNetGetNetworkInformationA [MPR.@]
2088 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2089 LPNETINFOSTRUCT lpNetInfoStruct
)
2093 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2096 ret
= WN_BAD_POINTER
;
2101 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2104 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2108 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2110 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2111 HeapFree(GetProcessHeap(), 0, wideProvider
);
2114 ret
= WN_OUT_OF_MEMORY
;
2117 ret
= GetLastError();
2121 TRACE("Returning %d\n", ret
);
2125 /*********************************************************************
2126 * WNetGetNetworkInformationW [MPR.@]
2128 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2129 LPNETINFOSTRUCT lpNetInfoStruct
)
2133 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2136 ret
= WN_BAD_POINTER
;
2137 else if (!lpNetInfoStruct
)
2138 ret
= WN_BAD_POINTER
;
2139 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2143 if (providerTable
&& providerTable
->numProviders
)
2145 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2147 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2149 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2150 lpNetInfoStruct
->dwProviderVersion
=
2151 providerTable
->table
[providerIndex
].dwSpecVersion
;
2152 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2153 lpNetInfoStruct
->dwCharacteristics
= 0;
2154 lpNetInfoStruct
->dwHandle
= 0;
2155 lpNetInfoStruct
->wNetType
=
2156 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2157 lpNetInfoStruct
->dwPrinters
= -1;
2158 lpNetInfoStruct
->dwDrives
= -1;
2162 ret
= WN_BAD_PROVIDER
;
2165 ret
= WN_NO_NETWORK
;
2169 TRACE("Returning %d\n", ret
);
2173 /*****************************************************************
2174 * WNetGetProviderNameA [MPR.@]
2176 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2177 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2181 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2185 ret
= WN_BAD_POINTER
;
2186 else if (!lpBufferSize
)
2187 ret
= WN_BAD_POINTER
;
2194 ret
= WN_NO_NETWORK
;
2195 for (i
= 0; i
< providerTable
->numProviders
&&
2196 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2199 if (i
< providerTable
->numProviders
)
2201 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2202 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2204 if (*lpBufferSize
< sizeNeeded
)
2206 *lpBufferSize
= sizeNeeded
;
2211 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2212 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2214 /* FIXME: is *lpBufferSize set to the number of characters
2220 ret
= WN_NO_NETWORK
;
2224 TRACE("Returning %d\n", ret
);
2228 /*****************************************************************
2229 * WNetGetProviderNameW [MPR.@]
2231 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2232 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2236 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2240 ret
= WN_BAD_POINTER
;
2241 else if (!lpBufferSize
)
2242 ret
= WN_BAD_POINTER
;
2249 ret
= WN_NO_NETWORK
;
2250 for (i
= 0; i
< providerTable
->numProviders
&&
2251 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2254 if (i
< providerTable
->numProviders
)
2256 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2258 if (*lpBufferSize
< sizeNeeded
)
2260 *lpBufferSize
= sizeNeeded
;
2265 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2267 /* FIXME: is *lpBufferSize set to the number of characters
2273 ret
= WN_NO_NETWORK
;
2277 TRACE("Returning %d\n", ret
);