4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(mpr
);
37 /* Data structures representing network service providers. Assumes only one
38 * thread creates them, and that they are constant for the life of the process
39 * (and therefore doesn't synchronize access).
40 * FIXME: only basic provider data and enumeration-related data are implemented
41 * so far, need to implement the rest too.
43 typedef struct _WNetProvider
51 PF_NPOpenEnum openEnum
;
52 PF_NPEnumResource enumResource
;
53 PF_NPCloseEnum closeEnum
;
54 } WNetProvider
, *PWNetProvider
;
56 typedef struct _WNetProviderTable
61 WNetProvider table
[1];
62 } WNetProviderTable
, *PWNetProviderTable
;
64 #define WNET_ENUMERATOR_TYPE_NULL 0
65 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
66 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
67 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
69 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
70 * the enumeration; it represents one of the following types:
71 * - a 'null' enumeration, one that contains no members
72 * - a global enumeration, one that's executed across all providers
73 * - a provider-specific enumeration, one that's only executed by a single
75 * - a context enumeration. I know this contradicts what I just said about
76 * there being no correspondence between the scope and the type, but it's
77 * necessary for the special case that a "Entire Network" entry needs to
78 * be enumerated in an enumeration of the context scope. Thus an enumeration
79 * of the context scope results in a context type enumerator, which morphs
80 * into a global enumeration (so the enumeration continues across all
83 typedef struct _WNetEnumerator
93 } WNetEnumerator
, *PWNetEnumerator
;
95 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
97 /* Returns an index (into the global WNetProviderTable) of the provider with
98 * the given name, or BAD_PROVIDER_INDEX if not found.
100 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
102 PWNetProviderTable providerTable
;
105 * Global provider table functions
108 static void _tryLoadProvider(PCWSTR provider
)
110 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
111 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
112 'S','e','r','v','i','c','e','s','\\',0 };
113 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
114 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
115 WCHAR serviceName
[MAX_PATH
];
118 TRACE("%s\n", debugstr_w(provider
));
119 snprintfW(serviceName
, sizeof(serviceName
) / sizeof(WCHAR
), serviceFmt
,
120 servicePrefix
, provider
);
121 serviceName
[sizeof(serviceName
) / sizeof(WCHAR
) - 1] = '\0';
122 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
125 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
127 WCHAR providerPath
[MAX_PATH
];
128 DWORD type
, size
= sizeof(providerPath
);
130 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
131 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
133 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
137 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
140 name
= HeapAlloc(GetProcessHeap(), 0, size
);
141 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
142 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
144 HeapFree(GetProcessHeap(), 0, name
);
150 HMODULE hLib
= LoadLibraryW(providerPath
);
154 PF_NPGetCaps getCaps
= (PF_NPGetCaps
)GetProcAddress(hLib
,
157 TRACE("loaded lib %p\n", hLib
);
160 PWNetProvider provider
=
161 &providerTable
->table
[providerTable
->numProviders
];
163 provider
->hLib
= hLib
;
164 provider
->name
= name
;
165 TRACE("name is %s\n", debugstr_w(name
));
166 provider
->getCaps
= getCaps
;
167 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
168 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
169 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
170 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
171 if (provider
->dwEnumScopes
)
173 TRACE("supports enumeration\n");
174 provider
->openEnum
= (PF_NPOpenEnum
)
175 GetProcAddress(hLib
, "NPOpenEnum");
176 TRACE("openEnum is %p\n", provider
->openEnum
);
177 provider
->enumResource
= (PF_NPEnumResource
)
178 GetProcAddress(hLib
, "NPEnumResource");
179 TRACE("enumResource is %p\n",
180 provider
->enumResource
);
181 provider
->closeEnum
= (PF_NPCloseEnum
)
182 GetProcAddress(hLib
, "NPCloseEnum");
183 TRACE("closeEnum is %p\n", provider
->closeEnum
);
184 if (!provider
->openEnum
|| !provider
->enumResource
185 || !provider
->closeEnum
)
187 provider
->openEnum
= NULL
;
188 provider
->enumResource
= NULL
;
189 provider
->closeEnum
= NULL
;
190 provider
->dwEnumScopes
= 0;
191 WARN("Couldn't load enumeration functions\n");
194 providerTable
->numProviders
++;
198 WARN("Provider %s didn't export NPGetCaps\n",
199 debugstr_w(provider
));
200 HeapFree(GetProcessHeap(), 0, name
);
206 WARN("Couldn't load library %s for provider %s\n",
207 debugstr_w(providerPath
), debugstr_w(provider
));
208 HeapFree(GetProcessHeap(), 0, name
);
213 WARN("Couldn't get provider name for provider %s\n",
214 debugstr_w(provider
));
218 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
222 WARN("Couldn't open service key for provider %s\n",
223 debugstr_w(provider
));
226 void wnetInit(HINSTANCE hInstDll
)
228 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
229 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
230 'C','o','n','t','r','o','l','\\',
231 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
232 'O','r','d','e','r',0 };
233 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
234 'O','r','d','e','r',0 };
237 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
242 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
245 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
251 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
252 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
257 TRACE("provider order is %s\n", debugstr_w(providers
));
258 /* first count commas as a heuristic for how many to
259 * allocate space for */
260 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
262 ptr
= strchrW(ptr
, ',');
269 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
270 sizeof(WNetProviderTable
)
271 + (numToAllocate
- 1) * sizeof(WNetProvider
));
275 int entireNetworkLen
;
277 entireNetworkLen
= LoadStringW(hInstDll
,
278 IDS_ENTIRENETWORK
, NULL
, 0);
279 providerTable
->entireNetwork
= HeapAlloc(
280 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
282 if (providerTable
->entireNetwork
)
283 LoadStringW(hInstDll
, IDS_ENTIRENETWORK
,
284 providerTable
->entireNetwork
,
285 entireNetworkLen
+ 1);
286 providerTable
->numAllocated
= numToAllocate
;
287 for (ptr
= providers
; ptr
; )
290 ptr
= strchrW(ptr
, ',');
293 _tryLoadProvider(ptrPrev
);
297 HeapFree(GetProcessHeap(), 0, providers
);
310 for (i
= 0; i
< providerTable
->numProviders
; i
++)
312 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
313 FreeModule(providerTable
->table
[i
].hLib
);
315 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
316 HeapFree(GetProcessHeap(), 0, providerTable
);
317 providerTable
= NULL
;
321 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
323 DWORD ret
= BAD_PROVIDER_INDEX
;
325 if (providerTable
&& providerTable
->numProviders
)
329 for (i
= 0; i
< providerTable
->numProviders
&&
330 ret
== BAD_PROVIDER_INDEX
; i
++)
331 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
341 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
347 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
352 memcpy(ret
, lpNet
, sizeof(ret
));
353 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
354 if (lpNet
->lpRemoteName
)
356 len
= strlenW(lpNet
->lpRemoteName
) + 1;
357 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
358 if (ret
->lpRemoteName
)
359 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
368 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
372 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
373 HeapFree(GetProcessHeap(), 0, lpNet
);
377 static PWNetEnumerator
_createNullEnumerator(void)
379 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
380 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
383 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
387 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
388 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
390 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
391 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
395 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
396 ret
->dwScope
= dwScope
;
397 ret
->dwType
= dwType
;
398 ret
->dwUsage
= dwUsage
;
399 ret
->lpNet
= _copyNetResourceForEnumW(lpNet
);
404 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
405 DWORD dwUsage
, DWORD index
, HANDLE handle
)
409 if (!providerTable
|| index
>= providerTable
->numProviders
)
413 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
416 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
417 ret
->providerIndex
= index
;
418 ret
->dwScope
= dwScope
;
419 ret
->dwType
= dwType
;
420 ret
->dwUsage
= dwUsage
;
421 ret
->handle
= handle
;
427 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
430 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
431 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
435 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
436 ret
->dwScope
= dwScope
;
437 ret
->dwType
= dwType
;
438 ret
->dwUsage
= dwUsage
;
443 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
444 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
445 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
446 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
447 * if not all members of the array could be thunked, and something else on
450 static DWORD
_thunkNetResourceArrayWToA(const LPNETRESOURCEW lpNetArrayIn
,
451 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
453 DWORD i
, numToThunk
, totalBytes
, ret
;
457 return WN_BAD_POINTER
;
459 return WN_BAD_POINTER
;
463 return WN_BAD_POINTER
;
465 return WN_BAD_POINTER
;
467 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
469 LPNETRESOURCEW lpNet
= lpNetArrayIn
+ i
;
471 totalBytes
+= sizeof(NETRESOURCEA
);
472 if (lpNet
->lpLocalName
)
473 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
474 -1, NULL
, 0, NULL
, NULL
);
475 if (lpNet
->lpRemoteName
)
476 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
477 -1, NULL
, 0, NULL
, NULL
);
478 if (lpNet
->lpComment
)
479 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
480 -1, NULL
, 0, NULL
, NULL
);
481 if (lpNet
->lpProvider
)
482 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
483 -1, NULL
, 0, NULL
, NULL
);
484 if (totalBytes
< *lpBufferSize
)
487 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
488 for (i
= 0; i
< numToThunk
; i
++)
490 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
491 LPNETRESOURCEW lpNetIn
= lpNetArrayIn
+ i
;
493 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
494 /* lie about string lengths, we already verified how many
495 * we have space for above
497 if (lpNetIn
->lpLocalName
)
499 lpNetOut
->lpLocalName
= strNext
;
500 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
501 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
503 if (lpNetIn
->lpRemoteName
)
505 lpNetOut
->lpRemoteName
= strNext
;
506 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
507 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
509 if (lpNetIn
->lpComment
)
511 lpNetOut
->lpComment
= strNext
;
512 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
513 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
515 if (lpNetIn
->lpProvider
)
517 lpNetOut
->lpProvider
= strNext
;
518 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
519 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
522 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
523 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
528 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
529 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
530 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
531 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
532 * if not all members of the array could be thunked, and something else on
535 static DWORD
_thunkNetResourceArrayAToW(const LPNETRESOURCEA lpNetArrayIn
,
536 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
538 DWORD i
, numToThunk
, totalBytes
, ret
;
542 return WN_BAD_POINTER
;
544 return WN_BAD_POINTER
;
548 return WN_BAD_POINTER
;
550 return WN_BAD_POINTER
;
552 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
554 LPNETRESOURCEA lpNet
= lpNetArrayIn
+ i
;
556 totalBytes
+= sizeof(NETRESOURCEW
);
557 if (lpNet
->lpLocalName
)
558 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
559 -1, NULL
, 0) * sizeof(WCHAR
);
560 if (lpNet
->lpRemoteName
)
561 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
562 -1, NULL
, 0) * sizeof(WCHAR
);
563 if (lpNet
->lpComment
)
564 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
565 -1, NULL
, 0) * sizeof(WCHAR
);
566 if (lpNet
->lpProvider
)
567 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
568 -1, NULL
, 0) * sizeof(WCHAR
);
569 if (totalBytes
< *lpBufferSize
)
572 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
573 for (i
= 0; i
< numToThunk
; i
++)
575 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
576 LPNETRESOURCEA lpNetIn
= lpNetArrayIn
+ i
;
578 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
579 /* lie about string lengths, we already verified how many
580 * we have space for above
582 if (lpNetIn
->lpLocalName
)
584 lpNetOut
->lpLocalName
= strNext
;
585 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
586 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
588 if (lpNetIn
->lpRemoteName
)
590 lpNetOut
->lpRemoteName
= strNext
;
591 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
592 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
594 if (lpNetIn
->lpComment
)
596 lpNetOut
->lpComment
= strNext
;
597 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
598 -1, lpNetOut
->lpComment
, *lpBufferSize
);
600 if (lpNetIn
->lpProvider
)
602 lpNetOut
->lpProvider
= strNext
;
603 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
604 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
607 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
608 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
613 /*********************************************************************
614 * WNetOpenEnumA [MPR.@]
616 * See comments for WNetOpenEnumW.
618 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
619 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
623 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
624 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
627 ret
= WN_BAD_POINTER
;
628 else if (!providerTable
|| providerTable
->numProviders
== 0)
634 LPNETRESOURCEW lpNetWide
= NULL
;
636 DWORD size
= sizeof(buf
), count
= 1;
637 BOOL allocated
= FALSE
;
639 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
640 if (ret
== WN_MORE_DATA
)
642 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
646 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
651 ret
= WN_OUT_OF_MEMORY
;
653 else if (ret
== WN_SUCCESS
)
654 lpNetWide
= (LPNETRESOURCEW
)buf
;
655 if (ret
== WN_SUCCESS
)
656 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
659 HeapFree(GetProcessHeap(), 0, lpNetWide
);
662 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
666 TRACE("Returning %d\n", ret
);
670 /*********************************************************************
671 * WNetOpenEnumW [MPR.@]
673 * Network enumeration has way too many parameters, so I'm not positive I got
674 * them right. What I've got so far:
676 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
677 * all the network providers should be enumerated.
679 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
680 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
681 * lpProvider is set, all the network providers should be enumerated.
682 * (This means the enumeration is a list of network providers, not that the
683 * enumeration is passed on to the providers.)
685 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
686 * resource matches the "Entire Network" resource (no remote name, no
687 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
688 * enumeration is done on every network provider.
690 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
691 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
692 * only to the given network provider.
694 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
695 * no lpProvider is set, enumeration will be tried on every network provider,
696 * in the order in which they're loaded.
698 * - The LPNETRESOURCE should be disregarded for scopes besides
699 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
700 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
702 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
703 * resource in the enumerated list, as well as any machines in your
704 * workgroup. The machines in your workgroup come from doing a
705 * RESOURCE_CONTEXT enumeration of every Network Provider.
707 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
708 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
712 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
713 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
716 ret
= WN_BAD_POINTER
;
717 else if (!providerTable
|| providerTable
->numProviders
== 0)
723 case RESOURCE_GLOBALNET
:
726 if (lpNet
->lpProvider
)
728 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
730 if (index
!= BAD_PROVIDER_INDEX
)
732 if (providerTable
->table
[index
].openEnum
&&
733 providerTable
->table
[index
].dwEnumScopes
& dwScope
)
737 ret
= providerTable
->table
[index
].openEnum(
738 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
739 if (ret
== WN_SUCCESS
)
742 (HANDLE
)_createProviderEnumerator(
743 dwScope
, dwType
, dwUsage
, index
, handle
);
744 ret
= *lphEnum
? WN_SUCCESS
:
749 ret
= WN_NOT_SUPPORTED
;
752 ret
= WN_BAD_PROVIDER
;
754 else if (lpNet
->lpRemoteName
)
756 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
,
757 dwType
, dwUsage
, lpNet
);
758 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
762 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
763 providerTable
->entireNetwork
))
765 /* comment matches the "Entire Network", enumerate
766 * global scope of every provider
768 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
,
769 dwType
, dwUsage
, lpNet
);
773 /* this is the same as not having passed lpNet */
774 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
,
775 dwType
, dwUsage
, NULL
);
777 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
782 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
, dwType
,
784 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
787 case RESOURCE_CONTEXT
:
788 *lphEnum
= (HANDLE
)_createContextEnumerator(dwScope
, dwType
,
790 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
792 case RESOURCE_REMEMBERED
:
793 case RESOURCE_CONNECTED
:
794 *lphEnum
= (HANDLE
)_createNullEnumerator();
795 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
798 WARN("unknown scope 0x%08x\n", dwScope
);
804 TRACE("Returning %d\n", ret
);
808 /*********************************************************************
809 * WNetEnumResourceA [MPR.@]
811 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
812 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
816 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
819 ret
= WN_BAD_POINTER
;
821 ret
= WN_BAD_POINTER
;
823 ret
= WN_BAD_POINTER
;
824 else if (!lpBufferSize
)
825 ret
= WN_BAD_POINTER
;
826 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
828 *lpBufferSize
= sizeof(NETRESOURCEA
);
833 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
834 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
838 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
840 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
842 /* FIXME: this isn't necessarily going to work in the case of
843 * WN_MORE_DATA, because our enumerator may have moved on to
844 * the next provider. MSDN states that a large (16KB) buffer
845 * size is the appropriate usage of this function, so
846 * hopefully it won't be an issue.
848 ret
= _thunkNetResourceArrayWToA((LPNETRESOURCEW
)localBuffer
,
849 &localCount
, lpBuffer
, lpBufferSize
);
850 *lpcCount
= localCount
;
852 HeapFree(GetProcessHeap(), 0, localBuffer
);
855 ret
= WN_OUT_OF_MEMORY
;
859 TRACE("Returning %d\n", ret
);
863 static DWORD
_countProviderBytesW(PWNetProvider provider
)
869 ret
= sizeof(NETRESOURCEW
);
870 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
877 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
878 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
883 return WN_BAD_POINTER
;
884 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
887 return WN_BAD_POINTER
;
889 return WN_BAD_POINTER
;
891 return WN_BAD_POINTER
;
892 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
895 if (!providerTable
|| enumerator
->providerIndex
>=
896 providerTable
->numProviders
)
897 ret
= WN_NO_MORE_ENTRIES
;
900 DWORD bytes
= 0, count
= 0, countLimit
, i
;
901 LPNETRESOURCEW resource
;
904 countLimit
= *lpcCount
== -1 ?
905 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
906 while (count
< countLimit
&& bytes
< *lpBufferSize
)
908 DWORD bytesNext
= _countProviderBytesW(
909 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
911 if (bytes
+ bytesNext
< *lpBufferSize
)
917 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
918 for (i
= 0, resource
= (LPNETRESOURCEW
)lpBuffer
; i
< count
;
921 resource
->dwScope
= RESOURCE_GLOBALNET
;
922 resource
->dwType
= RESOURCETYPE_ANY
;
923 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
924 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
925 RESOURCEUSAGE_RESERVED
;
926 resource
->lpLocalName
= NULL
;
927 resource
->lpRemoteName
= strNext
;
928 strcpyW(resource
->lpRemoteName
,
929 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
930 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
931 resource
->lpComment
= NULL
;
932 resource
->lpProvider
= strNext
;
933 strcpyW(resource
->lpProvider
,
934 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
935 strNext
+= strlenW(resource
->lpProvider
) + 1;
937 enumerator
->providerIndex
+= count
;
939 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
941 TRACE("Returning %d\n", ret
);
945 /* Advances the enumerator (assumed to be a global enumerator) to the next
946 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
947 * not open a handle with the next provider.
948 * If the existing handle is NULL, may leave the enumerator unchanged, since
949 * the current provider may support the desired scope.
950 * If the existing handle is not NULL, closes it before moving on.
951 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
952 * provider, and another error on failure.
954 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
957 return WN_BAD_POINTER
;
958 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
960 if (!providerTable
|| enumerator
->providerIndex
>=
961 providerTable
->numProviders
)
962 return WN_NO_MORE_ENTRIES
;
964 if (enumerator
->providerDone
)
966 enumerator
->providerDone
= FALSE
;
967 if (enumerator
->handle
)
969 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
971 enumerator
->handle
= NULL
;
972 enumerator
->providerIndex
++;
974 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
975 !(enumerator
->dwScope
& providerTable
->table
976 [enumerator
->providerIndex
].dwEnumScopes
);
977 enumerator
->providerIndex
++)
980 return enumerator
->providerIndex
< providerTable
->numProviders
?
981 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
984 /* "Passes through" call to the next provider that supports the enumeration
986 * FIXME: if one call to a provider's enumerator succeeds while there's still
987 * space in lpBuffer, I don't call to the next provider. The caller may not
988 * expect that it should call EnumResourceW again with a return value of
989 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
990 * may have to be moved around a bit, ick.
992 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
993 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
998 return WN_BAD_POINTER
;
999 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1000 return WN_BAD_VALUE
;
1002 return WN_BAD_POINTER
;
1004 return WN_BAD_POINTER
;
1006 return WN_BAD_POINTER
;
1007 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1008 return WN_MORE_DATA
;
1010 ret
= _globalEnumeratorAdvance(enumerator
);
1011 if (ret
== WN_SUCCESS
)
1013 ret
= providerTable
->table
[enumerator
->providerIndex
].
1014 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1015 enumerator
->dwUsage
, enumerator
->lpNet
,
1016 &enumerator
->handle
);
1017 if (ret
== WN_SUCCESS
)
1019 ret
= providerTable
->table
[enumerator
->providerIndex
].
1020 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1022 if (ret
!= WN_MORE_DATA
)
1023 enumerator
->providerDone
= TRUE
;
1026 TRACE("Returning %d\n", ret
);
1030 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1031 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1036 return WN_BAD_POINTER
;
1037 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1038 return WN_BAD_VALUE
;
1040 return WN_BAD_POINTER
;
1042 return WN_BAD_POINTER
;
1044 return WN_BAD_POINTER
;
1045 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1046 return WN_MORE_DATA
;
1048 return WN_NO_NETWORK
;
1050 switch (enumerator
->dwScope
)
1052 case RESOURCE_GLOBALNET
:
1053 if (enumerator
->lpNet
)
1054 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1055 lpBuffer
, lpBufferSize
);
1057 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1060 case RESOURCE_CONTEXT
:
1061 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1065 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1066 ret
= WN_NO_MORE_ENTRIES
;
1068 TRACE("Returning %d\n", ret
);
1072 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1073 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1076 return WN_BAD_POINTER
;
1077 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1078 return WN_BAD_VALUE
;
1079 if (!enumerator
->handle
)
1080 return WN_BAD_VALUE
;
1082 return WN_BAD_POINTER
;
1084 return WN_BAD_POINTER
;
1086 return WN_BAD_POINTER
;
1088 return WN_NO_NETWORK
;
1089 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1090 return WN_NO_MORE_ENTRIES
;
1091 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1092 return WN_BAD_VALUE
;
1093 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1094 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1097 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1098 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1101 size_t cchEntireNetworkLen
, bytesNeeded
;
1104 return WN_BAD_POINTER
;
1105 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1106 return WN_BAD_VALUE
;
1108 return WN_BAD_POINTER
;
1110 return WN_BAD_POINTER
;
1112 return WN_BAD_POINTER
;
1114 return WN_NO_NETWORK
;
1116 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1117 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1118 if (*lpBufferSize
< bytesNeeded
)
1120 *lpBufferSize
= bytesNeeded
;
1125 LPNETRESOURCEW lpNet
= (LPNETRESOURCEW
)lpBuffer
;
1127 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1128 lpNet
->dwType
= enumerator
->dwType
;
1129 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1130 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1131 lpNet
->lpLocalName
= NULL
;
1132 lpNet
->lpRemoteName
= NULL
;
1133 lpNet
->lpProvider
= NULL
;
1134 /* odd, but correct: put comment at end of buffer, so it won't get
1135 * overwritten by subsequent calls to a provider's enumResource
1137 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1138 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1139 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1142 if (ret
== WN_SUCCESS
)
1144 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1146 /* "Entire Network" entry enumerated--morph this into a global
1147 * enumerator. enumerator->lpNet continues to be NULL, since it has
1148 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1150 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1151 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1152 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1153 if (ret
== WN_SUCCESS
)
1155 /* reflect the fact that we already enumerated "Entire Network" */
1157 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1161 /* the provider enumeration failed, but we already succeeded in
1162 * enumerating "Entire Network"--leave type as global to allow a
1163 * retry, but indicate success with a count of one.
1167 *lpBufferSize
= bytesNeeded
;
1170 TRACE("Returning %d\n", ret
);
1174 /*********************************************************************
1175 * WNetEnumResourceW [MPR.@]
1177 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1178 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1182 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1185 ret
= WN_BAD_POINTER
;
1187 ret
= WN_BAD_POINTER
;
1189 ret
= WN_BAD_POINTER
;
1190 else if (!lpBufferSize
)
1191 ret
= WN_BAD_POINTER
;
1192 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1194 *lpBufferSize
= sizeof(NETRESOURCEW
);
1199 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1201 switch (enumerator
->enumType
)
1203 case WNET_ENUMERATOR_TYPE_NULL
:
1204 ret
= WN_NO_MORE_ENTRIES
;
1206 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1207 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1210 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1211 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1214 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1215 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1219 WARN("bogus enumerator type!\n");
1220 ret
= WN_NO_NETWORK
;
1225 TRACE("Returning %d\n", ret
);
1229 /*********************************************************************
1230 * WNetCloseEnum [MPR.@]
1232 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1236 TRACE( "(%p)\n", hEnum
);
1240 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1242 switch (enumerator
->enumType
)
1244 case WNET_ENUMERATOR_TYPE_NULL
:
1247 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1248 if (enumerator
->lpNet
)
1249 _freeEnumNetResource(enumerator
->lpNet
);
1250 if (enumerator
->handle
)
1251 providerTable
->table
[enumerator
->providerIndex
].
1252 closeEnum(enumerator
->handle
);
1255 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1256 if (enumerator
->handle
)
1257 providerTable
->table
[enumerator
->providerIndex
].
1258 closeEnum(enumerator
->handle
);
1262 WARN("bogus enumerator type!\n");
1263 ret
= WN_BAD_HANDLE
;
1265 HeapFree(GetProcessHeap(), 0, hEnum
);
1268 ret
= WN_BAD_HANDLE
;
1271 TRACE("Returning %d\n", ret
);
1275 /*********************************************************************
1276 * WNetGetResourceInformationA [MPR.@]
1278 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1279 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1282 FIXME( "(%p, %p, %p, %p): stub\n",
1283 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1285 SetLastError(WN_NO_NETWORK
);
1286 return WN_NO_NETWORK
;
1289 /*********************************************************************
1290 * WNetGetResourceInformationW [MPR.@]
1292 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1293 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1294 LPWSTR
*lplpSystem
)
1296 FIXME( "(%p, %p, %p, %p): stub\n",
1297 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1299 SetLastError(WN_NO_NETWORK
);
1300 return WN_NO_NETWORK
;
1303 /*********************************************************************
1304 * WNetGetResourceParentA [MPR.@]
1306 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1307 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1309 FIXME( "(%p, %p, %p): stub\n",
1310 lpNetResource
, lpBuffer
, lpBufferSize
);
1312 SetLastError(WN_NO_NETWORK
);
1313 return WN_NO_NETWORK
;
1316 /*********************************************************************
1317 * WNetGetResourceParentW [MPR.@]
1319 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1320 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1322 FIXME( "(%p, %p, %p): stub\n",
1323 lpNetResource
, lpBuffer
, lpBufferSize
);
1325 SetLastError(WN_NO_NETWORK
);
1326 return WN_NO_NETWORK
;
1332 * Connection Functions
1335 /*********************************************************************
1336 * WNetAddConnectionA [MPR.@]
1338 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1339 LPCSTR lpLocalName
)
1341 FIXME( "(%s, %p, %s): stub\n",
1342 debugstr_a(lpRemoteName
), lpPassword
, debugstr_a(lpLocalName
) );
1344 SetLastError(WN_NO_NETWORK
);
1345 return WN_NO_NETWORK
;
1348 /*********************************************************************
1349 * WNetAddConnectionW [MPR.@]
1351 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1352 LPCWSTR lpLocalName
)
1354 FIXME( "(%s, %p, %s): stub\n",
1355 debugstr_w(lpRemoteName
), lpPassword
, debugstr_w(lpLocalName
) );
1357 SetLastError(WN_NO_NETWORK
);
1358 return WN_NO_NETWORK
;
1361 /*********************************************************************
1362 * WNetAddConnection2A [MPR.@]
1364 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1365 LPCSTR lpPassword
, LPCSTR lpUserID
,
1368 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1369 lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
);
1371 SetLastError(WN_NO_NETWORK
);
1372 return WN_NO_NETWORK
;
1375 /*********************************************************************
1376 * WNetAddConnection2W [MPR.@]
1378 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1379 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1382 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1383 lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
);
1385 SetLastError(WN_NO_NETWORK
);
1386 return WN_NO_NETWORK
;
1389 /*********************************************************************
1390 * WNetAddConnection3A [MPR.@]
1392 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1393 LPCSTR lpPassword
, LPCSTR lpUserID
,
1396 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1397 hwndOwner
, lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
);
1399 SetLastError(WN_NO_NETWORK
);
1400 return WN_NO_NETWORK
;
1403 /*********************************************************************
1404 * WNetAddConnection3W [MPR.@]
1406 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1407 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1410 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1411 hwndOwner
, lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
);
1413 SetLastError(WN_NO_NETWORK
);
1414 return WN_NO_NETWORK
;
1417 /*****************************************************************
1418 * WNetUseConnectionA [MPR.@]
1420 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1421 LPCSTR lpPassword
, LPCSTR lpUserID
, DWORD dwFlags
,
1422 LPSTR lpAccessName
, LPDWORD lpBufferSize
,
1425 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1426 hwndOwner
, lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
,
1427 debugstr_a(lpAccessName
), lpBufferSize
, lpResult
);
1429 SetLastError(WN_NO_NETWORK
);
1430 return WN_NO_NETWORK
;
1433 /*****************************************************************
1434 * WNetUseConnectionW [MPR.@]
1436 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1437 LPCWSTR lpPassword
, LPCWSTR lpUserID
, DWORD dwFlags
,
1438 LPWSTR lpAccessName
, LPDWORD lpBufferSize
,
1441 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1442 hwndOwner
, lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
,
1443 debugstr_w(lpAccessName
), lpBufferSize
, lpResult
);
1445 SetLastError(WN_NO_NETWORK
);
1446 return WN_NO_NETWORK
;
1449 /*********************************************************************
1450 * WNetCancelConnectionA [MPR.@]
1452 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
1454 FIXME( "(%s, %d), stub\n", debugstr_a(lpName
), fForce
);
1459 /*********************************************************************
1460 * WNetCancelConnectionW [MPR.@]
1462 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
1464 FIXME( "(%s, %d), stub\n", debugstr_w(lpName
), fForce
);
1469 /*********************************************************************
1470 * WNetCancelConnection2A [MPR.@]
1472 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1474 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName
), dwFlags
, fForce
);
1479 /*********************************************************************
1480 * WNetCancelConnection2W [MPR.@]
1482 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1484 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName
), dwFlags
, fForce
);
1489 /*****************************************************************
1490 * WNetRestoreConnectionA [MPR.@]
1492 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPSTR lpszDevice
)
1494 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
1496 SetLastError(WN_NO_NETWORK
);
1497 return WN_NO_NETWORK
;
1500 /*****************************************************************
1501 * WNetRestoreConnectionW [MPR.@]
1503 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPWSTR lpszDevice
)
1505 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
1507 SetLastError(WN_NO_NETWORK
);
1508 return WN_NO_NETWORK
;
1511 /**************************************************************************
1512 * WNetGetConnectionA [MPR.@]
1515 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1516 * - WN_NOT_CONNECTED drive is a local drive
1517 * - WN_MORE_DATA buffer isn't big enough
1518 * - WN_SUCCESS success (net path in buffer)
1520 * FIXME: need to test return values under different errors
1522 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
1523 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
1528 ret
= WN_BAD_POINTER
;
1529 else if (!lpRemoteName
)
1530 ret
= WN_BAD_POINTER
;
1531 else if (!lpBufferSize
)
1532 ret
= WN_BAD_POINTER
;
1535 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
1539 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1543 WCHAR wideRemoteStatic
[MAX_PATH
];
1544 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
1546 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
1548 /* try once without memory allocation */
1549 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
1551 if (ret
== WN_SUCCESS
)
1553 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1554 -1, NULL
, 0, NULL
, NULL
);
1556 if (len
<= *lpBufferSize
)
1558 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
1559 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1564 *lpBufferSize
= len
;
1568 else if (ret
== WN_MORE_DATA
)
1570 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
1571 wideRemoteSize
* sizeof(WCHAR
));
1575 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
1577 if (ret
== WN_SUCCESS
)
1579 if (len
<= *lpBufferSize
)
1581 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1582 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1587 *lpBufferSize
= len
;
1591 HeapFree(GetProcessHeap(), 0, wideRemote
);
1594 ret
= WN_OUT_OF_MEMORY
;
1596 HeapFree(GetProcessHeap(), 0, wideLocalName
);
1599 ret
= WN_OUT_OF_MEMORY
;
1602 ret
= WN_BAD_LOCALNAME
;
1606 TRACE("Returning %d\n", ret
);
1610 /**************************************************************************
1611 * WNetGetConnectionW [MPR.@]
1613 * FIXME: need to test return values under different errors
1615 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
1616 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
1620 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
1624 ret
= WN_BAD_POINTER
;
1625 else if (!lpRemoteName
)
1626 ret
= WN_BAD_POINTER
;
1627 else if (!lpBufferSize
)
1628 ret
= WN_BAD_POINTER
;
1629 else if (!lpLocalName
[0])
1630 ret
= WN_BAD_LOCALNAME
;
1633 if (lpLocalName
[1] == ':')
1635 switch(GetDriveTypeW(lpLocalName
))
1639 WCHAR remote
[MAX_PATH
];
1640 if (!QueryDosDeviceW( lpLocalName
, remote
, MAX_PATH
)) remote
[0] = 0;
1641 if (strlenW(remote
) + 1 > *lpBufferSize
)
1643 *lpBufferSize
= strlenW(remote
) + 1;
1648 strcpyW( lpRemoteName
, remote
);
1649 *lpBufferSize
= strlenW(lpRemoteName
) + 1;
1654 case DRIVE_REMOVABLE
:
1657 TRACE("file is local\n");
1658 ret
= WN_NOT_CONNECTED
;
1661 ret
= WN_BAD_LOCALNAME
;
1665 ret
= WN_BAD_LOCALNAME
;
1669 TRACE("Returning %d\n", ret
);
1673 /**************************************************************************
1674 * WNetSetConnectionA [MPR.@]
1676 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
1679 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
1681 SetLastError(WN_NO_NETWORK
);
1682 return WN_NO_NETWORK
;
1685 /**************************************************************************
1686 * WNetSetConnectionW [MPR.@]
1688 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
1691 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
1693 SetLastError(WN_NO_NETWORK
);
1694 return WN_NO_NETWORK
;
1697 /*****************************************************************
1698 * WNetGetUniversalNameA [MPR.@]
1700 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
1701 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1703 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1704 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
1706 SetLastError(WN_NO_NETWORK
);
1707 return WN_NO_NETWORK
;
1710 /*****************************************************************
1711 * WNetGetUniversalNameW [MPR.@]
1713 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
1714 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1716 LPUNIVERSAL_NAME_INFOW uniw
;
1719 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1720 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
1722 switch (dwInfoLevel
)
1724 case UNIVERSAL_NAME_INFO_LEVEL
:
1726 len
= sizeof (*uniw
) + lstrlenW(lpLocalPath
);
1727 if (*lpBufferSize
<= len
)
1730 uniw
->lpUniversalName
= (LPWSTR
) &uniw
[1];
1731 lstrcpyW(uniw
->lpUniversalName
, lpLocalPath
);
1732 *lpBufferSize
= len
;
1736 case REMOTE_NAME_INFO_LEVEL
:
1737 err
= WN_NO_NETWORK
;
1754 /**************************************************************************
1755 * WNetGetUserA [MPR.@]
1757 * FIXME: we should not return ourselves, but the owner of the drive lpName
1759 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
1761 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
1762 return GetLastError();
1765 /*****************************************************************
1766 * WNetGetUserW [MPR.@]
1768 * FIXME: we should not return ourselves, but the owner of the drive lpName
1770 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
1772 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
1773 return GetLastError();
1776 /*********************************************************************
1777 * WNetConnectionDialog [MPR.@]
1779 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
1781 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
1783 SetLastError(WN_NO_NETWORK
);
1784 return WN_NO_NETWORK
;
1787 /*********************************************************************
1788 * WNetConnectionDialog1A [MPR.@]
1790 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
1792 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1794 SetLastError(WN_NO_NETWORK
);
1795 return WN_NO_NETWORK
;
1798 /*********************************************************************
1799 * WNetConnectionDialog1W [MPR.@]
1801 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
1803 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1805 SetLastError(WN_NO_NETWORK
);
1806 return WN_NO_NETWORK
;
1809 /*********************************************************************
1810 * WNetDisconnectDialog [MPR.@]
1812 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
1814 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
1816 SetLastError(WN_NO_NETWORK
);
1817 return WN_NO_NETWORK
;
1820 /*********************************************************************
1821 * WNetDisconnectDialog1A [MPR.@]
1823 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
1825 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1827 SetLastError(WN_NO_NETWORK
);
1828 return WN_NO_NETWORK
;
1831 /*********************************************************************
1832 * WNetDisconnectDialog1W [MPR.@]
1834 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
1836 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1838 SetLastError(WN_NO_NETWORK
);
1839 return WN_NO_NETWORK
;
1842 /*********************************************************************
1843 * WNetGetLastErrorA [MPR.@]
1845 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
1846 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
1847 LPSTR lpNameBuf
, DWORD nNameBufSize
)
1849 FIXME( "(%p, %p, %d, %p, %d): stub\n",
1850 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
1852 SetLastError(WN_NO_NETWORK
);
1853 return WN_NO_NETWORK
;
1856 /*********************************************************************
1857 * WNetGetLastErrorW [MPR.@]
1859 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
1860 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
1861 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
1863 FIXME( "(%p, %p, %d, %p, %d): stub\n",
1864 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
1866 SetLastError(WN_NO_NETWORK
);
1867 return WN_NO_NETWORK
;
1870 /*********************************************************************
1871 * WNetGetNetworkInformationA [MPR.@]
1873 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
1874 LPNETINFOSTRUCT lpNetInfoStruct
)
1878 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
1881 ret
= WN_BAD_POINTER
;
1886 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
1889 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1893 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
1895 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
1896 HeapFree(GetProcessHeap(), 0, wideProvider
);
1899 ret
= WN_OUT_OF_MEMORY
;
1902 ret
= GetLastError();
1906 TRACE("Returning %d\n", ret
);
1910 /*********************************************************************
1911 * WNetGetNetworkInformationW [MPR.@]
1913 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
1914 LPNETINFOSTRUCT lpNetInfoStruct
)
1918 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
1921 ret
= WN_BAD_POINTER
;
1922 else if (!lpNetInfoStruct
)
1923 ret
= WN_BAD_POINTER
;
1924 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
1928 if (providerTable
&& providerTable
->numProviders
)
1930 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
1932 if (providerIndex
!= BAD_PROVIDER_INDEX
)
1934 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
1935 lpNetInfoStruct
->dwProviderVersion
=
1936 providerTable
->table
[providerIndex
].dwSpecVersion
;
1937 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
1938 lpNetInfoStruct
->dwCharacteristics
= 0;
1939 lpNetInfoStruct
->dwHandle
= (ULONG_PTR
)NULL
;
1940 lpNetInfoStruct
->wNetType
=
1941 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
1942 lpNetInfoStruct
->dwPrinters
= -1;
1943 lpNetInfoStruct
->dwDrives
= -1;
1947 ret
= WN_BAD_PROVIDER
;
1950 ret
= WN_NO_NETWORK
;
1954 TRACE("Returning %d\n", ret
);
1958 /*****************************************************************
1959 * WNetGetProviderNameA [MPR.@]
1961 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
1962 LPSTR lpProvider
, LPDWORD lpBufferSize
)
1966 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
1970 ret
= WN_BAD_POINTER
;
1971 else if (!lpBufferSize
)
1972 ret
= WN_BAD_POINTER
;
1979 ret
= WN_NO_NETWORK
;
1980 for (i
= 0; i
< providerTable
->numProviders
&&
1981 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
1984 if (i
< providerTable
->numProviders
)
1986 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
1987 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
1989 if (*lpBufferSize
< sizeNeeded
)
1991 *lpBufferSize
= sizeNeeded
;
1996 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
1997 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
1999 /* FIXME: is *lpBufferSize set to the number of characters
2005 ret
= WN_NO_NETWORK
;
2009 TRACE("Returning %d\n", ret
);
2013 /*****************************************************************
2014 * WNetGetProviderNameW [MPR.@]
2016 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2017 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2021 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2025 ret
= WN_BAD_POINTER
;
2026 else if (!lpBufferSize
)
2027 ret
= WN_BAD_POINTER
;
2034 ret
= WN_NO_NETWORK
;
2035 for (i
= 0; i
< providerTable
->numProviders
&&
2036 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2039 if (i
< providerTable
->numProviders
)
2041 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2043 if (*lpBufferSize
< sizeNeeded
)
2045 *lpBufferSize
= sizeNeeded
;
2050 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2052 /* FIXME: is *lpBufferSize set to the number of characters
2058 ret
= WN_NO_NETWORK
;
2062 TRACE("Returning %d\n", ret
);