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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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%08lx\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
, ',');
267 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
268 sizeof(WNetProviderTable
)
269 + (numToAllocate
- 1) * sizeof(WNetProvider
));
273 int entireNetworkLen
;
275 entireNetworkLen
= LoadStringW(hInstDll
,
276 IDS_ENTIRENETWORK
, NULL
, 0);
277 providerTable
->entireNetwork
= HeapAlloc(
278 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
280 if (providerTable
->entireNetwork
)
281 LoadStringW(hInstDll
, IDS_ENTIRENETWORK
,
282 providerTable
->entireNetwork
,
283 entireNetworkLen
+ 1);
284 providerTable
->numAllocated
= numToAllocate
;
285 for (ptr
= providers
; ptr
; )
288 ptr
= strchrW(ptr
, ',');
291 _tryLoadProvider(ptrPrev
);
295 HeapFree(GetProcessHeap(), 0, providers
);
308 for (i
= 0; i
< providerTable
->numProviders
; i
++)
310 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
311 FreeModule(providerTable
->table
[i
].hLib
);
313 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
314 HeapFree(GetProcessHeap(), 0, providerTable
);
315 providerTable
= NULL
;
319 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
321 DWORD ret
= BAD_PROVIDER_INDEX
;
323 if (providerTable
&& providerTable
->numProviders
)
327 for (i
= 0; i
< providerTable
->numProviders
&&
328 ret
== BAD_PROVIDER_INDEX
; i
++)
329 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
339 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
345 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
350 memcpy(ret
, lpNet
, sizeof(ret
));
351 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
352 if (lpNet
->lpRemoteName
)
354 len
= strlenW(lpNet
->lpRemoteName
) + 1;
355 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
356 if (ret
->lpRemoteName
)
357 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
366 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
370 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
371 HeapFree(GetProcessHeap(), 0, lpNet
);
375 static PWNetEnumerator
_createNullEnumerator(void)
377 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
378 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
381 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
385 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
386 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
388 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
389 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
393 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
394 ret
->dwScope
= dwScope
;
395 ret
->dwType
= dwType
;
396 ret
->dwUsage
= dwUsage
;
397 ret
->lpNet
= _copyNetResourceForEnumW(lpNet
);
402 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
403 DWORD dwUsage
, DWORD index
, HANDLE handle
)
407 if (!providerTable
|| index
>= providerTable
->numProviders
)
411 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
414 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
415 ret
->providerIndex
= index
;
416 ret
->dwScope
= dwScope
;
417 ret
->dwType
= dwType
;
418 ret
->dwUsage
= dwUsage
;
419 ret
->handle
= handle
;
425 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
428 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
429 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
433 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
434 ret
->dwScope
= dwScope
;
435 ret
->dwType
= dwType
;
436 ret
->dwUsage
= dwUsage
;
441 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
442 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
443 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
444 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
445 * if not all members of the array could be thunked, and something else on
448 static DWORD
_thunkNetResourceArrayWToA(const LPNETRESOURCEW lpNetArrayIn
,
449 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
451 DWORD i
, numToThunk
, totalBytes
, ret
;
455 return WN_BAD_POINTER
;
457 return WN_BAD_POINTER
;
461 return WN_BAD_POINTER
;
463 return WN_BAD_POINTER
;
465 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
467 LPNETRESOURCEW lpNet
= lpNetArrayIn
+ i
;
469 totalBytes
+= sizeof(NETRESOURCEA
);
470 if (lpNet
->lpLocalName
)
471 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
472 -1, NULL
, 0, NULL
, NULL
);
473 if (lpNet
->lpRemoteName
)
474 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
475 -1, NULL
, 0, NULL
, NULL
);
476 if (lpNet
->lpComment
)
477 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
478 -1, NULL
, 0, NULL
, NULL
);
479 if (lpNet
->lpProvider
)
480 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
481 -1, NULL
, 0, NULL
, NULL
);
482 if (totalBytes
< *lpBufferSize
)
485 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
486 for (i
= 0; i
< numToThunk
; i
++)
488 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
489 LPNETRESOURCEW lpNetIn
= lpNetArrayIn
+ i
;
491 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
492 /* lie about string lengths, we already verified how many
493 * we have space for above
495 if (lpNetIn
->lpLocalName
)
497 lpNetOut
->lpLocalName
= strNext
;
498 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
499 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
501 if (lpNetIn
->lpRemoteName
)
503 lpNetOut
->lpRemoteName
= strNext
;
504 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
505 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
507 if (lpNetIn
->lpComment
)
509 lpNetOut
->lpComment
= strNext
;
510 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
511 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
513 if (lpNetIn
->lpProvider
)
515 lpNetOut
->lpProvider
= strNext
;
516 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
517 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
520 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
521 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk
,
526 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
527 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
528 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
529 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
530 * if not all members of the array could be thunked, and something else on
533 static DWORD
_thunkNetResourceArrayAToW(const LPNETRESOURCEA lpNetArrayIn
,
534 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
536 DWORD i
, numToThunk
, totalBytes
, ret
;
540 return WN_BAD_POINTER
;
542 return WN_BAD_POINTER
;
546 return WN_BAD_POINTER
;
548 return WN_BAD_POINTER
;
550 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
552 LPNETRESOURCEA lpNet
= lpNetArrayIn
+ i
;
554 totalBytes
+= sizeof(NETRESOURCEW
);
555 if (lpNet
->lpLocalName
)
556 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
557 -1, NULL
, 0) * sizeof(WCHAR
);
558 if (lpNet
->lpRemoteName
)
559 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
560 -1, NULL
, 0) * sizeof(WCHAR
);
561 if (lpNet
->lpComment
)
562 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
563 -1, NULL
, 0) * sizeof(WCHAR
);
564 if (lpNet
->lpProvider
)
565 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
566 -1, NULL
, 0) * sizeof(WCHAR
);
567 if (totalBytes
< *lpBufferSize
)
570 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
571 for (i
= 0; i
< numToThunk
; i
++)
573 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
574 LPNETRESOURCEA lpNetIn
= lpNetArrayIn
+ i
;
576 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
577 /* lie about string lengths, we already verified how many
578 * we have space for above
580 if (lpNetIn
->lpLocalName
)
582 lpNetOut
->lpLocalName
= strNext
;
583 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
584 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
586 if (lpNetIn
->lpRemoteName
)
588 lpNetOut
->lpRemoteName
= strNext
;
589 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
590 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
592 if (lpNetIn
->lpComment
)
594 lpNetOut
->lpComment
= strNext
;
595 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
596 -1, lpNetOut
->lpComment
, *lpBufferSize
);
598 if (lpNetIn
->lpProvider
)
600 lpNetOut
->lpProvider
= strNext
;
601 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
602 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
605 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
606 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk
,
611 /*********************************************************************
612 * WNetOpenEnumA [MPR.@]
614 * See comments for WNetOpenEnumW.
616 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
617 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
621 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
622 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
625 ret
= WN_BAD_POINTER
;
626 else if (!providerTable
|| providerTable
->numProviders
== 0)
632 LPNETRESOURCEW lpNetWide
= NULL
;
634 DWORD size
= sizeof(buf
), count
= 1;
635 BOOL allocated
= FALSE
;
637 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
638 if (ret
== WN_MORE_DATA
)
640 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
644 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
649 ret
= WN_OUT_OF_MEMORY
;
651 else if (ret
== WN_SUCCESS
)
652 lpNetWide
= (LPNETRESOURCEW
)buf
;
653 if (ret
== WN_SUCCESS
)
654 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
656 if (allocated
&& lpNetWide
)
657 HeapFree(GetProcessHeap(), 0, lpNetWide
);
660 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
664 TRACE("Returning %ld\n", ret
);
668 /*********************************************************************
669 * WNetOpenEnumW [MPR.@]
671 * Network enumeration has way too many parameters, so I'm not positive I got
672 * them right. What I've got so far:
674 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
675 * all the network providers should be enumerated.
677 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
678 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
679 * lpProvider is set, all the network providers should be enumerated.
680 * (This means the enumeration is a list of network providers, not that the
681 * enumeration is passed on to the providers.)
683 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
684 * resource matches the "Entire Network" resource (no remote name, no
685 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
686 * enumeration is done on every network provider.
688 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
689 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
690 * only to the given network provider.
692 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
693 * no lpProvider is set, enumeration will be tried on every network provider,
694 * in the order in which they're loaded.
696 * - The LPNETRESOURCE should be disregarded for scopes besides
697 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
698 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
700 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
701 * resource in the enumerated list, as well as any machines in your
702 * workgroup. The machines in your workgroup come from doing a
703 * RESOURCE_CONTEXT enumeration of every Network Provider.
705 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
706 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
710 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
711 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
714 ret
= WN_BAD_POINTER
;
715 else if (!providerTable
|| providerTable
->numProviders
== 0)
721 case RESOURCE_GLOBALNET
:
724 if (lpNet
->lpProvider
)
726 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
728 if (index
!= BAD_PROVIDER_INDEX
)
730 if (providerTable
->table
[index
].openEnum
&&
731 providerTable
->table
[index
].dwEnumScopes
& dwScope
)
735 ret
= providerTable
->table
[index
].openEnum(
736 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
737 if (ret
== WN_SUCCESS
)
740 (HANDLE
)_createProviderEnumerator(
741 dwScope
, dwType
, dwUsage
, index
, handle
);
742 ret
= *lphEnum
? WN_SUCCESS
:
747 ret
= WN_NOT_SUPPORTED
;
750 ret
= WN_BAD_PROVIDER
;
752 else if (lpNet
->lpRemoteName
)
754 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
,
755 dwType
, dwUsage
, lpNet
);
756 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
760 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
761 providerTable
->entireNetwork
))
763 /* comment matches the "Entire Network", enumerate
764 * global scope of every provider
766 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
,
767 dwType
, dwUsage
, lpNet
);
771 /* this is the same as not having passed lpNet */
772 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
,
773 dwType
, dwUsage
, NULL
);
775 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
780 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
, dwType
,
782 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
785 case RESOURCE_CONTEXT
:
786 *lphEnum
= (HANDLE
)_createContextEnumerator(dwScope
, dwType
,
788 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
790 case RESOURCE_REMEMBERED
:
791 case RESOURCE_CONNECTED
:
792 *lphEnum
= (HANDLE
)_createNullEnumerator();
793 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
796 WARN("unknown scope 0x%08lx\n", dwScope
);
802 TRACE("Returning %ld\n", ret
);
806 /*********************************************************************
807 * WNetEnumResourceA [MPR.@]
809 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
810 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
814 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
817 ret
= WN_BAD_POINTER
;
819 ret
= WN_BAD_POINTER
;
821 ret
= WN_BAD_POINTER
;
822 else if (!lpBufferSize
)
823 ret
= WN_BAD_POINTER
;
824 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
826 *lpBufferSize
= sizeof(NETRESOURCEA
);
831 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
832 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
836 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
838 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
840 /* FIXME: this isn't necessarily going to work in the case of
841 * WN_MORE_DATA, because our enumerator may have moved on to
842 * the next provider. MSDN states that a large (16KB) buffer
843 * size is the appropriate usage of this function, so
844 * hopefully it won't be an issue.
846 ret
= _thunkNetResourceArrayWToA((LPNETRESOURCEW
)localBuffer
,
847 &localCount
, lpBuffer
, lpBufferSize
);
848 *lpcCount
= localCount
;
850 HeapFree(GetProcessHeap(), 0, localBuffer
);
853 ret
= WN_OUT_OF_MEMORY
;
857 TRACE("Returning %ld\n", ret
);
861 static DWORD
_countProviderBytesW(PWNetProvider provider
)
867 ret
= sizeof(NETRESOURCEW
);
868 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
875 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
876 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
881 return WN_BAD_POINTER
;
882 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
885 return WN_BAD_POINTER
;
887 return WN_BAD_POINTER
;
889 return WN_BAD_POINTER
;
890 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
893 if (!providerTable
|| enumerator
->providerIndex
>=
894 providerTable
->numProviders
)
895 ret
= WN_NO_MORE_ENTRIES
;
898 DWORD bytes
= 0, count
= 0, countLimit
, i
;
899 LPNETRESOURCEW resource
;
902 countLimit
= *lpcCount
== -1 ?
903 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
904 while (count
< countLimit
&& bytes
< *lpBufferSize
)
906 DWORD bytesNext
= _countProviderBytesW(
907 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
909 if (bytes
+ bytesNext
< *lpBufferSize
)
915 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
916 for (i
= 0, resource
= (LPNETRESOURCEW
)lpBuffer
; i
< count
;
919 resource
->dwScope
= RESOURCE_GLOBALNET
;
920 resource
->dwType
= RESOURCETYPE_ANY
;
921 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
922 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
923 RESOURCEUSAGE_RESERVED
;
924 resource
->lpLocalName
= NULL
;
925 resource
->lpRemoteName
= strNext
;
926 strcpyW(resource
->lpRemoteName
,
927 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
928 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
929 resource
->lpComment
= NULL
;
930 resource
->lpProvider
= strNext
;
931 strcpyW(resource
->lpProvider
,
932 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
933 strNext
+= strlenW(resource
->lpProvider
) + 1;
935 enumerator
->providerIndex
+= count
;
937 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
939 TRACE("Returning %ld\n", ret
);
943 /* Advances the enumerator (assumed to be a global enumerator) to the next
944 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
945 * not open a handle with the next provider.
946 * If the existing handle is NULL, may leave the enumerator unchanged, since
947 * the current provider may support the desired scope.
948 * If the existing handle is not NULL, closes it before moving on.
949 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
950 * provider, and another error on failure.
952 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
955 return WN_BAD_POINTER
;
956 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
958 if (!providerTable
|| enumerator
->providerIndex
>=
959 providerTable
->numProviders
)
960 return WN_NO_MORE_ENTRIES
;
962 if (enumerator
->providerDone
)
964 enumerator
->providerDone
= FALSE
;
965 if (enumerator
->handle
)
967 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
969 enumerator
->handle
= NULL
;
970 enumerator
->providerIndex
++;
972 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
973 !(enumerator
->dwScope
& providerTable
->table
974 [enumerator
->providerIndex
].dwEnumScopes
);
975 enumerator
->providerIndex
++)
978 return enumerator
->providerIndex
< providerTable
->numProviders
?
979 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
982 /* "Passes through" call to the next provider that supports the enumeration
984 * FIXME: if one call to a provider's enumerator succeeds while there's still
985 * space in lpBuffer, I don't call to the next provider. The caller may not
986 * expect that it should call EnumResourceW again with a return value of
987 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
988 * may have to be moved around a bit, ick.
990 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
991 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
996 return WN_BAD_POINTER
;
997 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1000 return WN_BAD_POINTER
;
1002 return WN_BAD_POINTER
;
1004 return WN_BAD_POINTER
;
1005 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1006 return WN_MORE_DATA
;
1008 ret
= _globalEnumeratorAdvance(enumerator
);
1009 if (ret
== WN_SUCCESS
)
1011 ret
= providerTable
->table
[enumerator
->providerIndex
].
1012 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1013 enumerator
->dwUsage
, enumerator
->lpNet
,
1014 &enumerator
->handle
);
1015 if (ret
== WN_SUCCESS
)
1017 ret
= providerTable
->table
[enumerator
->providerIndex
].
1018 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1020 if (ret
!= WN_MORE_DATA
)
1021 enumerator
->providerDone
= TRUE
;
1024 TRACE("Returning %ld\n", ret
);
1028 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1029 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1034 return WN_BAD_POINTER
;
1035 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1036 return WN_BAD_VALUE
;
1038 return WN_BAD_POINTER
;
1040 return WN_BAD_POINTER
;
1042 return WN_BAD_POINTER
;
1043 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1044 return WN_MORE_DATA
;
1046 return WN_NO_NETWORK
;
1048 switch (enumerator
->dwScope
)
1050 case RESOURCE_GLOBALNET
:
1051 if (enumerator
->lpNet
)
1052 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1053 lpBuffer
, lpBufferSize
);
1055 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1058 case RESOURCE_CONTEXT
:
1059 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1063 WARN("unexpected scope 0x%08lx\n", enumerator
->dwScope
);
1064 ret
= WN_NO_MORE_ENTRIES
;
1066 TRACE("Returning %ld\n", ret
);
1070 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1071 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1074 return WN_BAD_POINTER
;
1075 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1076 return WN_BAD_VALUE
;
1077 if (!enumerator
->handle
)
1078 return WN_BAD_VALUE
;
1080 return WN_BAD_POINTER
;
1082 return WN_BAD_POINTER
;
1084 return WN_BAD_POINTER
;
1086 return WN_NO_NETWORK
;
1087 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1088 return WN_NO_MORE_ENTRIES
;
1089 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1090 return WN_BAD_VALUE
;
1091 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1092 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1095 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1096 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1099 size_t cchEntireNetworkLen
, bytesNeeded
;
1102 return WN_BAD_POINTER
;
1103 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1104 return WN_BAD_VALUE
;
1106 return WN_BAD_POINTER
;
1108 return WN_BAD_POINTER
;
1110 return WN_BAD_POINTER
;
1112 return WN_NO_NETWORK
;
1114 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1115 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1116 if (*lpBufferSize
< bytesNeeded
)
1118 *lpBufferSize
= bytesNeeded
;
1123 LPNETRESOURCEW lpNet
= (LPNETRESOURCEW
)lpBuffer
;
1125 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1126 lpNet
->dwType
= enumerator
->dwType
;
1127 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1128 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1129 lpNet
->lpLocalName
= NULL
;
1130 lpNet
->lpRemoteName
= NULL
;
1131 lpNet
->lpProvider
= NULL
;
1132 /* odd, but correct: put comment at end of buffer, so it won't get
1133 * overwritten by subsequent calls to a provider's enumResource
1135 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1136 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1137 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1140 if (ret
== WN_SUCCESS
)
1142 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1144 /* "Entire Network" entry enumerated--morph this into a global
1145 * enumerator. enumerator->lpNet continues to be NULL, since it has
1146 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1148 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1149 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1150 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1151 if (ret
== WN_SUCCESS
)
1153 /* reflect the fact that we already enumerated "Entire Network" */
1155 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1159 /* the provider enumeration failed, but we already succeeded in
1160 * enumerating "Entire Network"--leave type as global to allow a
1161 * retry, but indicate success with a count of one.
1165 *lpBufferSize
= bytesNeeded
;
1168 TRACE("Returning %ld\n", ret
);
1172 /*********************************************************************
1173 * WNetEnumResourceW [MPR.@]
1175 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1176 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1180 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1183 ret
= WN_BAD_POINTER
;
1185 ret
= WN_BAD_POINTER
;
1187 ret
= WN_BAD_POINTER
;
1188 else if (!lpBufferSize
)
1189 ret
= WN_BAD_POINTER
;
1190 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1192 *lpBufferSize
= sizeof(NETRESOURCEW
);
1197 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1199 switch (enumerator
->enumType
)
1201 case WNET_ENUMERATOR_TYPE_NULL
:
1202 ret
= WN_NO_MORE_ENTRIES
;
1204 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1205 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1208 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1209 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1212 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1213 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1217 WARN("bogus enumerator type!\n");
1218 ret
= WN_NO_NETWORK
;
1223 TRACE("Returning %ld\n", ret
);
1227 /*********************************************************************
1228 * WNetCloseEnum [MPR.@]
1230 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1234 TRACE( "(%p)\n", hEnum
);
1238 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1240 switch (enumerator
->enumType
)
1242 case WNET_ENUMERATOR_TYPE_NULL
:
1245 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1246 if (enumerator
->lpNet
)
1247 _freeEnumNetResource(enumerator
->lpNet
);
1248 if (enumerator
->handle
)
1249 providerTable
->table
[enumerator
->providerIndex
].
1250 closeEnum(enumerator
->handle
);
1253 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1254 if (enumerator
->handle
)
1255 providerTable
->table
[enumerator
->providerIndex
].
1256 closeEnum(enumerator
->handle
);
1260 WARN("bogus enumerator type!\n");
1261 ret
= WN_BAD_HANDLE
;
1263 HeapFree(GetProcessHeap(), 0, hEnum
);
1266 ret
= WN_BAD_HANDLE
;
1269 TRACE("Returning %ld\n", ret
);
1273 /*********************************************************************
1274 * WNetGetResourceInformationA [MPR.@]
1276 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1277 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1280 FIXME( "(%p, %p, %p, %p): stub\n",
1281 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1283 SetLastError(WN_NO_NETWORK
);
1284 return WN_NO_NETWORK
;
1287 /*********************************************************************
1288 * WNetGetResourceInformationW [MPR.@]
1290 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1291 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1292 LPWSTR
*lplpSystem
)
1294 FIXME( "(%p, %p, %p, %p): stub\n",
1295 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1297 SetLastError(WN_NO_NETWORK
);
1298 return WN_NO_NETWORK
;
1301 /*********************************************************************
1302 * WNetGetResourceParentA [MPR.@]
1304 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1305 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1307 FIXME( "(%p, %p, %p): stub\n",
1308 lpNetResource
, lpBuffer
, lpBufferSize
);
1310 SetLastError(WN_NO_NETWORK
);
1311 return WN_NO_NETWORK
;
1314 /*********************************************************************
1315 * WNetGetResourceParentW [MPR.@]
1317 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1318 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1320 FIXME( "(%p, %p, %p): stub\n",
1321 lpNetResource
, lpBuffer
, lpBufferSize
);
1323 SetLastError(WN_NO_NETWORK
);
1324 return WN_NO_NETWORK
;
1330 * Connection Functions
1333 /*********************************************************************
1334 * WNetAddConnectionA [MPR.@]
1336 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1337 LPCSTR lpLocalName
)
1339 FIXME( "(%s, %p, %s): stub\n",
1340 debugstr_a(lpRemoteName
), lpPassword
, debugstr_a(lpLocalName
) );
1342 SetLastError(WN_NO_NETWORK
);
1343 return WN_NO_NETWORK
;
1346 /*********************************************************************
1347 * WNetAddConnectionW [MPR.@]
1349 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1350 LPCWSTR lpLocalName
)
1352 FIXME( "(%s, %p, %s): stub\n",
1353 debugstr_w(lpRemoteName
), lpPassword
, debugstr_w(lpLocalName
) );
1355 SetLastError(WN_NO_NETWORK
);
1356 return WN_NO_NETWORK
;
1359 /*********************************************************************
1360 * WNetAddConnection2A [MPR.@]
1362 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1363 LPCSTR lpPassword
, LPCSTR lpUserID
,
1366 FIXME( "(%p, %p, %s, 0x%08lX): stub\n",
1367 lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
);
1369 SetLastError(WN_NO_NETWORK
);
1370 return WN_NO_NETWORK
;
1373 /*********************************************************************
1374 * WNetAddConnection2W [MPR.@]
1376 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1377 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1380 FIXME( "(%p, %p, %s, 0x%08lX): stub\n",
1381 lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
);
1383 SetLastError(WN_NO_NETWORK
);
1384 return WN_NO_NETWORK
;
1387 /*********************************************************************
1388 * WNetAddConnection3A [MPR.@]
1390 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1391 LPCSTR lpPassword
, LPCSTR lpUserID
,
1394 FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n",
1395 hwndOwner
, lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
);
1397 SetLastError(WN_NO_NETWORK
);
1398 return WN_NO_NETWORK
;
1401 /*********************************************************************
1402 * WNetAddConnection3W [MPR.@]
1404 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1405 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1408 FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n",
1409 hwndOwner
, lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
);
1411 SetLastError(WN_NO_NETWORK
);
1412 return WN_NO_NETWORK
;
1415 /*****************************************************************
1416 * WNetUseConnectionA [MPR.@]
1418 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1419 LPCSTR lpPassword
, LPCSTR lpUserID
, DWORD dwFlags
,
1420 LPSTR lpAccessName
, LPDWORD lpBufferSize
,
1423 FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n",
1424 hwndOwner
, lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
,
1425 debugstr_a(lpAccessName
), lpBufferSize
, lpResult
);
1427 SetLastError(WN_NO_NETWORK
);
1428 return WN_NO_NETWORK
;
1431 /*****************************************************************
1432 * WNetUseConnectionW [MPR.@]
1434 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1435 LPCWSTR lpPassword
, LPCWSTR lpUserID
, DWORD dwFlags
,
1436 LPWSTR lpAccessName
, LPDWORD lpBufferSize
,
1439 FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n",
1440 hwndOwner
, lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
,
1441 debugstr_w(lpAccessName
), lpBufferSize
, lpResult
);
1443 SetLastError(WN_NO_NETWORK
);
1444 return WN_NO_NETWORK
;
1447 /*********************************************************************
1448 * WNetCancelConnectionA [MPR.@]
1450 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
1452 FIXME( "(%s, %d), stub\n", debugstr_a(lpName
), fForce
);
1457 /*********************************************************************
1458 * WNetCancelConnectionW [MPR.@]
1460 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
1462 FIXME( "(%s, %d), stub\n", debugstr_w(lpName
), fForce
);
1467 /*********************************************************************
1468 * WNetCancelConnection2A [MPR.@]
1470 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1472 FIXME( "(%s, %08lX, %d), stub\n", debugstr_a(lpName
), dwFlags
, fForce
);
1477 /*********************************************************************
1478 * WNetCancelConnection2W [MPR.@]
1480 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1482 FIXME( "(%s, %08lX, %d), stub\n", debugstr_w(lpName
), dwFlags
, fForce
);
1487 /*****************************************************************
1488 * WNetRestoreConnectionA [MPR.@]
1490 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPSTR lpszDevice
)
1492 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
1494 SetLastError(WN_NO_NETWORK
);
1495 return WN_NO_NETWORK
;
1498 /*****************************************************************
1499 * WNetRestoreConnectionW [MPR.@]
1501 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPWSTR lpszDevice
)
1503 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
1505 SetLastError(WN_NO_NETWORK
);
1506 return WN_NO_NETWORK
;
1509 /**************************************************************************
1510 * WNetGetConnectionA [MPR.@]
1513 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1514 * - WN_NOT_CONNECTED drive is a local drive
1515 * - WN_MORE_DATA buffer isn't big enough
1516 * - WN_SUCCESS success (net path in buffer)
1518 * FIXME: need to test return values under different errors
1520 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
1521 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
1526 ret
= WN_BAD_POINTER
;
1527 else if (!lpRemoteName
)
1528 ret
= WN_BAD_POINTER
;
1529 else if (!lpBufferSize
)
1530 ret
= WN_BAD_POINTER
;
1533 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
1537 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1541 WCHAR wideRemoteStatic
[MAX_PATH
];
1542 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
1544 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
1546 /* try once without memory allocation */
1547 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
1549 if (ret
== WN_SUCCESS
)
1551 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1552 -1, NULL
, 0, NULL
, NULL
);
1554 if (len
<= *lpBufferSize
)
1556 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
1557 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1562 *lpBufferSize
= len
;
1566 else if (ret
== WN_MORE_DATA
)
1568 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
1569 wideRemoteSize
* sizeof(WCHAR
));
1573 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
1575 if (ret
== WN_SUCCESS
)
1577 if (len
<= *lpBufferSize
)
1579 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1580 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1585 *lpBufferSize
= len
;
1589 HeapFree(GetProcessHeap(), 0, wideRemote
);
1592 ret
= WN_OUT_OF_MEMORY
;
1594 HeapFree(GetProcessHeap(), 0, wideLocalName
);
1597 ret
= WN_OUT_OF_MEMORY
;
1600 ret
= WN_BAD_LOCALNAME
;
1604 TRACE("Returning %ld\n", ret
);
1608 /**************************************************************************
1609 * WNetGetConnectionW [MPR.@]
1611 * FIXME: need to test return values under different errors
1613 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
1614 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
1618 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
1622 ret
= WN_BAD_POINTER
;
1623 else if (!lpRemoteName
)
1624 ret
= WN_BAD_POINTER
;
1625 else if (!lpBufferSize
)
1626 ret
= WN_BAD_POINTER
;
1627 else if (!lpLocalName
[0])
1628 ret
= WN_BAD_LOCALNAME
;
1631 if (lpLocalName
[1] == ':')
1633 switch(GetDriveTypeW(lpLocalName
))
1637 WCHAR remote
[MAX_PATH
];
1638 if (!QueryDosDeviceW( lpLocalName
, remote
, MAX_PATH
)) remote
[0] = 0;
1639 if (strlenW(remote
) + 1 > *lpBufferSize
)
1641 *lpBufferSize
= strlenW(remote
) + 1;
1646 strcpyW( lpRemoteName
, remote
);
1647 *lpBufferSize
= strlenW(lpRemoteName
) + 1;
1652 case DRIVE_REMOVABLE
:
1655 TRACE("file is local\n");
1656 ret
= WN_NOT_CONNECTED
;
1659 ret
= WN_BAD_LOCALNAME
;
1663 ret
= WN_BAD_LOCALNAME
;
1667 TRACE("Returning %ld\n", ret
);
1671 /**************************************************************************
1672 * WNetSetConnectionA [MPR.@]
1674 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
1677 FIXME( "(%s, %08lX, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
1679 SetLastError(WN_NO_NETWORK
);
1680 return WN_NO_NETWORK
;
1683 /**************************************************************************
1684 * WNetSetConnectionW [MPR.@]
1686 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
1689 FIXME( "(%s, %08lX, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
1691 SetLastError(WN_NO_NETWORK
);
1692 return WN_NO_NETWORK
;
1695 /*****************************************************************
1696 * WNetGetUniversalNameA [MPR.@]
1698 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
1699 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1701 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
1702 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
1704 SetLastError(WN_NO_NETWORK
);
1705 return WN_NO_NETWORK
;
1708 /*****************************************************************
1709 * WNetGetUniversalNameW [MPR.@]
1711 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
1712 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1714 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
1715 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
1717 SetLastError(WN_NO_NETWORK
);
1718 return WN_NO_NETWORK
;
1727 /**************************************************************************
1728 * WNetGetUserA [MPR.@]
1730 * FIXME: we should not return ourselves, but the owner of the drive lpName
1732 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
1734 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
1735 return GetLastError();
1738 /*****************************************************************
1739 * WNetGetUserW [MPR.@]
1741 * FIXME: we should not return ourselves, but the owner of the drive lpName
1743 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
1745 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
1746 return GetLastError();
1749 /*********************************************************************
1750 * WNetConnectionDialog [MPR.@]
1752 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
1754 FIXME( "(%p, %08lX): stub\n", hwnd
, dwType
);
1756 SetLastError(WN_NO_NETWORK
);
1757 return WN_NO_NETWORK
;
1760 /*********************************************************************
1761 * WNetConnectionDialog1A [MPR.@]
1763 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
1765 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1767 SetLastError(WN_NO_NETWORK
);
1768 return WN_NO_NETWORK
;
1771 /*********************************************************************
1772 * WNetConnectionDialog1W [MPR.@]
1774 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
1776 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1778 SetLastError(WN_NO_NETWORK
);
1779 return WN_NO_NETWORK
;
1782 /*********************************************************************
1783 * WNetDisconnectDialog [MPR.@]
1785 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
1787 FIXME( "(%p, %08lX): stub\n", hwnd
, dwType
);
1789 SetLastError(WN_NO_NETWORK
);
1790 return WN_NO_NETWORK
;
1793 /*********************************************************************
1794 * WNetDisconnectDialog1A [MPR.@]
1796 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
1798 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1800 SetLastError(WN_NO_NETWORK
);
1801 return WN_NO_NETWORK
;
1804 /*********************************************************************
1805 * WNetDisconnectDialog1W [MPR.@]
1807 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
1809 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1811 SetLastError(WN_NO_NETWORK
);
1812 return WN_NO_NETWORK
;
1815 /*********************************************************************
1816 * WNetGetLastErrorA [MPR.@]
1818 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
1819 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
1820 LPSTR lpNameBuf
, DWORD nNameBufSize
)
1822 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
1823 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
1825 SetLastError(WN_NO_NETWORK
);
1826 return WN_NO_NETWORK
;
1829 /*********************************************************************
1830 * WNetGetLastErrorW [MPR.@]
1832 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
1833 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
1834 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
1836 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
1837 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
1839 SetLastError(WN_NO_NETWORK
);
1840 return WN_NO_NETWORK
;
1843 /*********************************************************************
1844 * WNetGetNetworkInformationA [MPR.@]
1846 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
1847 LPNETINFOSTRUCT lpNetInfoStruct
)
1851 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
1854 ret
= WN_BAD_POINTER
;
1859 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
1862 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1866 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
1868 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
1869 HeapFree(GetProcessHeap(), 0, wideProvider
);
1872 ret
= WN_OUT_OF_MEMORY
;
1875 ret
= GetLastError();
1879 TRACE("Returning %ld\n", ret
);
1883 /*********************************************************************
1884 * WNetGetNetworkInformationW [MPR.@]
1886 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
1887 LPNETINFOSTRUCT lpNetInfoStruct
)
1891 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
1894 ret
= WN_BAD_POINTER
;
1895 else if (!lpNetInfoStruct
)
1896 ret
= WN_BAD_POINTER
;
1897 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
1901 if (providerTable
&& providerTable
->numProviders
)
1903 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
1905 if (providerIndex
!= BAD_PROVIDER_INDEX
)
1907 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
1908 lpNetInfoStruct
->dwProviderVersion
=
1909 providerTable
->table
[providerIndex
].dwSpecVersion
;
1910 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
1911 lpNetInfoStruct
->dwCharacteristics
= 0;
1912 lpNetInfoStruct
->dwHandle
= (ULONG_PTR
)NULL
;
1913 lpNetInfoStruct
->wNetType
=
1914 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
1915 lpNetInfoStruct
->dwPrinters
= -1;
1916 lpNetInfoStruct
->dwDrives
= -1;
1920 ret
= WN_BAD_PROVIDER
;
1923 ret
= WN_NO_NETWORK
;
1927 TRACE("Returning %ld\n", ret
);
1931 /*****************************************************************
1932 * WNetGetProviderNameA [MPR.@]
1934 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
1935 LPSTR lpProvider
, LPDWORD lpBufferSize
)
1939 TRACE("(0x%08lx, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
1943 ret
= WN_BAD_POINTER
;
1944 else if (!lpBufferSize
)
1945 ret
= WN_BAD_POINTER
;
1952 ret
= WN_NO_NETWORK
;
1953 for (i
= 0; i
< providerTable
->numProviders
&&
1954 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
1957 if (i
< providerTable
->numProviders
)
1959 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
1960 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
1962 if (*lpBufferSize
< sizeNeeded
)
1964 *lpBufferSize
= sizeNeeded
;
1969 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
1970 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
1972 /* FIXME: is *lpBufferSize set to the number of characters
1978 ret
= WN_NO_NETWORK
;
1982 TRACE("Returning %ld\n", ret
);
1986 /*****************************************************************
1987 * WNetGetProviderNameW [MPR.@]
1989 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
1990 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
1994 TRACE("(0x%08lx, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
1998 ret
= WN_BAD_POINTER
;
1999 else if (!lpBufferSize
)
2000 ret
= WN_BAD_POINTER
;
2007 ret
= WN_NO_NETWORK
;
2008 for (i
= 0; i
< providerTable
->numProviders
&&
2009 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2012 if (i
< providerTable
->numProviders
)
2014 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2016 if (*lpBufferSize
< sizeNeeded
)
2018 *lpBufferSize
= sizeNeeded
;
2023 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2025 /* FIXME: is *lpBufferSize set to the number of characters
2031 ret
= WN_NO_NETWORK
;
2035 TRACE("Returning %ld\n", ret
);