4 * Copyright 1999 Ulrich Weigand
5 * Copyright 2004 Juan Lang
6 * Copyright 2007 Maarten Lankhorst
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(mpr
);
38 /* Data structures representing network service providers. Assumes only one
39 * thread creates them, and that they are constant for the life of the process
40 * (and therefore doesn't synchronize access).
41 * FIXME: only basic provider data and enumeration-related data are implemented
42 * so far, need to implement the rest too.
44 typedef struct _WNetProvider
52 PF_NPOpenEnum openEnum
;
53 PF_NPEnumResource enumResource
;
54 PF_NPCloseEnum closeEnum
;
55 } WNetProvider
, *PWNetProvider
;
57 typedef struct _WNetProviderTable
62 WNetProvider table
[1];
63 } WNetProviderTable
, *PWNetProviderTable
;
65 #define WNET_ENUMERATOR_TYPE_NULL 0
66 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
67 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
68 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
70 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
71 * the enumeration; it represents one of the following types:
72 * - a 'null' enumeration, one that contains no members
73 * - a global enumeration, one that's executed across all providers
74 * - a provider-specific enumeration, one that's only executed by a single
76 * - a context enumeration. I know this contradicts what I just said about
77 * there being no correspondence between the scope and the type, but it's
78 * necessary for the special case that a "Entire Network" entry needs to
79 * be enumerated in an enumeration of the context scope. Thus an enumeration
80 * of the context scope results in a context type enumerator, which morphs
81 * into a global enumeration (so the enumeration continues across all
84 typedef struct _WNetEnumerator
94 } WNetEnumerator
, *PWNetEnumerator
;
96 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
98 /* Returns an index (into the global WNetProviderTable) of the provider with
99 * the given name, or BAD_PROVIDER_INDEX if not found.
101 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
103 static PWNetProviderTable providerTable
;
106 * Global provider table functions
109 static void _tryLoadProvider(PCWSTR provider
)
111 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
112 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
113 'S','e','r','v','i','c','e','s','\\',0 };
114 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
115 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
116 WCHAR serviceName
[MAX_PATH
];
119 TRACE("%s\n", debugstr_w(provider
));
120 snprintfW(serviceName
, sizeof(serviceName
) / sizeof(WCHAR
), serviceFmt
,
121 servicePrefix
, provider
);
122 serviceName
[sizeof(serviceName
) / sizeof(WCHAR
) - 1] = '\0';
123 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
126 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
128 WCHAR providerPath
[MAX_PATH
];
129 DWORD type
, size
= sizeof(providerPath
);
131 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
132 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
134 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
138 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
141 name
= HeapAlloc(GetProcessHeap(), 0, size
);
142 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
143 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
145 HeapFree(GetProcessHeap(), 0, name
);
151 HMODULE hLib
= LoadLibraryW(providerPath
);
155 PF_NPGetCaps getCaps
= (PF_NPGetCaps
)GetProcAddress(hLib
,
158 TRACE("loaded lib %p\n", hLib
);
161 PWNetProvider provider
=
162 &providerTable
->table
[providerTable
->numProviders
];
164 provider
->hLib
= hLib
;
165 provider
->name
= name
;
166 TRACE("name is %s\n", debugstr_w(name
));
167 provider
->getCaps
= getCaps
;
168 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
169 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
170 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
171 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
172 if (provider
->dwEnumScopes
)
174 TRACE("supports enumeration\n");
175 provider
->openEnum
= (PF_NPOpenEnum
)
176 GetProcAddress(hLib
, "NPOpenEnum");
177 TRACE("openEnum is %p\n", provider
->openEnum
);
178 provider
->enumResource
= (PF_NPEnumResource
)
179 GetProcAddress(hLib
, "NPEnumResource");
180 TRACE("enumResource is %p\n",
181 provider
->enumResource
);
182 provider
->closeEnum
= (PF_NPCloseEnum
)
183 GetProcAddress(hLib
, "NPCloseEnum");
184 TRACE("closeEnum is %p\n", provider
->closeEnum
);
185 if (!provider
->openEnum
|| !provider
->enumResource
186 || !provider
->closeEnum
)
188 provider
->openEnum
= NULL
;
189 provider
->enumResource
= NULL
;
190 provider
->closeEnum
= NULL
;
191 provider
->dwEnumScopes
= 0;
192 WARN("Couldn't load enumeration functions\n");
195 providerTable
->numProviders
++;
199 WARN("Provider %s didn't export NPGetCaps\n",
200 debugstr_w(provider
));
201 HeapFree(GetProcessHeap(), 0, name
);
207 WARN("Couldn't load library %s for provider %s\n",
208 debugstr_w(providerPath
), debugstr_w(provider
));
209 HeapFree(GetProcessHeap(), 0, name
);
214 WARN("Couldn't get provider name for provider %s\n",
215 debugstr_w(provider
));
219 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
223 WARN("Couldn't open service key for provider %s\n",
224 debugstr_w(provider
));
227 void wnetInit(HINSTANCE hInstDll
)
229 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
230 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
231 'C','o','n','t','r','o','l','\\',
232 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
233 'O','r','d','e','r',0 };
234 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
235 'O','r','d','e','r',0 };
238 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
243 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
246 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
252 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
253 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
258 TRACE("provider order is %s\n", debugstr_w(providers
));
259 /* first count commas as a heuristic for how many to
260 * allocate space for */
261 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
263 ptr
= strchrW(ptr
, ',');
270 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
271 sizeof(WNetProviderTable
)
272 + (numToAllocate
- 1) * sizeof(WNetProvider
));
276 int entireNetworkLen
;
278 entireNetworkLen
= LoadStringW(hInstDll
,
279 IDS_ENTIRENETWORK
, NULL
, 0);
280 providerTable
->entireNetwork
= HeapAlloc(
281 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
283 if (providerTable
->entireNetwork
)
284 LoadStringW(hInstDll
, IDS_ENTIRENETWORK
,
285 providerTable
->entireNetwork
,
286 entireNetworkLen
+ 1);
287 providerTable
->numAllocated
= numToAllocate
;
288 for (ptr
= providers
; ptr
; )
291 ptr
= strchrW(ptr
, ',');
294 _tryLoadProvider(ptrPrev
);
298 HeapFree(GetProcessHeap(), 0, providers
);
311 for (i
= 0; i
< providerTable
->numProviders
; i
++)
313 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
314 FreeModule(providerTable
->table
[i
].hLib
);
316 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
317 HeapFree(GetProcessHeap(), 0, providerTable
);
318 providerTable
= NULL
;
322 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
324 DWORD ret
= BAD_PROVIDER_INDEX
;
326 if (providerTable
&& providerTable
->numProviders
)
330 for (i
= 0; i
< providerTable
->numProviders
&&
331 ret
== BAD_PROVIDER_INDEX
; i
++)
332 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
342 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
348 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
353 memcpy(ret
, lpNet
, sizeof(ret
));
354 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
355 if (lpNet
->lpRemoteName
)
357 len
= strlenW(lpNet
->lpRemoteName
) + 1;
358 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
359 if (ret
->lpRemoteName
)
360 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
369 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
373 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
374 HeapFree(GetProcessHeap(), 0, lpNet
);
378 static PWNetEnumerator
_createNullEnumerator(void)
380 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
381 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
384 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
388 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
389 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
391 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
392 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
396 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
397 ret
->dwScope
= dwScope
;
398 ret
->dwType
= dwType
;
399 ret
->dwUsage
= dwUsage
;
400 ret
->lpNet
= _copyNetResourceForEnumW(lpNet
);
405 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
406 DWORD dwUsage
, DWORD index
, HANDLE handle
)
410 if (!providerTable
|| index
>= providerTable
->numProviders
)
414 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
417 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
418 ret
->providerIndex
= index
;
419 ret
->dwScope
= dwScope
;
420 ret
->dwType
= dwType
;
421 ret
->dwUsage
= dwUsage
;
422 ret
->handle
= handle
;
428 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
431 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
432 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
436 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
437 ret
->dwScope
= dwScope
;
438 ret
->dwType
= dwType
;
439 ret
->dwUsage
= dwUsage
;
444 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
445 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
446 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
447 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
448 * if not all members of the array could be thunked, and something else on
451 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
452 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
454 DWORD i
, numToThunk
, totalBytes
, ret
;
458 return WN_BAD_POINTER
;
460 return WN_BAD_POINTER
;
464 return WN_BAD_POINTER
;
466 return WN_BAD_POINTER
;
468 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
470 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
472 totalBytes
+= sizeof(NETRESOURCEA
);
473 if (lpNet
->lpLocalName
)
474 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
475 -1, NULL
, 0, NULL
, NULL
);
476 if (lpNet
->lpRemoteName
)
477 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
478 -1, NULL
, 0, NULL
, NULL
);
479 if (lpNet
->lpComment
)
480 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
481 -1, NULL
, 0, NULL
, NULL
);
482 if (lpNet
->lpProvider
)
483 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
484 -1, NULL
, 0, NULL
, NULL
);
485 if (totalBytes
< *lpBufferSize
)
488 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
489 for (i
= 0; i
< numToThunk
; i
++)
491 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
492 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
494 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
495 /* lie about string lengths, we already verified how many
496 * we have space for above
498 if (lpNetIn
->lpLocalName
)
500 lpNetOut
->lpLocalName
= strNext
;
501 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
502 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
504 if (lpNetIn
->lpRemoteName
)
506 lpNetOut
->lpRemoteName
= strNext
;
507 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
508 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
510 if (lpNetIn
->lpComment
)
512 lpNetOut
->lpComment
= strNext
;
513 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
514 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
516 if (lpNetIn
->lpProvider
)
518 lpNetOut
->lpProvider
= strNext
;
519 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
520 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
523 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
524 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
529 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
530 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
531 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
532 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
533 * if not all members of the array could be thunked, and something else on
536 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
537 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
539 DWORD i
, numToThunk
, totalBytes
, ret
;
543 return WN_BAD_POINTER
;
545 return WN_BAD_POINTER
;
549 return WN_BAD_POINTER
;
551 return WN_BAD_POINTER
;
553 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
555 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
557 totalBytes
+= sizeof(NETRESOURCEW
);
558 if (lpNet
->lpLocalName
)
559 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
560 -1, NULL
, 0) * sizeof(WCHAR
);
561 if (lpNet
->lpRemoteName
)
562 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
563 -1, NULL
, 0) * sizeof(WCHAR
);
564 if (lpNet
->lpComment
)
565 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
566 -1, NULL
, 0) * sizeof(WCHAR
);
567 if (lpNet
->lpProvider
)
568 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
569 -1, NULL
, 0) * sizeof(WCHAR
);
570 if (totalBytes
< *lpBufferSize
)
573 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
574 for (i
= 0; i
< numToThunk
; i
++)
576 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
577 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
579 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
580 /* lie about string lengths, we already verified how many
581 * we have space for above
583 if (lpNetIn
->lpLocalName
)
585 lpNetOut
->lpLocalName
= strNext
;
586 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
587 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
589 if (lpNetIn
->lpRemoteName
)
591 lpNetOut
->lpRemoteName
= strNext
;
592 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
593 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
595 if (lpNetIn
->lpComment
)
597 lpNetOut
->lpComment
= strNext
;
598 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
599 -1, lpNetOut
->lpComment
, *lpBufferSize
);
601 if (lpNetIn
->lpProvider
)
603 lpNetOut
->lpProvider
= strNext
;
604 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
605 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
608 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
609 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
614 /*********************************************************************
615 * WNetOpenEnumA [MPR.@]
617 * See comments for WNetOpenEnumW.
619 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
620 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
624 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
625 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
628 ret
= WN_BAD_POINTER
;
629 else if (!providerTable
|| providerTable
->numProviders
== 0)
635 LPNETRESOURCEW lpNetWide
= NULL
;
637 DWORD size
= sizeof(buf
), count
= 1;
638 BOOL allocated
= FALSE
;
640 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
641 if (ret
== WN_MORE_DATA
)
643 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
647 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
652 ret
= WN_OUT_OF_MEMORY
;
654 else if (ret
== WN_SUCCESS
)
655 lpNetWide
= (LPNETRESOURCEW
)buf
;
656 if (ret
== WN_SUCCESS
)
657 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
660 HeapFree(GetProcessHeap(), 0, lpNetWide
);
663 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
667 TRACE("Returning %d\n", ret
);
671 /*********************************************************************
672 * WNetOpenEnumW [MPR.@]
674 * Network enumeration has way too many parameters, so I'm not positive I got
675 * them right. What I've got so far:
677 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
678 * all the network providers should be enumerated.
680 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
681 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
682 * lpProvider is set, all the network providers should be enumerated.
683 * (This means the enumeration is a list of network providers, not that the
684 * enumeration is passed on to the providers.)
686 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
687 * resource matches the "Entire Network" resource (no remote name, no
688 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
689 * enumeration is done on every network provider.
691 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
692 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
693 * only to the given network provider.
695 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
696 * no lpProvider is set, enumeration will be tried on every network provider,
697 * in the order in which they're loaded.
699 * - The LPNETRESOURCE should be disregarded for scopes besides
700 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
701 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
703 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
704 * resource in the enumerated list, as well as any machines in your
705 * workgroup. The machines in your workgroup come from doing a
706 * RESOURCE_CONTEXT enumeration of every Network Provider.
708 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
709 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
713 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
714 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
717 ret
= WN_BAD_POINTER
;
718 else if (!providerTable
|| providerTable
->numProviders
== 0)
724 case RESOURCE_GLOBALNET
:
727 if (lpNet
->lpProvider
)
729 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
731 if (index
!= BAD_PROVIDER_INDEX
)
733 if (providerTable
->table
[index
].openEnum
&&
734 providerTable
->table
[index
].dwEnumScopes
& dwScope
)
738 ret
= providerTable
->table
[index
].openEnum(
739 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
740 if (ret
== WN_SUCCESS
)
743 (HANDLE
)_createProviderEnumerator(
744 dwScope
, dwType
, dwUsage
, index
, handle
);
745 ret
= *lphEnum
? WN_SUCCESS
:
750 ret
= WN_NOT_SUPPORTED
;
753 ret
= WN_BAD_PROVIDER
;
755 else if (lpNet
->lpRemoteName
)
757 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
,
758 dwType
, dwUsage
, lpNet
);
759 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
763 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
764 providerTable
->entireNetwork
))
766 /* comment matches the "Entire Network", enumerate
767 * global scope of every provider
769 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
,
770 dwType
, dwUsage
, lpNet
);
774 /* this is the same as not having passed lpNet */
775 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
,
776 dwType
, dwUsage
, NULL
);
778 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
783 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
, dwType
,
785 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
788 case RESOURCE_CONTEXT
:
789 *lphEnum
= (HANDLE
)_createContextEnumerator(dwScope
, dwType
,
791 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
793 case RESOURCE_REMEMBERED
:
794 case RESOURCE_CONNECTED
:
795 *lphEnum
= (HANDLE
)_createNullEnumerator();
796 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
799 WARN("unknown scope 0x%08x\n", dwScope
);
805 TRACE("Returning %d\n", ret
);
809 /*********************************************************************
810 * WNetEnumResourceA [MPR.@]
812 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
813 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
817 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
820 ret
= WN_BAD_POINTER
;
822 ret
= WN_BAD_POINTER
;
824 ret
= WN_BAD_POINTER
;
825 else if (!lpBufferSize
)
826 ret
= WN_BAD_POINTER
;
827 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
829 *lpBufferSize
= sizeof(NETRESOURCEA
);
834 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
835 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
839 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
841 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
843 /* FIXME: this isn't necessarily going to work in the case of
844 * WN_MORE_DATA, because our enumerator may have moved on to
845 * the next provider. MSDN states that a large (16KB) buffer
846 * size is the appropriate usage of this function, so
847 * hopefully it won't be an issue.
849 ret
= _thunkNetResourceArrayWToA((LPNETRESOURCEW
)localBuffer
,
850 &localCount
, lpBuffer
, lpBufferSize
);
851 *lpcCount
= localCount
;
853 HeapFree(GetProcessHeap(), 0, localBuffer
);
856 ret
= WN_OUT_OF_MEMORY
;
860 TRACE("Returning %d\n", ret
);
864 static DWORD
_countProviderBytesW(PWNetProvider provider
)
870 ret
= sizeof(NETRESOURCEW
);
871 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
878 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
879 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
884 return WN_BAD_POINTER
;
885 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
888 return WN_BAD_POINTER
;
890 return WN_BAD_POINTER
;
892 return WN_BAD_POINTER
;
893 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
896 if (!providerTable
|| enumerator
->providerIndex
>=
897 providerTable
->numProviders
)
898 ret
= WN_NO_MORE_ENTRIES
;
901 DWORD bytes
= 0, count
= 0, countLimit
, i
;
902 LPNETRESOURCEW resource
;
905 countLimit
= *lpcCount
== -1 ?
906 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
907 while (count
< countLimit
&& bytes
< *lpBufferSize
)
909 DWORD bytesNext
= _countProviderBytesW(
910 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
912 if (bytes
+ bytesNext
< *lpBufferSize
)
918 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
919 for (i
= 0, resource
= (LPNETRESOURCEW
)lpBuffer
; i
< count
;
922 resource
->dwScope
= RESOURCE_GLOBALNET
;
923 resource
->dwType
= RESOURCETYPE_ANY
;
924 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
925 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
926 RESOURCEUSAGE_RESERVED
;
927 resource
->lpLocalName
= NULL
;
928 resource
->lpRemoteName
= strNext
;
929 strcpyW(resource
->lpRemoteName
,
930 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
931 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
932 resource
->lpComment
= NULL
;
933 resource
->lpProvider
= strNext
;
934 strcpyW(resource
->lpProvider
,
935 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
936 strNext
+= strlenW(resource
->lpProvider
) + 1;
938 enumerator
->providerIndex
+= count
;
940 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
942 TRACE("Returning %d\n", ret
);
946 /* Advances the enumerator (assumed to be a global enumerator) to the next
947 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
948 * not open a handle with the next provider.
949 * If the existing handle is NULL, may leave the enumerator unchanged, since
950 * the current provider may support the desired scope.
951 * If the existing handle is not NULL, closes it before moving on.
952 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
953 * provider, and another error on failure.
955 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
958 return WN_BAD_POINTER
;
959 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
961 if (!providerTable
|| enumerator
->providerIndex
>=
962 providerTable
->numProviders
)
963 return WN_NO_MORE_ENTRIES
;
965 if (enumerator
->providerDone
)
967 enumerator
->providerDone
= FALSE
;
968 if (enumerator
->handle
)
970 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
972 enumerator
->handle
= NULL
;
973 enumerator
->providerIndex
++;
975 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
976 !(enumerator
->dwScope
& providerTable
->table
977 [enumerator
->providerIndex
].dwEnumScopes
);
978 enumerator
->providerIndex
++)
981 return enumerator
->providerIndex
< providerTable
->numProviders
?
982 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
985 /* "Passes through" call to the next provider that supports the enumeration
987 * FIXME: if one call to a provider's enumerator succeeds while there's still
988 * space in lpBuffer, I don't call to the next provider. The caller may not
989 * expect that it should call EnumResourceW again with a return value of
990 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
991 * may have to be moved around a bit, ick.
993 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
994 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
999 return WN_BAD_POINTER
;
1000 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1001 return WN_BAD_VALUE
;
1003 return WN_BAD_POINTER
;
1005 return WN_BAD_POINTER
;
1007 return WN_BAD_POINTER
;
1008 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1009 return WN_MORE_DATA
;
1011 ret
= _globalEnumeratorAdvance(enumerator
);
1012 if (ret
== WN_SUCCESS
)
1014 ret
= providerTable
->table
[enumerator
->providerIndex
].
1015 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1016 enumerator
->dwUsage
, enumerator
->lpNet
,
1017 &enumerator
->handle
);
1018 if (ret
== WN_SUCCESS
)
1020 ret
= providerTable
->table
[enumerator
->providerIndex
].
1021 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1023 if (ret
!= WN_MORE_DATA
)
1024 enumerator
->providerDone
= TRUE
;
1027 TRACE("Returning %d\n", ret
);
1031 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1032 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1037 return WN_BAD_POINTER
;
1038 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1039 return WN_BAD_VALUE
;
1041 return WN_BAD_POINTER
;
1043 return WN_BAD_POINTER
;
1045 return WN_BAD_POINTER
;
1046 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1047 return WN_MORE_DATA
;
1049 return WN_NO_NETWORK
;
1051 switch (enumerator
->dwScope
)
1053 case RESOURCE_GLOBALNET
:
1054 if (enumerator
->lpNet
)
1055 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1056 lpBuffer
, lpBufferSize
);
1058 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1061 case RESOURCE_CONTEXT
:
1062 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1066 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1067 ret
= WN_NO_MORE_ENTRIES
;
1069 TRACE("Returning %d\n", ret
);
1073 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1074 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1077 return WN_BAD_POINTER
;
1078 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1079 return WN_BAD_VALUE
;
1080 if (!enumerator
->handle
)
1081 return WN_BAD_VALUE
;
1083 return WN_BAD_POINTER
;
1085 return WN_BAD_POINTER
;
1087 return WN_BAD_POINTER
;
1089 return WN_NO_NETWORK
;
1090 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1091 return WN_NO_MORE_ENTRIES
;
1092 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1093 return WN_BAD_VALUE
;
1094 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1095 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1098 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1099 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1102 size_t cchEntireNetworkLen
, bytesNeeded
;
1105 return WN_BAD_POINTER
;
1106 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1107 return WN_BAD_VALUE
;
1109 return WN_BAD_POINTER
;
1111 return WN_BAD_POINTER
;
1113 return WN_BAD_POINTER
;
1115 return WN_NO_NETWORK
;
1117 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1118 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1119 if (*lpBufferSize
< bytesNeeded
)
1121 *lpBufferSize
= bytesNeeded
;
1126 LPNETRESOURCEW lpNet
= (LPNETRESOURCEW
)lpBuffer
;
1128 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1129 lpNet
->dwType
= enumerator
->dwType
;
1130 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1131 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1132 lpNet
->lpLocalName
= NULL
;
1133 lpNet
->lpRemoteName
= NULL
;
1134 lpNet
->lpProvider
= NULL
;
1135 /* odd, but correct: put comment at end of buffer, so it won't get
1136 * overwritten by subsequent calls to a provider's enumResource
1138 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1139 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1140 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1143 if (ret
== WN_SUCCESS
)
1145 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1147 /* "Entire Network" entry enumerated--morph this into a global
1148 * enumerator. enumerator->lpNet continues to be NULL, since it has
1149 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1151 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1152 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1153 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1154 if (ret
== WN_SUCCESS
)
1156 /* reflect the fact that we already enumerated "Entire Network" */
1158 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1162 /* the provider enumeration failed, but we already succeeded in
1163 * enumerating "Entire Network"--leave type as global to allow a
1164 * retry, but indicate success with a count of one.
1168 *lpBufferSize
= bytesNeeded
;
1171 TRACE("Returning %d\n", ret
);
1175 /*********************************************************************
1176 * WNetEnumResourceW [MPR.@]
1178 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1179 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1183 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1186 ret
= WN_BAD_POINTER
;
1188 ret
= WN_BAD_POINTER
;
1190 ret
= WN_BAD_POINTER
;
1191 else if (!lpBufferSize
)
1192 ret
= WN_BAD_POINTER
;
1193 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1195 *lpBufferSize
= sizeof(NETRESOURCEW
);
1200 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1202 switch (enumerator
->enumType
)
1204 case WNET_ENUMERATOR_TYPE_NULL
:
1205 ret
= WN_NO_MORE_ENTRIES
;
1207 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1208 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1211 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1212 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1215 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1216 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1220 WARN("bogus enumerator type!\n");
1221 ret
= WN_NO_NETWORK
;
1226 TRACE("Returning %d\n", ret
);
1230 /*********************************************************************
1231 * WNetCloseEnum [MPR.@]
1233 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1237 TRACE( "(%p)\n", hEnum
);
1241 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1243 switch (enumerator
->enumType
)
1245 case WNET_ENUMERATOR_TYPE_NULL
:
1248 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1249 if (enumerator
->lpNet
)
1250 _freeEnumNetResource(enumerator
->lpNet
);
1251 if (enumerator
->handle
)
1252 providerTable
->table
[enumerator
->providerIndex
].
1253 closeEnum(enumerator
->handle
);
1256 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1257 if (enumerator
->handle
)
1258 providerTable
->table
[enumerator
->providerIndex
].
1259 closeEnum(enumerator
->handle
);
1263 WARN("bogus enumerator type!\n");
1264 ret
= WN_BAD_HANDLE
;
1266 HeapFree(GetProcessHeap(), 0, hEnum
);
1269 ret
= WN_BAD_HANDLE
;
1272 TRACE("Returning %d\n", ret
);
1276 /*********************************************************************
1277 * WNetGetResourceInformationA [MPR.@]
1279 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1280 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1283 FIXME( "(%p, %p, %p, %p): stub\n",
1284 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1286 SetLastError(WN_NO_NETWORK
);
1287 return WN_NO_NETWORK
;
1290 /*********************************************************************
1291 * WNetGetResourceInformationW [MPR.@]
1293 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1294 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1295 LPWSTR
*lplpSystem
)
1297 FIXME( "(%p, %p, %p, %p): stub\n",
1298 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1300 SetLastError(WN_NO_NETWORK
);
1301 return WN_NO_NETWORK
;
1304 /*********************************************************************
1305 * WNetGetResourceParentA [MPR.@]
1307 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1308 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1310 FIXME( "(%p, %p, %p): stub\n",
1311 lpNetResource
, lpBuffer
, lpBufferSize
);
1313 SetLastError(WN_NO_NETWORK
);
1314 return WN_NO_NETWORK
;
1317 /*********************************************************************
1318 * WNetGetResourceParentW [MPR.@]
1320 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1321 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1323 FIXME( "(%p, %p, %p): stub\n",
1324 lpNetResource
, lpBuffer
, lpBufferSize
);
1326 SetLastError(WN_NO_NETWORK
);
1327 return WN_NO_NETWORK
;
1333 * Connection Functions
1336 /*********************************************************************
1337 * WNetAddConnectionA [MPR.@]
1339 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1340 LPCSTR lpLocalName
)
1342 FIXME( "(%s, %p, %s): stub\n",
1343 debugstr_a(lpRemoteName
), lpPassword
, debugstr_a(lpLocalName
) );
1345 SetLastError(WN_NO_NETWORK
);
1346 return WN_NO_NETWORK
;
1349 /*********************************************************************
1350 * WNetAddConnectionW [MPR.@]
1352 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1353 LPCWSTR lpLocalName
)
1355 FIXME( "(%s, %p, %s): stub\n",
1356 debugstr_w(lpRemoteName
), lpPassword
, debugstr_w(lpLocalName
) );
1358 SetLastError(WN_NO_NETWORK
);
1359 return WN_NO_NETWORK
;
1362 /*********************************************************************
1363 * WNetAddConnection2A [MPR.@]
1365 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1366 LPCSTR lpPassword
, LPCSTR lpUserID
,
1369 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1370 lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
);
1372 SetLastError(WN_NO_NETWORK
);
1373 return WN_NO_NETWORK
;
1376 /*********************************************************************
1377 * WNetAddConnection2W [MPR.@]
1379 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1380 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1383 FIXME( "(%p, %p, %s, 0x%08X): stub\n",
1384 lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
);
1386 SetLastError(WN_NO_NETWORK
);
1387 return WN_NO_NETWORK
;
1390 /*********************************************************************
1391 * WNetAddConnection3A [MPR.@]
1393 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1394 LPCSTR lpPassword
, LPCSTR lpUserID
,
1397 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1398 hwndOwner
, lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
);
1400 SetLastError(WN_NO_NETWORK
);
1401 return WN_NO_NETWORK
;
1404 /*********************************************************************
1405 * WNetAddConnection3W [MPR.@]
1407 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1408 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1411 FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
1412 hwndOwner
, lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
);
1414 SetLastError(WN_NO_NETWORK
);
1415 return WN_NO_NETWORK
;
1418 /*****************************************************************
1419 * WNetUseConnectionA [MPR.@]
1421 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1422 LPCSTR lpPassword
, LPCSTR lpUserID
, DWORD dwFlags
,
1423 LPSTR lpAccessName
, LPDWORD lpBufferSize
,
1426 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1427 hwndOwner
, lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
,
1428 debugstr_a(lpAccessName
), lpBufferSize
, lpResult
);
1430 SetLastError(WN_NO_NETWORK
);
1431 return WN_NO_NETWORK
;
1434 /*****************************************************************
1435 * WNetUseConnectionW [MPR.@]
1437 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1438 LPCWSTR lpPassword
, LPCWSTR lpUserID
, DWORD dwFlags
,
1439 LPWSTR lpAccessName
, LPDWORD lpBufferSize
,
1442 FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
1443 hwndOwner
, lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
,
1444 debugstr_w(lpAccessName
), lpBufferSize
, lpResult
);
1446 SetLastError(WN_NO_NETWORK
);
1447 return WN_NO_NETWORK
;
1450 /*********************************************************************
1451 * WNetCancelConnectionA [MPR.@]
1453 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
1455 FIXME( "(%s, %d), stub\n", debugstr_a(lpName
), fForce
);
1460 /*********************************************************************
1461 * WNetCancelConnectionW [MPR.@]
1463 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
1465 FIXME( "(%s, %d), stub\n", debugstr_w(lpName
), fForce
);
1470 /*********************************************************************
1471 * WNetCancelConnection2A [MPR.@]
1473 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1475 FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName
), dwFlags
, fForce
);
1480 /*********************************************************************
1481 * WNetCancelConnection2W [MPR.@]
1483 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1485 FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName
), dwFlags
, fForce
);
1490 /*****************************************************************
1491 * WNetRestoreConnectionA [MPR.@]
1493 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
1495 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
1497 SetLastError(WN_NO_NETWORK
);
1498 return WN_NO_NETWORK
;
1501 /*****************************************************************
1502 * WNetRestoreConnectionW [MPR.@]
1504 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
1506 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
1508 SetLastError(WN_NO_NETWORK
);
1509 return WN_NO_NETWORK
;
1512 /**************************************************************************
1513 * WNetGetConnectionA [MPR.@]
1516 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1517 * - WN_NOT_CONNECTED drive is a local drive
1518 * - WN_MORE_DATA buffer isn't big enough
1519 * - WN_SUCCESS success (net path in buffer)
1521 * FIXME: need to test return values under different errors
1523 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
1524 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
1529 ret
= WN_BAD_POINTER
;
1530 else if (!lpBufferSize
)
1531 ret
= WN_BAD_POINTER
;
1532 else if (!lpRemoteName
&& *lpBufferSize
)
1533 ret
= WN_BAD_POINTER
;
1536 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
1540 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1544 WCHAR wideRemoteStatic
[MAX_PATH
];
1545 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
1547 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
1549 /* try once without memory allocation */
1550 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
1552 if (ret
== WN_SUCCESS
)
1554 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1555 -1, NULL
, 0, NULL
, NULL
);
1557 if (len
<= *lpBufferSize
)
1559 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
1560 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1565 *lpBufferSize
= len
;
1569 else if (ret
== WN_MORE_DATA
)
1571 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
1572 wideRemoteSize
* sizeof(WCHAR
));
1576 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
1578 if (ret
== WN_SUCCESS
)
1580 if (len
<= *lpBufferSize
)
1582 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1583 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1588 *lpBufferSize
= len
;
1592 HeapFree(GetProcessHeap(), 0, wideRemote
);
1595 ret
= WN_OUT_OF_MEMORY
;
1597 HeapFree(GetProcessHeap(), 0, wideLocalName
);
1600 ret
= WN_OUT_OF_MEMORY
;
1603 ret
= WN_BAD_LOCALNAME
;
1607 TRACE("Returning %d\n", ret
);
1611 /**************************************************************************
1612 * WNetGetConnectionW [MPR.@]
1614 * FIXME: need to test return values under different errors
1616 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
1617 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
1621 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
1625 ret
= WN_BAD_POINTER
;
1626 else if (!lpBufferSize
)
1627 ret
= WN_BAD_POINTER
;
1628 else if (!lpRemoteName
&& *lpBufferSize
)
1629 ret
= WN_BAD_POINTER
;
1630 else if (!lpLocalName
[0])
1631 ret
= WN_BAD_LOCALNAME
;
1634 if (lpLocalName
[1] == ':')
1636 switch(GetDriveTypeW(lpLocalName
))
1640 static const WCHAR unc
[] = { 'u','n','c','\\' };
1641 WCHAR rremote
[MAX_PATH
], *remote
= rremote
;
1642 if (!QueryDosDeviceW( lpLocalName
, remote
, MAX_PATH
)) remote
[0] = 0;
1643 else if (!strncmpW(remote
, unc
, 4))
1648 else if (remote
[0] != '\\' || remote
[1] != '\\')
1649 FIXME("Don't know how to convert %s to an unc\n", debugstr_w(remote
));
1651 if (strlenW(remote
) + 1 > *lpBufferSize
)
1653 *lpBufferSize
= strlenW(remote
) + 1;
1658 strcpyW( lpRemoteName
, remote
);
1659 *lpBufferSize
= strlenW(lpRemoteName
) + 1;
1664 case DRIVE_REMOVABLE
:
1667 TRACE("file is local\n");
1668 ret
= WN_NOT_CONNECTED
;
1671 ret
= WN_BAD_LOCALNAME
;
1675 ret
= WN_BAD_LOCALNAME
;
1679 TRACE("Returning %d\n", ret
);
1683 /**************************************************************************
1684 * WNetSetConnectionA [MPR.@]
1686 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
1689 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
1691 SetLastError(WN_NO_NETWORK
);
1692 return WN_NO_NETWORK
;
1695 /**************************************************************************
1696 * WNetSetConnectionW [MPR.@]
1698 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
1701 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
1703 SetLastError(WN_NO_NETWORK
);
1704 return WN_NO_NETWORK
;
1707 /*****************************************************************
1708 * WNetGetUniversalNameA [MPR.@]
1710 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
1711 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1715 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1716 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
1718 switch (dwInfoLevel
)
1720 case UNIVERSAL_NAME_INFO_LEVEL
:
1722 LPUNIVERSAL_NAME_INFOA info
= (LPUNIVERSAL_NAME_INFOA
)lpBuffer
;
1724 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
1725 if (*lpBufferSize
< size
)
1730 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
1731 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
1732 *lpBufferSize
= size
;
1736 case REMOTE_NAME_INFO_LEVEL
:
1737 err
= WN_NO_NETWORK
;
1749 /*****************************************************************
1750 * WNetGetUniversalNameW [MPR.@]
1752 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
1753 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1757 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
1758 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
1760 switch (dwInfoLevel
)
1762 case UNIVERSAL_NAME_INFO_LEVEL
:
1764 LPUNIVERSAL_NAME_INFOW info
= (LPUNIVERSAL_NAME_INFOW
)lpBuffer
;
1766 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
1767 if (*lpBufferSize
< size
)
1772 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
1773 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
1774 *lpBufferSize
= size
;
1778 case REMOTE_NAME_INFO_LEVEL
:
1779 err
= WN_NO_NETWORK
;
1797 /**************************************************************************
1798 * WNetGetUserA [MPR.@]
1800 * FIXME: we should not return ourselves, but the owner of the drive lpName
1802 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
1804 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
1805 return GetLastError();
1808 /*****************************************************************
1809 * WNetGetUserW [MPR.@]
1811 * FIXME: we should not return ourselves, but the owner of the drive lpName
1813 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
1815 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
1816 return GetLastError();
1819 /*********************************************************************
1820 * WNetConnectionDialog [MPR.@]
1822 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
1824 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
1826 SetLastError(WN_NO_NETWORK
);
1827 return WN_NO_NETWORK
;
1830 /*********************************************************************
1831 * WNetConnectionDialog1A [MPR.@]
1833 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
1835 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1837 SetLastError(WN_NO_NETWORK
);
1838 return WN_NO_NETWORK
;
1841 /*********************************************************************
1842 * WNetConnectionDialog1W [MPR.@]
1844 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
1846 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1848 SetLastError(WN_NO_NETWORK
);
1849 return WN_NO_NETWORK
;
1852 /*********************************************************************
1853 * WNetDisconnectDialog [MPR.@]
1855 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
1857 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
1859 SetLastError(WN_NO_NETWORK
);
1860 return WN_NO_NETWORK
;
1863 /*********************************************************************
1864 * WNetDisconnectDialog1A [MPR.@]
1866 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
1868 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1870 SetLastError(WN_NO_NETWORK
);
1871 return WN_NO_NETWORK
;
1874 /*********************************************************************
1875 * WNetDisconnectDialog1W [MPR.@]
1877 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
1879 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1881 SetLastError(WN_NO_NETWORK
);
1882 return WN_NO_NETWORK
;
1885 /*********************************************************************
1886 * WNetGetLastErrorA [MPR.@]
1888 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
1889 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
1890 LPSTR lpNameBuf
, DWORD nNameBufSize
)
1892 FIXME( "(%p, %p, %d, %p, %d): stub\n",
1893 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
1895 SetLastError(WN_NO_NETWORK
);
1896 return WN_NO_NETWORK
;
1899 /*********************************************************************
1900 * WNetGetLastErrorW [MPR.@]
1902 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
1903 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
1904 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
1906 FIXME( "(%p, %p, %d, %p, %d): stub\n",
1907 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
1909 SetLastError(WN_NO_NETWORK
);
1910 return WN_NO_NETWORK
;
1913 /*********************************************************************
1914 * WNetGetNetworkInformationA [MPR.@]
1916 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
1917 LPNETINFOSTRUCT lpNetInfoStruct
)
1921 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
1924 ret
= WN_BAD_POINTER
;
1929 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
1932 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1936 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
1938 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
1939 HeapFree(GetProcessHeap(), 0, wideProvider
);
1942 ret
= WN_OUT_OF_MEMORY
;
1945 ret
= GetLastError();
1949 TRACE("Returning %d\n", ret
);
1953 /*********************************************************************
1954 * WNetGetNetworkInformationW [MPR.@]
1956 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
1957 LPNETINFOSTRUCT lpNetInfoStruct
)
1961 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
1964 ret
= WN_BAD_POINTER
;
1965 else if (!lpNetInfoStruct
)
1966 ret
= WN_BAD_POINTER
;
1967 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
1971 if (providerTable
&& providerTable
->numProviders
)
1973 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
1975 if (providerIndex
!= BAD_PROVIDER_INDEX
)
1977 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
1978 lpNetInfoStruct
->dwProviderVersion
=
1979 providerTable
->table
[providerIndex
].dwSpecVersion
;
1980 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
1981 lpNetInfoStruct
->dwCharacteristics
= 0;
1982 lpNetInfoStruct
->dwHandle
= (ULONG_PTR
)NULL
;
1983 lpNetInfoStruct
->wNetType
=
1984 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
1985 lpNetInfoStruct
->dwPrinters
= -1;
1986 lpNetInfoStruct
->dwDrives
= -1;
1990 ret
= WN_BAD_PROVIDER
;
1993 ret
= WN_NO_NETWORK
;
1997 TRACE("Returning %d\n", ret
);
2001 /*****************************************************************
2002 * WNetGetProviderNameA [MPR.@]
2004 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2005 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2009 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2013 ret
= WN_BAD_POINTER
;
2014 else if (!lpBufferSize
)
2015 ret
= WN_BAD_POINTER
;
2022 ret
= WN_NO_NETWORK
;
2023 for (i
= 0; i
< providerTable
->numProviders
&&
2024 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2027 if (i
< providerTable
->numProviders
)
2029 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2030 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2032 if (*lpBufferSize
< sizeNeeded
)
2034 *lpBufferSize
= sizeNeeded
;
2039 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2040 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2042 /* FIXME: is *lpBufferSize set to the number of characters
2048 ret
= WN_NO_NETWORK
;
2052 TRACE("Returning %d\n", ret
);
2056 /*****************************************************************
2057 * WNetGetProviderNameW [MPR.@]
2059 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2060 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2064 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2068 ret
= WN_BAD_POINTER
;
2069 else if (!lpBufferSize
)
2070 ret
= WN_BAD_POINTER
;
2077 ret
= WN_NO_NETWORK
;
2078 for (i
= 0; i
< providerTable
->numProviders
&&
2079 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2082 if (i
< providerTable
->numProviders
)
2084 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2086 if (*lpBufferSize
< sizeNeeded
)
2088 *lpBufferSize
= sizeNeeded
;
2093 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2095 /* FIXME: is *lpBufferSize set to the number of characters
2101 ret
= WN_NO_NETWORK
;
2105 TRACE("Returning %d\n", ret
);