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
= (PWSTR
)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
));
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
= (PWSTR
)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
, ',');
267 providerTable
= (PWNetProviderTable
)
268 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
269 sizeof(WNetProviderTable
)
270 + (numToAllocate
- 1) * sizeof(WNetProvider
));
274 int entireNetworkLen
;
276 entireNetworkLen
= LoadStringW(hInstDll
,
277 IDS_ENTIRENETWORK
, NULL
, 0);
278 providerTable
->entireNetwork
= (LPWSTR
)HeapAlloc(
279 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
281 if (providerTable
->entireNetwork
)
282 LoadStringW(hInstDll
, IDS_ENTIRENETWORK
,
283 providerTable
->entireNetwork
,
284 entireNetworkLen
+ 1);
285 providerTable
->numAllocated
= numToAllocate
;
286 for (ptr
= providers
; ptr
; )
289 ptr
= strchrW(ptr
, ',');
292 _tryLoadProvider(ptrPrev
);
296 HeapFree(GetProcessHeap(), 0, providers
);
309 for (i
= 0; i
< providerTable
->numProviders
; i
++)
311 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
312 FreeModule(providerTable
->table
[i
].hLib
);
314 if (providerTable
->entireNetwork
)
315 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
316 HeapFree(GetProcessHeap(), 0, providerTable
);
317 providerTable
= NULL
;
321 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
323 DWORD ret
= BAD_PROVIDER_INDEX
;
325 if (providerTable
&& providerTable
->numProviders
)
329 for (i
= 0; i
< providerTable
->numProviders
&&
330 ret
== BAD_PROVIDER_INDEX
; i
++)
331 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
341 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
347 ret
= (LPNETRESOURCEW
)HeapAlloc(GetProcessHeap(), 0,
348 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
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0,
359 len
* sizeof(WCHAR
));
360 if (ret
->lpRemoteName
)
361 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
370 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
374 if (lpNet
->lpRemoteName
)
375 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
376 HeapFree(GetProcessHeap(), 0, lpNet
);
380 static PWNetEnumerator
_createNullEnumerator(void)
382 PWNetEnumerator ret
= (PWNetEnumerator
)HeapAlloc(GetProcessHeap(),
383 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
386 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
390 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
391 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
393 PWNetEnumerator ret
= (PWNetEnumerator
)HeapAlloc(GetProcessHeap(),
394 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
398 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
399 ret
->dwScope
= dwScope
;
400 ret
->dwType
= dwType
;
401 ret
->dwUsage
= dwUsage
;
402 ret
->lpNet
= _copyNetResourceForEnumW(lpNet
);
407 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
408 DWORD dwUsage
, DWORD index
, HANDLE handle
)
412 if (!providerTable
|| index
>= providerTable
->numProviders
)
416 ret
= (PWNetEnumerator
)HeapAlloc(GetProcessHeap(),
417 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
420 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
421 ret
->providerIndex
= index
;
422 ret
->dwScope
= dwScope
;
423 ret
->dwType
= dwType
;
424 ret
->dwUsage
= dwUsage
;
425 ret
->handle
= handle
;
431 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
434 PWNetEnumerator ret
= (PWNetEnumerator
)HeapAlloc(GetProcessHeap(),
435 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
439 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
440 ret
->dwScope
= dwScope
;
441 ret
->dwType
= dwType
;
442 ret
->dwUsage
= dwUsage
;
447 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
448 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
449 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
450 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
451 * if not all members of the array could be thunked, and something else on
454 static DWORD
_thunkNetResourceArrayWToA(const LPNETRESOURCEW lpNetArrayIn
,
455 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
457 DWORD i
, numToThunk
, totalBytes
, ret
;
461 return WN_BAD_POINTER
;
463 return WN_BAD_POINTER
;
467 return WN_BAD_POINTER
;
469 return WN_BAD_POINTER
;
471 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
473 LPNETRESOURCEW lpNet
= lpNetArrayIn
+ i
;
475 totalBytes
+= sizeof(NETRESOURCEA
);
476 if (lpNet
->lpLocalName
)
477 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
478 -1, NULL
, 0, NULL
, NULL
);
479 if (lpNet
->lpRemoteName
)
480 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
481 -1, NULL
, 0, NULL
, NULL
);
482 if (lpNet
->lpComment
)
483 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
484 -1, NULL
, 0, NULL
, NULL
);
485 if (lpNet
->lpProvider
)
486 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
487 -1, NULL
, 0, NULL
, NULL
);
488 if (totalBytes
< *lpBufferSize
)
491 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
492 for (i
= 0; i
< numToThunk
; i
++)
494 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
495 LPNETRESOURCEW lpNetIn
= lpNetArrayIn
+ i
;
497 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
498 /* lie about string lengths, we already verified how many
499 * we have space for above
501 if (lpNetIn
->lpLocalName
)
503 lpNetOut
->lpLocalName
= strNext
;
504 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
505 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
507 if (lpNetIn
->lpRemoteName
)
509 lpNetOut
->lpRemoteName
= strNext
;
510 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
511 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
513 if (lpNetIn
->lpComment
)
515 lpNetOut
->lpComment
= strNext
;
516 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
517 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
519 if (lpNetIn
->lpProvider
)
521 lpNetOut
->lpProvider
= strNext
;
522 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
523 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
526 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
527 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk
,
532 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
533 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
534 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
535 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
536 * if not all members of the array could be thunked, and something else on
539 static DWORD
_thunkNetResourceArrayAToW(const LPNETRESOURCEA lpNetArrayIn
,
540 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
542 DWORD i
, numToThunk
, totalBytes
, ret
;
546 return WN_BAD_POINTER
;
548 return WN_BAD_POINTER
;
552 return WN_BAD_POINTER
;
554 return WN_BAD_POINTER
;
556 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
558 LPNETRESOURCEA lpNet
= lpNetArrayIn
+ i
;
560 totalBytes
+= sizeof(NETRESOURCEW
);
561 if (lpNet
->lpLocalName
)
562 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
563 -1, NULL
, 0) * sizeof(WCHAR
);
564 if (lpNet
->lpRemoteName
)
565 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
566 -1, NULL
, 0) * sizeof(WCHAR
);
567 if (lpNet
->lpComment
)
568 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
569 -1, NULL
, 0) * sizeof(WCHAR
);
570 if (lpNet
->lpProvider
)
571 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
572 -1, NULL
, 0) * sizeof(WCHAR
);
573 if (totalBytes
< *lpBufferSize
)
576 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
577 for (i
= 0; i
< numToThunk
; i
++)
579 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
580 LPNETRESOURCEA lpNetIn
= lpNetArrayIn
+ i
;
582 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
583 /* lie about string lengths, we already verified how many
584 * we have space for above
586 if (lpNetIn
->lpLocalName
)
588 lpNetOut
->lpLocalName
= strNext
;
589 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
590 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
592 if (lpNetIn
->lpRemoteName
)
594 lpNetOut
->lpRemoteName
= strNext
;
595 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
596 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
598 if (lpNetIn
->lpComment
)
600 lpNetOut
->lpComment
= strNext
;
601 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
602 -1, lpNetOut
->lpComment
, *lpBufferSize
);
604 if (lpNetIn
->lpProvider
)
606 lpNetOut
->lpProvider
= strNext
;
607 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
608 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
611 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
612 TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk
,
617 /*********************************************************************
618 * WNetOpenEnumA [MPR.@]
620 * See comments for WNetOpenEnumW.
622 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
623 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
627 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
628 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
631 ret
= WN_BAD_POINTER
;
632 else if (!providerTable
|| providerTable
->numProviders
== 0)
638 LPNETRESOURCEW lpNetWide
= NULL
;
640 DWORD size
= sizeof(buf
), count
= 1;
641 BOOL allocated
= FALSE
;
643 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
644 if (ret
== WN_MORE_DATA
)
646 lpNetWide
= (LPNETRESOURCEW
)HeapAlloc(GetProcessHeap(), 0,
650 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
655 ret
= WN_OUT_OF_MEMORY
;
657 else if (ret
== WN_SUCCESS
)
658 lpNetWide
= (LPNETRESOURCEW
)buf
;
659 if (ret
== WN_SUCCESS
)
660 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
662 if (allocated
&& lpNetWide
)
663 HeapFree(GetProcessHeap(), 0, lpNetWide
);
666 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
670 TRACE("Returning %ld\n", ret
);
674 /*********************************************************************
675 * WNetOpenEnumW [MPR.@]
677 * Network enumeration has way too many parameters, so I'm not positive I got
678 * them right. What I've got so far:
680 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
681 * all the network providers should be enumerated.
683 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
684 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
685 * lpProvider is set, all the network providers should be enumerated.
686 * (This means the enumeration is a list of network providers, not that the
687 * enumeration is passed on to the providers.)
689 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
690 * resource matches the "Entire Network" resource (no remote name, no
691 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
692 * enumeration is done on every network provider.
694 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
695 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
696 * only to the given network provider.
698 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
699 * no lpProvider is set, enumeration will be tried on every network provider,
700 * in the order in which they're loaded.
702 * - The LPNETRESOURCE should be disregarded for scopes besides
703 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
704 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
706 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
707 * resource in the enumerated list, as well as any machines in your
708 * workgroup. The machines in your workgroup come from doing a
709 * RESOURCE_CONTEXT enumeration of every Network Provider.
711 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
712 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
716 TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n",
717 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
720 ret
= WN_BAD_POINTER
;
721 else if (!providerTable
|| providerTable
->numProviders
== 0)
727 case RESOURCE_GLOBALNET
:
730 if (lpNet
->lpProvider
)
732 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
734 if (index
!= BAD_PROVIDER_INDEX
)
736 if (providerTable
->table
[index
].openEnum
&&
737 providerTable
->table
[index
].dwEnumScopes
& dwScope
)
741 ret
= providerTable
->table
[index
].openEnum(
742 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
743 if (ret
== WN_SUCCESS
)
746 (HANDLE
)_createProviderEnumerator(
747 dwScope
, dwType
, dwUsage
, index
, handle
);
748 ret
= *lphEnum
? WN_SUCCESS
:
753 ret
= WN_NOT_SUPPORTED
;
756 ret
= WN_BAD_PROVIDER
;
758 else if (lpNet
->lpRemoteName
)
760 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
,
761 dwType
, dwUsage
, lpNet
);
762 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
766 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
767 providerTable
->entireNetwork
))
769 /* comment matches the "Entire Network", enumerate
770 * global scope of every provider
772 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
,
773 dwType
, dwUsage
, lpNet
);
777 /* this is the same as not having passed lpNet */
778 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
,
779 dwType
, dwUsage
, NULL
);
781 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
786 *lphEnum
= (HANDLE
)_createGlobalEnumeratorW(dwScope
, dwType
,
788 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
791 case RESOURCE_CONTEXT
:
792 *lphEnum
= (HANDLE
)_createContextEnumerator(dwScope
, dwType
,
794 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
796 case RESOURCE_REMEMBERED
:
797 case RESOURCE_CONNECTED
:
798 *lphEnum
= (HANDLE
)_createNullEnumerator();
799 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
802 WARN("unknown scope 0x%08lx\n", dwScope
);
808 TRACE("Returning %ld\n", ret
);
812 /*********************************************************************
813 * WNetEnumResourceA [MPR.@]
815 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
816 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
820 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
823 ret
= WN_BAD_POINTER
;
825 ret
= WN_BAD_POINTER
;
827 ret
= WN_BAD_POINTER
;
828 else if (!lpBufferSize
)
829 ret
= WN_BAD_POINTER
;
830 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
832 *lpBufferSize
= sizeof(NETRESOURCEA
);
837 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
838 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
842 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
844 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
846 /* FIXME: this isn't necessarily going to work in the case of
847 * WN_MORE_DATA, because our enumerator may have moved on to
848 * the next provider. MSDN states that a large (16KB) buffer
849 * size is the appropriate usage of this function, so
850 * hopefully it won't be an issue.
852 ret
= _thunkNetResourceArrayWToA((LPNETRESOURCEW
)localBuffer
,
853 &localCount
, lpBuffer
, lpBufferSize
);
854 *lpcCount
= localCount
;
856 HeapFree(GetProcessHeap(), 0, localBuffer
);
859 ret
= WN_OUT_OF_MEMORY
;
863 TRACE("Returning %ld\n", ret
);
867 static DWORD
_countProviderBytesW(PWNetProvider provider
)
873 ret
= sizeof(NETRESOURCEW
);
874 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
881 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
882 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
887 return WN_BAD_POINTER
;
888 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
891 return WN_BAD_POINTER
;
893 return WN_BAD_POINTER
;
895 return WN_BAD_POINTER
;
896 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
899 if (!providerTable
|| enumerator
->providerIndex
>=
900 providerTable
->numProviders
)
901 ret
= WN_NO_MORE_ENTRIES
;
904 DWORD bytes
= 0, count
= 0, countLimit
, i
;
905 LPNETRESOURCEW resource
;
908 countLimit
= *lpcCount
== -1 ?
909 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
910 while (count
< countLimit
&& bytes
< *lpBufferSize
)
912 DWORD bytesNext
= _countProviderBytesW(
913 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
915 if (bytes
+ bytesNext
< *lpBufferSize
)
921 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
922 for (i
= 0, resource
= (LPNETRESOURCEW
)lpBuffer
; i
< count
;
925 resource
->dwScope
= RESOURCE_GLOBALNET
;
926 resource
->dwType
= RESOURCETYPE_ANY
;
927 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
928 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
929 RESOURCEUSAGE_RESERVED
;
930 resource
->lpLocalName
= NULL
;
931 resource
->lpRemoteName
= strNext
;
932 strcpyW(resource
->lpRemoteName
,
933 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
934 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
935 resource
->lpComment
= NULL
;
936 resource
->lpProvider
= strNext
;
937 strcpyW(resource
->lpProvider
,
938 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
939 strNext
+= strlenW(resource
->lpProvider
) + 1;
941 enumerator
->providerIndex
+= count
;
943 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
945 TRACE("Returning %ld\n", ret
);
949 /* Advances the enumerator (assumed to be a global enumerator) to the next
950 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
951 * not open a handle with the next provider.
952 * If the existing handle is NULL, may leave the enumerator unchanged, since
953 * the current provider may support the desired scope.
954 * If the existing handle is not NULL, closes it before moving on.
955 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
956 * provider, and another error on failure.
958 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
961 return WN_BAD_POINTER
;
962 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
964 if (!providerTable
|| enumerator
->providerIndex
>=
965 providerTable
->numProviders
)
966 return WN_NO_MORE_ENTRIES
;
968 if (enumerator
->providerDone
)
970 enumerator
->providerDone
= FALSE
;
971 if (enumerator
->handle
)
973 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
975 enumerator
->handle
= NULL
;
976 enumerator
->providerIndex
++;
978 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
979 !(enumerator
->dwScope
& providerTable
->table
980 [enumerator
->providerIndex
].dwEnumScopes
);
981 enumerator
->providerIndex
++)
984 return enumerator
->providerIndex
< providerTable
->numProviders
?
985 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
988 /* "Passes through" call to the next provider that supports the enumeration
990 * FIXME: if one call to a provider's enumerator succeeds while there's still
991 * space in lpBuffer, I don't call to the next provider. The caller may not
992 * expect that it should call EnumResourceW again with a return value of
993 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
994 * may have to be moved around a bit, ick.
996 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
997 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1002 return WN_BAD_POINTER
;
1003 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1004 return WN_BAD_VALUE
;
1006 return WN_BAD_POINTER
;
1008 return WN_BAD_POINTER
;
1010 return WN_BAD_POINTER
;
1011 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1012 return WN_MORE_DATA
;
1014 ret
= _globalEnumeratorAdvance(enumerator
);
1015 if (ret
== WN_SUCCESS
)
1017 ret
= providerTable
->table
[enumerator
->providerIndex
].
1018 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1019 enumerator
->dwUsage
, enumerator
->lpNet
,
1020 &enumerator
->handle
);
1021 if (ret
== WN_SUCCESS
)
1023 ret
= providerTable
->table
[enumerator
->providerIndex
].
1024 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1026 if (ret
!= WN_MORE_DATA
)
1027 enumerator
->providerDone
= TRUE
;
1030 TRACE("Returning %ld\n", ret
);
1034 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1035 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1040 return WN_BAD_POINTER
;
1041 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1042 return WN_BAD_VALUE
;
1044 return WN_BAD_POINTER
;
1046 return WN_BAD_POINTER
;
1048 return WN_BAD_POINTER
;
1049 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1050 return WN_MORE_DATA
;
1052 return WN_NO_NETWORK
;
1054 switch (enumerator
->dwScope
)
1056 case RESOURCE_GLOBALNET
:
1057 if (enumerator
->lpNet
)
1058 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1059 lpBuffer
, lpBufferSize
);
1061 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1064 case RESOURCE_CONTEXT
:
1065 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1069 WARN("unexpected scope 0x%08lx\n", enumerator
->dwScope
);
1070 ret
= WN_NO_MORE_ENTRIES
;
1072 TRACE("Returning %ld\n", ret
);
1076 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1077 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1080 return WN_BAD_POINTER
;
1081 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1082 return WN_BAD_VALUE
;
1083 if (!enumerator
->handle
)
1084 return WN_BAD_VALUE
;
1086 return WN_BAD_POINTER
;
1088 return WN_BAD_POINTER
;
1090 return WN_BAD_POINTER
;
1092 return WN_NO_NETWORK
;
1093 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1094 return WN_NO_MORE_ENTRIES
;
1095 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1096 return WN_BAD_VALUE
;
1097 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1098 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1101 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1102 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1105 size_t cchEntireNetworkLen
, bytesNeeded
;
1108 return WN_BAD_POINTER
;
1109 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1110 return WN_BAD_VALUE
;
1112 return WN_BAD_POINTER
;
1114 return WN_BAD_POINTER
;
1116 return WN_BAD_POINTER
;
1118 return WN_NO_NETWORK
;
1120 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1121 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1122 if (*lpBufferSize
< bytesNeeded
)
1124 *lpBufferSize
= bytesNeeded
;
1129 LPNETRESOURCEW lpNet
= (LPNETRESOURCEW
)lpBuffer
;
1131 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1132 lpNet
->dwType
= enumerator
->dwType
;
1133 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1134 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1135 lpNet
->lpLocalName
= NULL
;
1136 lpNet
->lpRemoteName
= NULL
;
1137 lpNet
->lpProvider
= NULL
;
1138 /* odd, but correct: put comment at end of buffer, so it won't get
1139 * overwritten by subsequent calls to a provider's enumResource
1141 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1142 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1143 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1146 if (ret
== WN_SUCCESS
)
1148 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1150 /* "Entire Network" entry enumerated--morph this into a global
1151 * enumerator. enumerator->lpNet continues to be NULL, since it has
1152 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1154 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1155 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1156 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1157 if (ret
== WN_SUCCESS
)
1159 /* reflect the fact that we already enumerated "Entire Network" */
1161 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1165 /* the provider enumeration failed, but we already succeeded in
1166 * enumerating "Entire Network"--leave type as global to allow a
1167 * retry, but indicate success with a count of one.
1171 *lpBufferSize
= bytesNeeded
;
1174 TRACE("Returning %ld\n", ret
);
1178 /*********************************************************************
1179 * WNetEnumResourceW [MPR.@]
1181 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1182 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1186 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1189 ret
= WN_BAD_POINTER
;
1191 ret
= WN_BAD_POINTER
;
1193 ret
= WN_BAD_POINTER
;
1194 else if (!lpBufferSize
)
1195 ret
= WN_BAD_POINTER
;
1196 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1198 *lpBufferSize
= sizeof(NETRESOURCEW
);
1203 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1205 switch (enumerator
->enumType
)
1207 case WNET_ENUMERATOR_TYPE_NULL
:
1208 ret
= WN_NO_MORE_ENTRIES
;
1210 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1211 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1214 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1215 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1218 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1219 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1223 WARN("bogus enumerator type!\n");
1224 ret
= WN_NO_NETWORK
;
1229 TRACE("Returning %ld\n", ret
);
1233 /*********************************************************************
1234 * WNetCloseEnum [MPR.@]
1236 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1240 TRACE( "(%p)\n", hEnum
);
1244 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1246 switch (enumerator
->enumType
)
1248 case WNET_ENUMERATOR_TYPE_NULL
:
1251 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1252 if (enumerator
->lpNet
)
1253 _freeEnumNetResource(enumerator
->lpNet
);
1254 if (enumerator
->handle
)
1255 providerTable
->table
[enumerator
->providerIndex
].
1256 closeEnum(enumerator
->handle
);
1259 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1260 if (enumerator
->handle
)
1261 providerTable
->table
[enumerator
->providerIndex
].
1262 closeEnum(enumerator
->handle
);
1266 WARN("bogus enumerator type!\n");
1267 ret
= WN_BAD_HANDLE
;
1269 HeapFree(GetProcessHeap(), 0, hEnum
);
1272 ret
= WN_BAD_HANDLE
;
1275 TRACE("Returning %ld\n", ret
);
1279 /*********************************************************************
1280 * WNetGetResourceInformationA [MPR.@]
1282 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1283 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1286 FIXME( "(%p, %p, %p, %p): stub\n",
1287 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1289 SetLastError(WN_NO_NETWORK
);
1290 return WN_NO_NETWORK
;
1293 /*********************************************************************
1294 * WNetGetResourceInformationW [MPR.@]
1296 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1297 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1298 LPWSTR
*lplpSystem
)
1300 FIXME( "(%p, %p, %p, %p): stub\n",
1301 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1303 SetLastError(WN_NO_NETWORK
);
1304 return WN_NO_NETWORK
;
1307 /*********************************************************************
1308 * WNetGetResourceParentA [MPR.@]
1310 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1311 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1313 FIXME( "(%p, %p, %p): stub\n",
1314 lpNetResource
, lpBuffer
, lpBufferSize
);
1316 SetLastError(WN_NO_NETWORK
);
1317 return WN_NO_NETWORK
;
1320 /*********************************************************************
1321 * WNetGetResourceParentW [MPR.@]
1323 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1324 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1326 FIXME( "(%p, %p, %p): stub\n",
1327 lpNetResource
, lpBuffer
, lpBufferSize
);
1329 SetLastError(WN_NO_NETWORK
);
1330 return WN_NO_NETWORK
;
1336 * Connection Functions
1339 /*********************************************************************
1340 * WNetAddConnectionA [MPR.@]
1342 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1343 LPCSTR lpLocalName
)
1345 FIXME( "(%s, %p, %s): stub\n",
1346 debugstr_a(lpRemoteName
), lpPassword
, debugstr_a(lpLocalName
) );
1348 SetLastError(WN_NO_NETWORK
);
1349 return WN_NO_NETWORK
;
1352 /*********************************************************************
1353 * WNetAddConnectionW [MPR.@]
1355 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1356 LPCWSTR lpLocalName
)
1358 FIXME( "(%s, %p, %s): stub\n",
1359 debugstr_w(lpRemoteName
), lpPassword
, debugstr_w(lpLocalName
) );
1361 SetLastError(WN_NO_NETWORK
);
1362 return WN_NO_NETWORK
;
1365 /*********************************************************************
1366 * WNetAddConnection2A [MPR.@]
1368 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1369 LPCSTR lpPassword
, LPCSTR lpUserID
,
1372 FIXME( "(%p, %p, %s, 0x%08lX): stub\n",
1373 lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
);
1375 SetLastError(WN_NO_NETWORK
);
1376 return WN_NO_NETWORK
;
1379 /*********************************************************************
1380 * WNetAddConnection2W [MPR.@]
1382 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1383 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1386 FIXME( "(%p, %p, %s, 0x%08lX): stub\n",
1387 lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
);
1389 SetLastError(WN_NO_NETWORK
);
1390 return WN_NO_NETWORK
;
1393 /*********************************************************************
1394 * WNetAddConnection3A [MPR.@]
1396 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1397 LPCSTR lpPassword
, LPCSTR lpUserID
,
1400 FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n",
1401 hwndOwner
, lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
);
1403 SetLastError(WN_NO_NETWORK
);
1404 return WN_NO_NETWORK
;
1407 /*********************************************************************
1408 * WNetAddConnection3W [MPR.@]
1410 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1411 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1414 FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n",
1415 hwndOwner
, lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
);
1417 SetLastError(WN_NO_NETWORK
);
1418 return WN_NO_NETWORK
;
1421 /*****************************************************************
1422 * WNetUseConnectionA [MPR.@]
1424 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1425 LPCSTR lpPassword
, LPCSTR lpUserID
, DWORD dwFlags
,
1426 LPSTR lpAccessName
, LPDWORD lpBufferSize
,
1429 FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n",
1430 hwndOwner
, lpNetResource
, lpPassword
, debugstr_a(lpUserID
), dwFlags
,
1431 debugstr_a(lpAccessName
), lpBufferSize
, lpResult
);
1433 SetLastError(WN_NO_NETWORK
);
1434 return WN_NO_NETWORK
;
1437 /*****************************************************************
1438 * WNetUseConnectionW [MPR.@]
1440 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1441 LPCWSTR lpPassword
, LPCWSTR lpUserID
, DWORD dwFlags
,
1442 LPWSTR lpAccessName
, LPDWORD lpBufferSize
,
1445 FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n",
1446 hwndOwner
, lpNetResource
, lpPassword
, debugstr_w(lpUserID
), dwFlags
,
1447 debugstr_w(lpAccessName
), lpBufferSize
, lpResult
);
1449 SetLastError(WN_NO_NETWORK
);
1450 return WN_NO_NETWORK
;
1453 /*********************************************************************
1454 * WNetCancelConnectionA [MPR.@]
1456 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
1458 FIXME( "(%s, %d), stub\n", debugstr_a(lpName
), fForce
);
1463 /*********************************************************************
1464 * WNetCancelConnectionW [MPR.@]
1466 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
1468 FIXME( "(%s, %d), stub\n", debugstr_w(lpName
), fForce
);
1473 /*********************************************************************
1474 * WNetCancelConnection2A [MPR.@]
1476 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1478 FIXME( "(%s, %08lX, %d), stub\n", debugstr_a(lpName
), dwFlags
, fForce
);
1483 /*********************************************************************
1484 * WNetCancelConnection2W [MPR.@]
1486 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1488 FIXME( "(%s, %08lX, %d), stub\n", debugstr_w(lpName
), dwFlags
, fForce
);
1493 /*****************************************************************
1494 * WNetRestoreConnectionA [MPR.@]
1496 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPSTR lpszDevice
)
1498 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
1500 SetLastError(WN_NO_NETWORK
);
1501 return WN_NO_NETWORK
;
1504 /*****************************************************************
1505 * WNetRestoreConnectionW [MPR.@]
1507 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPWSTR lpszDevice
)
1509 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
1511 SetLastError(WN_NO_NETWORK
);
1512 return WN_NO_NETWORK
;
1515 /**************************************************************************
1516 * WNetGetConnectionA [MPR.@]
1519 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1520 * - WN_NOT_CONNECTED drive is a local drive
1521 * - WN_MORE_DATA buffer isn't big enough
1522 * - WN_SUCCESS success (net path in buffer)
1524 * FIXME: need to test return values under different errors
1526 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
1527 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
1532 ret
= WN_BAD_POINTER
;
1533 else if (!lpRemoteName
)
1534 ret
= WN_BAD_POINTER
;
1535 else if (!lpBufferSize
)
1536 ret
= WN_BAD_POINTER
;
1539 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
1543 PWSTR wideLocalName
= (PWSTR
)HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1547 WCHAR wideRemoteStatic
[MAX_PATH
];
1548 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
1550 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
1552 /* try once without memory allocation */
1553 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
1555 if (ret
== WN_SUCCESS
)
1557 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1558 -1, NULL
, 0, NULL
, NULL
);
1560 if (len
<= *lpBufferSize
)
1562 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
1563 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1568 *lpBufferSize
= len
;
1572 else if (ret
== WN_MORE_DATA
)
1574 PWSTR wideRemote
= (PWSTR
)HeapAlloc(GetProcessHeap(), 0,
1575 wideRemoteSize
* sizeof(WCHAR
));
1579 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
1581 if (ret
== WN_SUCCESS
)
1583 if (len
<= *lpBufferSize
)
1585 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1586 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1591 *lpBufferSize
= len
;
1595 HeapFree(GetProcessHeap(), 0, wideRemote
);
1598 ret
= WN_OUT_OF_MEMORY
;
1600 HeapFree(GetProcessHeap(), 0, wideLocalName
);
1603 ret
= WN_OUT_OF_MEMORY
;
1606 ret
= WN_BAD_LOCALNAME
;
1610 TRACE("Returning %ld\n", ret
);
1614 /**************************************************************************
1615 * WNetGetConnectionW [MPR.@]
1617 * FIXME: need to test return values under different errors
1619 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
1620 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
1624 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
1628 ret
= WN_BAD_POINTER
;
1629 else if (!lpRemoteName
)
1630 ret
= WN_BAD_POINTER
;
1631 else if (!lpBufferSize
)
1632 ret
= WN_BAD_POINTER
;
1633 else if (!lpLocalName
[0])
1634 ret
= WN_BAD_LOCALNAME
;
1637 if (lpLocalName
[1] == ':')
1639 switch(GetDriveTypeW(lpLocalName
))
1643 WCHAR remote
[MAX_PATH
];
1644 if (!QueryDosDeviceW( lpLocalName
, remote
, MAX_PATH
)) remote
[0] = 0;
1645 if (strlenW(remote
) + 1 > *lpBufferSize
)
1647 *lpBufferSize
= strlenW(remote
) + 1;
1652 strcpyW( lpRemoteName
, remote
);
1653 *lpBufferSize
= strlenW(lpRemoteName
) + 1;
1658 case DRIVE_REMOVABLE
:
1661 TRACE("file is local\n");
1662 ret
= WN_NOT_CONNECTED
;
1665 ret
= WN_BAD_LOCALNAME
;
1669 ret
= WN_BAD_LOCALNAME
;
1673 TRACE("Returning %ld\n", ret
);
1677 /**************************************************************************
1678 * WNetSetConnectionA [MPR.@]
1680 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
1683 FIXME( "(%s, %08lX, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
1685 SetLastError(WN_NO_NETWORK
);
1686 return WN_NO_NETWORK
;
1689 /**************************************************************************
1690 * WNetSetConnectionW [MPR.@]
1692 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
1695 FIXME( "(%s, %08lX, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
1697 SetLastError(WN_NO_NETWORK
);
1698 return WN_NO_NETWORK
;
1701 /*****************************************************************
1702 * WNetGetUniversalNameA [MPR.@]
1704 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
1705 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1707 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
1708 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
1710 SetLastError(WN_NO_NETWORK
);
1711 return WN_NO_NETWORK
;
1714 /*****************************************************************
1715 * WNetGetUniversalNameW [MPR.@]
1717 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
1718 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1720 FIXME( "(%s, 0x%08lX, %p, %p): stub\n",
1721 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
1723 SetLastError(WN_NO_NETWORK
);
1724 return WN_NO_NETWORK
;
1733 /**************************************************************************
1734 * WNetGetUserA [MPR.@]
1736 * FIXME: we should not return ourselves, but the owner of the drive lpName
1738 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
1740 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
1741 return GetLastError();
1744 /*****************************************************************
1745 * WNetGetUserW [MPR.@]
1747 * FIXME: we should not return ourselves, but the owner of the drive lpName
1749 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
1751 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
1752 return GetLastError();
1755 /*********************************************************************
1756 * WNetConnectionDialog [MPR.@]
1758 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
1760 FIXME( "(%p, %08lX): stub\n", hwnd
, dwType
);
1762 SetLastError(WN_NO_NETWORK
);
1763 return WN_NO_NETWORK
;
1766 /*********************************************************************
1767 * WNetConnectionDialog1A [MPR.@]
1769 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
1771 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1773 SetLastError(WN_NO_NETWORK
);
1774 return WN_NO_NETWORK
;
1777 /*********************************************************************
1778 * WNetConnectionDialog1W [MPR.@]
1780 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
1782 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1784 SetLastError(WN_NO_NETWORK
);
1785 return WN_NO_NETWORK
;
1788 /*********************************************************************
1789 * WNetDisconnectDialog [MPR.@]
1791 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
1793 FIXME( "(%p, %08lX): stub\n", hwnd
, dwType
);
1795 SetLastError(WN_NO_NETWORK
);
1796 return WN_NO_NETWORK
;
1799 /*********************************************************************
1800 * WNetDisconnectDialog1A [MPR.@]
1802 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
1804 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1806 SetLastError(WN_NO_NETWORK
);
1807 return WN_NO_NETWORK
;
1810 /*********************************************************************
1811 * WNetDisconnectDialog1W [MPR.@]
1813 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
1815 FIXME( "(%p): stub\n", lpConnDlgStruct
);
1817 SetLastError(WN_NO_NETWORK
);
1818 return WN_NO_NETWORK
;
1821 /*********************************************************************
1822 * WNetGetLastErrorA [MPR.@]
1824 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
1825 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
1826 LPSTR lpNameBuf
, DWORD nNameBufSize
)
1828 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
1829 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
1831 SetLastError(WN_NO_NETWORK
);
1832 return WN_NO_NETWORK
;
1835 /*********************************************************************
1836 * WNetGetLastErrorW [MPR.@]
1838 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
1839 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
1840 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
1842 FIXME( "(%p, %p, %ld, %p, %ld): stub\n",
1843 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
1845 SetLastError(WN_NO_NETWORK
);
1846 return WN_NO_NETWORK
;
1849 /*********************************************************************
1850 * WNetGetNetworkInformationA [MPR.@]
1852 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
1853 LPNETINFOSTRUCT lpNetInfoStruct
)
1857 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
1860 ret
= WN_BAD_POINTER
;
1865 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
1868 LPWSTR wideProvider
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0,
1869 len
* sizeof(WCHAR
));
1873 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
1875 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
1876 HeapFree(GetProcessHeap(), 0, wideProvider
);
1879 ret
= WN_OUT_OF_MEMORY
;
1882 ret
= GetLastError();
1886 TRACE("Returning %ld\n", ret
);
1890 /*********************************************************************
1891 * WNetGetNetworkInformationW [MPR.@]
1893 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
1894 LPNETINFOSTRUCT lpNetInfoStruct
)
1898 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
1901 ret
= WN_BAD_POINTER
;
1902 else if (!lpNetInfoStruct
)
1903 ret
= WN_BAD_POINTER
;
1904 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
1908 if (providerTable
&& providerTable
->numProviders
)
1910 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
1912 if (providerIndex
!= BAD_PROVIDER_INDEX
)
1914 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
1915 lpNetInfoStruct
->dwProviderVersion
=
1916 providerTable
->table
[providerIndex
].dwSpecVersion
;
1917 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
1918 lpNetInfoStruct
->dwCharacteristics
= 0;
1919 lpNetInfoStruct
->dwHandle
= (ULONG_PTR
)NULL
;
1920 lpNetInfoStruct
->wNetType
=
1921 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
1922 lpNetInfoStruct
->dwPrinters
= -1;
1923 lpNetInfoStruct
->dwDrives
= -1;
1927 ret
= WN_BAD_PROVIDER
;
1930 ret
= WN_NO_NETWORK
;
1934 TRACE("Returning %ld\n", ret
);
1938 /*****************************************************************
1939 * WNetGetProviderNameA [MPR.@]
1941 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
1942 LPSTR lpProvider
, LPDWORD lpBufferSize
)
1946 TRACE("(0x%08lx, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
1950 ret
= WN_BAD_POINTER
;
1951 else if (!lpBufferSize
)
1952 ret
= WN_BAD_POINTER
;
1959 ret
= WN_NO_NETWORK
;
1960 for (i
= 0; i
< providerTable
->numProviders
&&
1961 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
1964 if (i
< providerTable
->numProviders
)
1966 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
1967 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
1969 if (*lpBufferSize
< sizeNeeded
)
1971 *lpBufferSize
= sizeNeeded
;
1976 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
1977 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
1979 /* FIXME: is *lpBufferSize set to the number of characters
1985 ret
= WN_NO_NETWORK
;
1989 TRACE("Returning %ld\n", ret
);
1993 /*****************************************************************
1994 * WNetGetProviderNameW [MPR.@]
1996 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
1997 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2001 TRACE("(0x%08lx, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2005 ret
= WN_BAD_POINTER
;
2006 else if (!lpBufferSize
)
2007 ret
= WN_BAD_POINTER
;
2014 ret
= WN_NO_NETWORK
;
2015 for (i
= 0; i
< providerTable
->numProviders
&&
2016 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2019 if (i
< providerTable
->numProviders
)
2021 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2023 if (*lpBufferSize
< sizeNeeded
)
2025 *lpBufferSize
= sizeNeeded
;
2030 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2032 /* FIXME: is *lpBufferSize set to the number of characters
2038 ret
= WN_NO_NETWORK
;
2042 TRACE("Returning %ld\n", ret
);