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
32 #define WINE_MOUNTMGR_EXTENSIONS
33 #include "ddk/mountmgr.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(mpr
);
41 /* Data structures representing network service providers. Assumes only one
42 * thread creates them, and that they are constant for the life of the process
43 * (and therefore doesn't synchronize access).
44 * FIXME: only basic provider data and enumeration-related data are implemented
45 * so far, need to implement the rest too.
47 typedef struct _WNetProvider
55 PF_NPOpenEnum openEnum
;
56 PF_NPEnumResource enumResource
;
57 PF_NPCloseEnum closeEnum
;
58 PF_NPGetResourceInformation getResourceInformation
;
59 PF_NPAddConnection addConnection
;
60 PF_NPAddConnection3 addConnection3
;
61 PF_NPCancelConnection cancelConnection
;
62 } WNetProvider
, *PWNetProvider
;
64 typedef struct _WNetProviderTable
69 WNetProvider table
[1];
70 } WNetProviderTable
, *PWNetProviderTable
;
72 #define WNET_ENUMERATOR_TYPE_NULL 0
73 #define WNET_ENUMERATOR_TYPE_GLOBAL 1
74 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
75 #define WNET_ENUMERATOR_TYPE_CONTEXT 3
77 /* An WNet enumerator. Note that the type doesn't correspond to the scope of
78 * the enumeration; it represents one of the following types:
79 * - a 'null' enumeration, one that contains no members
80 * - a global enumeration, one that's executed across all providers
81 * - a provider-specific enumeration, one that's only executed by a single
83 * - a context enumeration. I know this contradicts what I just said about
84 * there being no correspondence between the scope and the type, but it's
85 * necessary for the special case that a "Entire Network" entry needs to
86 * be enumerated in an enumeration of the context scope. Thus an enumeration
87 * of the context scope results in a context type enumerator, which morphs
88 * into a global enumeration (so the enumeration continues across all
91 typedef struct _WNetEnumerator
100 LPNETRESOURCEW lpNet
;
101 } WNetEnumerator
, *PWNetEnumerator
;
103 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
105 /* Returns an index (into the global WNetProviderTable) of the provider with
106 * the given name, or BAD_PROVIDER_INDEX if not found.
108 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
);
110 static PWNetProviderTable providerTable
;
113 * Global provider table functions
116 static void _tryLoadProvider(PCWSTR provider
)
118 static const WCHAR servicePrefix
[] = { 'S','y','s','t','e','m','\\',
119 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
120 'S','e','r','v','i','c','e','s','\\',0 };
121 static const WCHAR serviceFmt
[] = { '%','s','%','s','\\',
122 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
123 WCHAR serviceName
[MAX_PATH
];
126 TRACE("%s\n", debugstr_w(provider
));
127 snprintfW(serviceName
, sizeof(serviceName
) / sizeof(WCHAR
), serviceFmt
,
128 servicePrefix
, provider
);
129 serviceName
[sizeof(serviceName
) / sizeof(WCHAR
) - 1] = '\0';
130 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, serviceName
, 0, KEY_READ
, &hKey
) ==
133 static const WCHAR szProviderPath
[] = { 'P','r','o','v','i','d','e','r',
135 WCHAR providerPath
[MAX_PATH
];
136 DWORD type
, size
= sizeof(providerPath
);
138 if (RegQueryValueExW(hKey
, szProviderPath
, NULL
, &type
,
139 (LPBYTE
)providerPath
, &size
) == ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
141 static const WCHAR szProviderName
[] = { 'N','a','m','e',0 };
144 if (type
== REG_EXPAND_SZ
)
146 WCHAR path
[MAX_PATH
];
147 if (ExpandEnvironmentStringsW(providerPath
, path
, MAX_PATH
)) lstrcpyW( providerPath
, path
);
151 RegQueryValueExW(hKey
, szProviderName
, NULL
, NULL
, NULL
, &size
);
154 name
= HeapAlloc(GetProcessHeap(), 0, size
);
155 if (RegQueryValueExW(hKey
, szProviderName
, NULL
, &type
,
156 (LPBYTE
)name
, &size
) != ERROR_SUCCESS
|| type
!= REG_SZ
)
158 HeapFree(GetProcessHeap(), 0, name
);
164 HMODULE hLib
= LoadLibraryW(providerPath
);
168 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc))
170 PF_NPGetCaps getCaps
= MPR_GETPROC(NPGetCaps
);
172 TRACE("loaded lib %p\n", hLib
);
175 PWNetProvider provider
=
176 &providerTable
->table
[providerTable
->numProviders
];
178 provider
->hLib
= hLib
;
179 provider
->name
= name
;
180 TRACE("name is %s\n", debugstr_w(name
));
181 provider
->getCaps
= getCaps
;
182 provider
->dwSpecVersion
= getCaps(WNNC_SPEC_VERSION
);
183 provider
->dwNetType
= getCaps(WNNC_NET_TYPE
);
184 TRACE("net type is 0x%08x\n", provider
->dwNetType
);
185 provider
->dwEnumScopes
= getCaps(WNNC_ENUMERATION
);
186 if (provider
->dwEnumScopes
)
188 TRACE("supports enumeration\n");
189 provider
->openEnum
= MPR_GETPROC(NPOpenEnum
);
190 TRACE("NPOpenEnum %p\n", provider
->openEnum
);
191 provider
->enumResource
= MPR_GETPROC(NPEnumResource
);
192 TRACE("NPEnumResource %p\n", provider
->enumResource
);
193 provider
->closeEnum
= MPR_GETPROC(NPCloseEnum
);
194 TRACE("NPCloseEnum %p\n", provider
->closeEnum
);
195 provider
->getResourceInformation
= MPR_GETPROC(NPGetResourceInformation
);
196 TRACE("NPGetResourceInformation %p\n", provider
->getResourceInformation
);
197 if (!provider
->openEnum
||
198 !provider
->enumResource
||
199 !provider
->closeEnum
)
201 provider
->openEnum
= NULL
;
202 provider
->enumResource
= NULL
;
203 provider
->closeEnum
= NULL
;
204 provider
->dwEnumScopes
= 0;
205 WARN("Couldn't load enumeration functions\n");
208 provider
->addConnection
= MPR_GETPROC(NPAddConnection
);
209 provider
->addConnection3
= MPR_GETPROC(NPAddConnection3
);
210 provider
->cancelConnection
= MPR_GETPROC(NPCancelConnection
);
211 TRACE("NPAddConnection %p\n", provider
->addConnection
);
212 TRACE("NPAddConnection3 %p\n", provider
->addConnection3
);
213 TRACE("NPCancelConnection %p\n", provider
->cancelConnection
);
214 providerTable
->numProviders
++;
218 WARN("Provider %s didn't export NPGetCaps\n",
219 debugstr_w(provider
));
220 HeapFree(GetProcessHeap(), 0, name
);
228 WARN("Couldn't load library %s for provider %s\n",
229 debugstr_w(providerPath
), debugstr_w(provider
));
230 HeapFree(GetProcessHeap(), 0, name
);
235 WARN("Couldn't get provider name for provider %s\n",
236 debugstr_w(provider
));
240 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath
));
244 WARN("Couldn't open service key for provider %s\n",
245 debugstr_w(provider
));
248 void wnetInit(HINSTANCE hInstDll
)
250 static const WCHAR providerOrderKey
[] = { 'S','y','s','t','e','m','\\',
251 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
252 'C','o','n','t','r','o','l','\\',
253 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
254 'O','r','d','e','r',0 };
255 static const WCHAR providerOrder
[] = { 'P','r','o','v','i','d','e','r',
256 'O','r','d','e','r',0 };
259 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, providerOrderKey
, 0, KEY_READ
, &hKey
)
264 RegQueryValueExW(hKey
, providerOrder
, NULL
, NULL
, NULL
, &size
);
267 PWSTR providers
= HeapAlloc(GetProcessHeap(), 0, size
);
273 if (RegQueryValueExW(hKey
, providerOrder
, NULL
, &type
,
274 (LPBYTE
)providers
, &size
) == ERROR_SUCCESS
&& type
== REG_SZ
)
279 TRACE("provider order is %s\n", debugstr_w(providers
));
280 /* first count commas as a heuristic for how many to
281 * allocate space for */
282 for (ptr
= providers
, numToAllocate
= 1; ptr
; )
284 ptr
= strchrW(ptr
, ',');
291 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
292 sizeof(WNetProviderTable
)
293 + (numToAllocate
- 1) * sizeof(WNetProvider
));
297 int entireNetworkLen
;
298 LPCWSTR stringresource
;
300 entireNetworkLen
= LoadStringW(hInstDll
,
301 IDS_ENTIRENETWORK
, (LPWSTR
)&stringresource
, 0);
302 providerTable
->entireNetwork
= HeapAlloc(
303 GetProcessHeap(), 0, (entireNetworkLen
+ 1) *
305 if (providerTable
->entireNetwork
)
307 memcpy(providerTable
->entireNetwork
, stringresource
, entireNetworkLen
*sizeof(WCHAR
));
308 providerTable
->entireNetwork
[entireNetworkLen
] = 0;
310 providerTable
->numAllocated
= numToAllocate
;
311 for (ptr
= providers
; ptr
; )
314 ptr
= strchrW(ptr
, ',');
317 _tryLoadProvider(ptrPrev
);
321 HeapFree(GetProcessHeap(), 0, providers
);
334 for (i
= 0; i
< providerTable
->numProviders
; i
++)
336 HeapFree(GetProcessHeap(), 0, providerTable
->table
[i
].name
);
337 FreeModule(providerTable
->table
[i
].hLib
);
339 HeapFree(GetProcessHeap(), 0, providerTable
->entireNetwork
);
340 HeapFree(GetProcessHeap(), 0, providerTable
);
341 providerTable
= NULL
;
345 static DWORD
_findProviderIndexW(LPCWSTR lpProvider
)
347 DWORD ret
= BAD_PROVIDER_INDEX
;
349 if (providerTable
&& providerTable
->numProviders
)
353 for (i
= 0; i
< providerTable
->numProviders
&&
354 ret
== BAD_PROVIDER_INDEX
; i
++)
355 if (!strcmpW(lpProvider
, providerTable
->table
[i
].name
))
365 static LPNETRESOURCEW
_copyNetResourceForEnumW(LPNETRESOURCEW lpNet
)
371 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW
));
377 ret
->lpLocalName
= ret
->lpComment
= ret
->lpProvider
= NULL
;
378 if (lpNet
->lpRemoteName
)
380 len
= strlenW(lpNet
->lpRemoteName
) + 1;
381 ret
->lpRemoteName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
382 if (ret
->lpRemoteName
)
383 strcpyW(ret
->lpRemoteName
, lpNet
->lpRemoteName
);
392 static void _freeEnumNetResource(LPNETRESOURCEW lpNet
)
396 HeapFree(GetProcessHeap(), 0, lpNet
->lpRemoteName
);
397 HeapFree(GetProcessHeap(), 0, lpNet
);
401 static PWNetEnumerator
_createNullEnumerator(void)
403 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
404 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
407 ret
->enumType
= WNET_ENUMERATOR_TYPE_NULL
;
411 static PWNetEnumerator
_createGlobalEnumeratorW(DWORD dwScope
, DWORD dwType
,
412 DWORD dwUsage
, LPNETRESOURCEW lpNet
)
414 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
415 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
419 ret
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
420 ret
->dwScope
= dwScope
;
421 ret
->dwType
= dwType
;
422 ret
->dwUsage
= dwUsage
;
423 ret
->lpNet
= _copyNetResourceForEnumW(lpNet
);
428 static PWNetEnumerator
_createProviderEnumerator(DWORD dwScope
, DWORD dwType
,
429 DWORD dwUsage
, DWORD index
, HANDLE handle
)
433 if (!providerTable
|| index
>= providerTable
->numProviders
)
437 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
440 ret
->enumType
= WNET_ENUMERATOR_TYPE_PROVIDER
;
441 ret
->providerIndex
= index
;
442 ret
->dwScope
= dwScope
;
443 ret
->dwType
= dwType
;
444 ret
->dwUsage
= dwUsage
;
445 ret
->handle
= handle
;
451 static PWNetEnumerator
_createContextEnumerator(DWORD dwScope
, DWORD dwType
,
454 PWNetEnumerator ret
= HeapAlloc(GetProcessHeap(),
455 HEAP_ZERO_MEMORY
, sizeof(WNetEnumerator
));
459 ret
->enumType
= WNET_ENUMERATOR_TYPE_CONTEXT
;
460 ret
->dwScope
= dwScope
;
461 ret
->dwType
= dwType
;
462 ret
->dwUsage
= dwUsage
;
467 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
468 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
469 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
470 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
471 * if not all members of the array could be thunked, and something else on
474 static DWORD
_thunkNetResourceArrayWToA(const NETRESOURCEW
*lpNetArrayIn
,
475 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
477 DWORD i
, numToThunk
, totalBytes
, ret
;
481 return WN_BAD_POINTER
;
483 return WN_BAD_POINTER
;
487 return WN_BAD_POINTER
;
489 return WN_BAD_POINTER
;
491 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
493 const NETRESOURCEW
*lpNet
= lpNetArrayIn
+ i
;
495 totalBytes
+= sizeof(NETRESOURCEA
);
496 if (lpNet
->lpLocalName
)
497 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpLocalName
,
498 -1, NULL
, 0, NULL
, NULL
);
499 if (lpNet
->lpRemoteName
)
500 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpRemoteName
,
501 -1, NULL
, 0, NULL
, NULL
);
502 if (lpNet
->lpComment
)
503 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpComment
,
504 -1, NULL
, 0, NULL
, NULL
);
505 if (lpNet
->lpProvider
)
506 totalBytes
+= WideCharToMultiByte(CP_ACP
, 0, lpNet
->lpProvider
,
507 -1, NULL
, 0, NULL
, NULL
);
508 if (totalBytes
< *lpBufferSize
)
511 strNext
= (LPSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEA
));
512 for (i
= 0; i
< numToThunk
; i
++)
514 LPNETRESOURCEA lpNetOut
= (LPNETRESOURCEA
)lpBuffer
+ i
;
515 const NETRESOURCEW
*lpNetIn
= lpNetArrayIn
+ i
;
517 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEA
));
518 /* lie about string lengths, we already verified how many
519 * we have space for above
521 if (lpNetIn
->lpLocalName
)
523 lpNetOut
->lpLocalName
= strNext
;
524 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpLocalName
, -1,
525 lpNetOut
->lpLocalName
, *lpBufferSize
, NULL
, NULL
);
527 if (lpNetIn
->lpRemoteName
)
529 lpNetOut
->lpRemoteName
= strNext
;
530 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpRemoteName
, -1,
531 lpNetOut
->lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
533 if (lpNetIn
->lpComment
)
535 lpNetOut
->lpComment
= strNext
;
536 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpComment
, -1,
537 lpNetOut
->lpComment
, *lpBufferSize
, NULL
, NULL
);
539 if (lpNetIn
->lpProvider
)
541 lpNetOut
->lpProvider
= strNext
;
542 strNext
+= WideCharToMultiByte(CP_ACP
, 0, lpNetIn
->lpProvider
, -1,
543 lpNetOut
->lpProvider
, *lpBufferSize
, NULL
, NULL
);
546 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
547 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
552 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
553 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries
554 * to start. On return, *lpcCount reflects the number thunked into lpBuffer.
555 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
556 * if not all members of the array could be thunked, and something else on
559 static DWORD
_thunkNetResourceArrayAToW(const NETRESOURCEA
*lpNetArrayIn
,
560 const DWORD
*lpcCount
, LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
562 DWORD i
, numToThunk
, totalBytes
, ret
;
566 return WN_BAD_POINTER
;
568 return WN_BAD_POINTER
;
572 return WN_BAD_POINTER
;
574 return WN_BAD_POINTER
;
576 for (i
= 0, numToThunk
= 0, totalBytes
= 0; i
< *lpcCount
; i
++)
578 const NETRESOURCEA
*lpNet
= lpNetArrayIn
+ i
;
580 totalBytes
+= sizeof(NETRESOURCEW
);
581 if (lpNet
->lpLocalName
)
582 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpLocalName
,
583 -1, NULL
, 0) * sizeof(WCHAR
);
584 if (lpNet
->lpRemoteName
)
585 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpRemoteName
,
586 -1, NULL
, 0) * sizeof(WCHAR
);
587 if (lpNet
->lpComment
)
588 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpComment
,
589 -1, NULL
, 0) * sizeof(WCHAR
);
590 if (lpNet
->lpProvider
)
591 totalBytes
+= MultiByteToWideChar(CP_ACP
, 0, lpNet
->lpProvider
,
592 -1, NULL
, 0) * sizeof(WCHAR
);
593 if (totalBytes
< *lpBufferSize
)
596 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ numToThunk
* sizeof(NETRESOURCEW
));
597 for (i
= 0; i
< numToThunk
; i
++)
599 LPNETRESOURCEW lpNetOut
= (LPNETRESOURCEW
)lpBuffer
+ i
;
600 const NETRESOURCEA
*lpNetIn
= lpNetArrayIn
+ i
;
602 memcpy(lpNetOut
, lpNetIn
, sizeof(NETRESOURCEW
));
603 /* lie about string lengths, we already verified how many
604 * we have space for above
606 if (lpNetIn
->lpLocalName
)
608 lpNetOut
->lpLocalName
= strNext
;
609 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpLocalName
,
610 -1, lpNetOut
->lpLocalName
, *lpBufferSize
);
612 if (lpNetIn
->lpRemoteName
)
614 lpNetOut
->lpRemoteName
= strNext
;
615 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpRemoteName
,
616 -1, lpNetOut
->lpRemoteName
, *lpBufferSize
);
618 if (lpNetIn
->lpComment
)
620 lpNetOut
->lpComment
= strNext
;
621 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpComment
,
622 -1, lpNetOut
->lpComment
, *lpBufferSize
);
624 if (lpNetIn
->lpProvider
)
626 lpNetOut
->lpProvider
= strNext
;
627 strNext
+= MultiByteToWideChar(CP_ACP
, 0, lpNetIn
->lpProvider
,
628 -1, lpNetOut
->lpProvider
, *lpBufferSize
);
631 ret
= numToThunk
< *lpcCount
? WN_MORE_DATA
: WN_SUCCESS
;
632 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk
,
637 /*********************************************************************
638 * WNetOpenEnumA [MPR.@]
640 * See comments for WNetOpenEnumW.
642 DWORD WINAPI
WNetOpenEnumA( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
643 LPNETRESOURCEA lpNet
, LPHANDLE lphEnum
)
647 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
648 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
651 ret
= WN_BAD_POINTER
;
652 else if (!providerTable
|| providerTable
->numProviders
== 0)
661 LPNETRESOURCEW lpNetWide
= NULL
;
663 DWORD size
= sizeof(buf
), count
= 1;
664 BOOL allocated
= FALSE
;
666 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, buf
, &size
);
667 if (ret
== WN_MORE_DATA
)
669 lpNetWide
= HeapAlloc(GetProcessHeap(), 0,
673 ret
= _thunkNetResourceArrayAToW(lpNet
, &count
, lpNetWide
,
678 ret
= WN_OUT_OF_MEMORY
;
680 else if (ret
== WN_SUCCESS
)
681 lpNetWide
= (LPNETRESOURCEW
)buf
;
682 if (ret
== WN_SUCCESS
)
683 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, lpNetWide
,
686 HeapFree(GetProcessHeap(), 0, lpNetWide
);
689 ret
= WNetOpenEnumW(dwScope
, dwType
, dwUsage
, NULL
, lphEnum
);
693 TRACE("Returning %d\n", ret
);
697 /*********************************************************************
698 * WNetOpenEnumW [MPR.@]
700 * Network enumeration has way too many parameters, so I'm not positive I got
701 * them right. What I've got so far:
703 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
704 * all the network providers should be enumerated.
706 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
707 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
708 * lpProvider is set, all the network providers should be enumerated.
709 * (This means the enumeration is a list of network providers, not that the
710 * enumeration is passed on to the providers.)
712 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
713 * resource matches the "Entire Network" resource (no remote name, no
714 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
715 * enumeration is done on every network provider.
717 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
718 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
719 * only to the given network provider.
721 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
722 * no lpProvider is set, enumeration will be tried on every network provider,
723 * in the order in which they're loaded.
725 * - The LPNETRESOURCE should be disregarded for scopes besides
726 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not
727 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
729 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
730 * resource in the enumerated list, as well as any machines in your
731 * workgroup. The machines in your workgroup come from doing a
732 * RESOURCE_CONTEXT enumeration of every Network Provider.
734 DWORD WINAPI
WNetOpenEnumW( DWORD dwScope
, DWORD dwType
, DWORD dwUsage
,
735 LPNETRESOURCEW lpNet
, LPHANDLE lphEnum
)
739 TRACE( "(%08X, %08X, %08X, %p, %p)\n",
740 dwScope
, dwType
, dwUsage
, lpNet
, lphEnum
);
743 ret
= WN_BAD_POINTER
;
744 else if (!providerTable
|| providerTable
->numProviders
== 0)
753 case RESOURCE_GLOBALNET
:
756 if (lpNet
->lpProvider
)
758 DWORD index
= _findProviderIndexW(lpNet
->lpProvider
);
760 if (index
!= BAD_PROVIDER_INDEX
)
762 if (providerTable
->table
[index
].openEnum
&&
763 providerTable
->table
[index
].dwEnumScopes
& WNNC_ENUM_GLOBAL
)
766 PWSTR RemoteName
= lpNet
->lpRemoteName
;
768 if ((lpNet
->dwUsage
& RESOURCEUSAGE_CONTAINER
) &&
769 RemoteName
&& !strcmpW(RemoteName
, lpNet
->lpProvider
))
770 lpNet
->lpRemoteName
= NULL
;
772 ret
= providerTable
->table
[index
].openEnum(
773 dwScope
, dwType
, dwUsage
, lpNet
, &handle
);
774 if (ret
== WN_SUCCESS
)
776 *lphEnum
= _createProviderEnumerator(
777 dwScope
, dwType
, dwUsage
, index
, handle
);
778 ret
= *lphEnum
? WN_SUCCESS
:
782 lpNet
->lpRemoteName
= RemoteName
;
785 ret
= WN_NOT_SUPPORTED
;
788 ret
= WN_BAD_PROVIDER
;
790 else if (lpNet
->lpRemoteName
)
792 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
793 dwType
, dwUsage
, lpNet
);
794 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
798 if (lpNet
->lpComment
&& !strcmpW(lpNet
->lpComment
,
799 providerTable
->entireNetwork
))
801 /* comment matches the "Entire Network", enumerate
802 * global scope of every provider
804 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
805 dwType
, dwUsage
, lpNet
);
809 /* this is the same as not having passed lpNet */
810 *lphEnum
= _createGlobalEnumeratorW(dwScope
,
811 dwType
, dwUsage
, NULL
);
813 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
818 *lphEnum
= _createGlobalEnumeratorW(dwScope
, dwType
,
820 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
823 case RESOURCE_CONTEXT
:
824 *lphEnum
= _createContextEnumerator(dwScope
, dwType
, dwUsage
);
825 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
827 case RESOURCE_REMEMBERED
:
828 case RESOURCE_CONNECTED
:
829 *lphEnum
= _createNullEnumerator();
830 ret
= *lphEnum
? WN_SUCCESS
: WN_OUT_OF_MEMORY
;
833 WARN("unknown scope 0x%08x\n", dwScope
);
839 TRACE("Returning %d\n", ret
);
843 /*********************************************************************
844 * WNetEnumResourceA [MPR.@]
846 DWORD WINAPI
WNetEnumResourceA( HANDLE hEnum
, LPDWORD lpcCount
,
847 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
851 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
854 ret
= WN_BAD_POINTER
;
856 ret
= WN_BAD_POINTER
;
858 ret
= WN_BAD_POINTER
;
859 else if (!lpBufferSize
)
860 ret
= WN_BAD_POINTER
;
861 else if (*lpBufferSize
< sizeof(NETRESOURCEA
))
863 *lpBufferSize
= sizeof(NETRESOURCEA
);
868 DWORD localCount
= *lpcCount
, localSize
= *lpBufferSize
;
869 LPVOID localBuffer
= HeapAlloc(GetProcessHeap(), 0, localSize
);
873 ret
= WNetEnumResourceW(hEnum
, &localCount
, localBuffer
,
875 if (ret
== WN_SUCCESS
|| (ret
== WN_MORE_DATA
&& localCount
!= -1))
877 /* FIXME: this isn't necessarily going to work in the case of
878 * WN_MORE_DATA, because our enumerator may have moved on to
879 * the next provider. MSDN states that a large (16KB) buffer
880 * size is the appropriate usage of this function, so
881 * hopefully it won't be an issue.
883 ret
= _thunkNetResourceArrayWToA(localBuffer
, &localCount
,
884 lpBuffer
, lpBufferSize
);
885 *lpcCount
= localCount
;
887 HeapFree(GetProcessHeap(), 0, localBuffer
);
890 ret
= WN_OUT_OF_MEMORY
;
894 TRACE("Returning %d\n", ret
);
898 static DWORD
_countProviderBytesW(PWNetProvider provider
)
904 ret
= sizeof(NETRESOURCEW
);
905 ret
+= 2 * (strlenW(provider
->name
) + 1) * sizeof(WCHAR
);
912 static DWORD
_enumerateProvidersW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
913 LPVOID lpBuffer
, const DWORD
*lpBufferSize
)
918 return WN_BAD_POINTER
;
919 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
922 return WN_BAD_POINTER
;
924 return WN_BAD_POINTER
;
926 return WN_BAD_POINTER
;
927 if (*lpBufferSize
< sizeof(NETRESOURCEA
))
930 if (!providerTable
|| enumerator
->providerIndex
>=
931 providerTable
->numProviders
)
932 ret
= WN_NO_MORE_ENTRIES
;
935 DWORD bytes
= 0, count
= 0, countLimit
, i
;
936 LPNETRESOURCEW resource
;
939 countLimit
= *lpcCount
== -1 ?
940 providerTable
->numProviders
- enumerator
->providerIndex
: *lpcCount
;
941 while (count
< countLimit
&& bytes
< *lpBufferSize
)
943 DWORD bytesNext
= _countProviderBytesW(
944 &providerTable
->table
[count
+ enumerator
->providerIndex
]);
946 if (bytes
+ bytesNext
< *lpBufferSize
)
952 strNext
= (LPWSTR
)((LPBYTE
)lpBuffer
+ count
* sizeof(NETRESOURCEW
));
953 for (i
= 0, resource
= lpBuffer
; i
< count
; i
++, resource
++)
955 resource
->dwScope
= RESOURCE_GLOBALNET
;
956 resource
->dwType
= RESOURCETYPE_ANY
;
957 resource
->dwDisplayType
= RESOURCEDISPLAYTYPE_NETWORK
;
958 resource
->dwUsage
= RESOURCEUSAGE_CONTAINER
|
959 RESOURCEUSAGE_RESERVED
;
960 resource
->lpLocalName
= NULL
;
961 resource
->lpRemoteName
= strNext
;
962 strcpyW(resource
->lpRemoteName
,
963 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
964 strNext
+= strlenW(resource
->lpRemoteName
) + 1;
965 resource
->lpComment
= NULL
;
966 resource
->lpProvider
= strNext
;
967 strcpyW(resource
->lpProvider
,
968 providerTable
->table
[i
+ enumerator
->providerIndex
].name
);
969 strNext
+= strlenW(resource
->lpProvider
) + 1;
971 enumerator
->providerIndex
+= count
;
973 ret
= count
> 0 ? WN_SUCCESS
: WN_MORE_DATA
;
975 TRACE("Returning %d\n", ret
);
979 /* Advances the enumerator (assumed to be a global enumerator) to the next
980 * provider that supports the enumeration scope passed to WNetOpenEnum. Does
981 * not open a handle with the next provider.
982 * If the existing handle is NULL, may leave the enumerator unchanged, since
983 * the current provider may support the desired scope.
984 * If the existing handle is not NULL, closes it before moving on.
985 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
986 * provider, and another error on failure.
988 static DWORD
_globalEnumeratorAdvance(PWNetEnumerator enumerator
)
991 return WN_BAD_POINTER
;
992 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
994 if (!providerTable
|| enumerator
->providerIndex
>=
995 providerTable
->numProviders
)
996 return WN_NO_MORE_ENTRIES
;
998 if (enumerator
->providerDone
)
1001 enumerator
->providerDone
= FALSE
;
1002 if (enumerator
->handle
)
1004 providerTable
->table
[enumerator
->providerIndex
].closeEnum(
1005 enumerator
->handle
);
1006 enumerator
->handle
= NULL
;
1007 enumerator
->providerIndex
++;
1009 if (enumerator
->dwScope
== RESOURCE_CONNECTED
)
1010 dwEnum
= WNNC_ENUM_LOCAL
;
1011 else if (enumerator
->dwScope
== RESOURCE_GLOBALNET
)
1012 dwEnum
= WNNC_ENUM_GLOBAL
;
1013 else if (enumerator
->dwScope
== RESOURCE_CONTEXT
)
1014 dwEnum
= WNNC_ENUM_CONTEXT
;
1015 for (; enumerator
->providerIndex
< providerTable
->numProviders
&&
1016 !(providerTable
->table
[enumerator
->providerIndex
].dwEnumScopes
1017 & dwEnum
); enumerator
->providerIndex
++)
1020 return enumerator
->providerIndex
< providerTable
->numProviders
?
1021 WN_SUCCESS
: WN_NO_MORE_ENTRIES
;
1024 /* "Passes through" call to the next provider that supports the enumeration
1026 * FIXME: if one call to a provider's enumerator succeeds while there's still
1027 * space in lpBuffer, I don't call to the next provider. The caller may not
1028 * expect that it should call EnumResourceW again with a return value of
1029 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings
1030 * may have to be moved around a bit, ick.
1032 static DWORD
_enumerateGlobalPassthroughW(PWNetEnumerator enumerator
,
1033 LPDWORD lpcCount
, LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1038 return WN_BAD_POINTER
;
1039 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1040 return WN_BAD_VALUE
;
1042 return WN_BAD_POINTER
;
1044 return WN_BAD_POINTER
;
1046 return WN_BAD_POINTER
;
1047 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1048 return WN_MORE_DATA
;
1050 ret
= _globalEnumeratorAdvance(enumerator
);
1051 if (ret
== WN_SUCCESS
)
1053 ret
= providerTable
->table
[enumerator
->providerIndex
].
1054 openEnum(enumerator
->dwScope
, enumerator
->dwType
,
1055 enumerator
->dwUsage
, enumerator
->lpNet
,
1056 &enumerator
->handle
);
1057 if (ret
== WN_SUCCESS
)
1059 ret
= providerTable
->table
[enumerator
->providerIndex
].
1060 enumResource(enumerator
->handle
, lpcCount
, lpBuffer
,
1062 if (ret
!= WN_MORE_DATA
)
1063 enumerator
->providerDone
= TRUE
;
1066 TRACE("Returning %d\n", ret
);
1070 static DWORD
_enumerateGlobalW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1071 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1076 return WN_BAD_POINTER
;
1077 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_GLOBAL
)
1078 return WN_BAD_VALUE
;
1080 return WN_BAD_POINTER
;
1082 return WN_BAD_POINTER
;
1084 return WN_BAD_POINTER
;
1085 if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1086 return WN_MORE_DATA
;
1088 return WN_NO_NETWORK
;
1090 switch (enumerator
->dwScope
)
1092 case RESOURCE_GLOBALNET
:
1093 if (enumerator
->lpNet
)
1094 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
,
1095 lpBuffer
, lpBufferSize
);
1097 ret
= _enumerateProvidersW(enumerator
, lpcCount
, lpBuffer
,
1100 case RESOURCE_CONTEXT
:
1101 ret
= _enumerateGlobalPassthroughW(enumerator
, lpcCount
, lpBuffer
,
1105 WARN("unexpected scope 0x%08x\n", enumerator
->dwScope
);
1106 ret
= WN_NO_MORE_ENTRIES
;
1108 TRACE("Returning %d\n", ret
);
1112 static DWORD
_enumerateProviderW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1113 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1116 return WN_BAD_POINTER
;
1117 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_PROVIDER
)
1118 return WN_BAD_VALUE
;
1119 if (!enumerator
->handle
)
1120 return WN_BAD_VALUE
;
1122 return WN_BAD_POINTER
;
1124 return WN_BAD_POINTER
;
1126 return WN_BAD_POINTER
;
1128 return WN_NO_NETWORK
;
1129 if (enumerator
->providerIndex
>= providerTable
->numProviders
)
1130 return WN_NO_MORE_ENTRIES
;
1131 if (!providerTable
->table
[enumerator
->providerIndex
].enumResource
)
1132 return WN_BAD_VALUE
;
1133 return providerTable
->table
[enumerator
->providerIndex
].enumResource(
1134 enumerator
->handle
, lpcCount
, lpBuffer
, lpBufferSize
);
1137 static DWORD
_enumerateContextW(PWNetEnumerator enumerator
, LPDWORD lpcCount
,
1138 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1141 size_t cchEntireNetworkLen
, bytesNeeded
;
1144 return WN_BAD_POINTER
;
1145 if (enumerator
->enumType
!= WNET_ENUMERATOR_TYPE_CONTEXT
)
1146 return WN_BAD_VALUE
;
1148 return WN_BAD_POINTER
;
1150 return WN_BAD_POINTER
;
1152 return WN_BAD_POINTER
;
1154 return WN_NO_NETWORK
;
1156 cchEntireNetworkLen
= strlenW(providerTable
->entireNetwork
) + 1;
1157 bytesNeeded
= sizeof(NETRESOURCEW
) + cchEntireNetworkLen
* sizeof(WCHAR
);
1158 if (*lpBufferSize
< bytesNeeded
)
1160 *lpBufferSize
= bytesNeeded
;
1165 LPNETRESOURCEW lpNet
= lpBuffer
;
1167 lpNet
->dwScope
= RESOURCE_GLOBALNET
;
1168 lpNet
->dwType
= enumerator
->dwType
;
1169 lpNet
->dwDisplayType
= RESOURCEDISPLAYTYPE_ROOT
;
1170 lpNet
->dwUsage
= RESOURCEUSAGE_CONTAINER
;
1171 lpNet
->lpLocalName
= NULL
;
1172 lpNet
->lpRemoteName
= NULL
;
1173 lpNet
->lpProvider
= NULL
;
1174 /* odd, but correct: put comment at end of buffer, so it won't get
1175 * overwritten by subsequent calls to a provider's enumResource
1177 lpNet
->lpComment
= (LPWSTR
)((LPBYTE
)lpBuffer
+ *lpBufferSize
-
1178 (cchEntireNetworkLen
* sizeof(WCHAR
)));
1179 strcpyW(lpNet
->lpComment
, providerTable
->entireNetwork
);
1182 if (ret
== WN_SUCCESS
)
1184 DWORD bufferSize
= *lpBufferSize
- bytesNeeded
;
1186 /* "Entire Network" entry enumerated--morph this into a global
1187 * enumerator. enumerator->lpNet continues to be NULL, since it has
1188 * no meaning when the scope isn't RESOURCE_GLOBALNET.
1190 enumerator
->enumType
= WNET_ENUMERATOR_TYPE_GLOBAL
;
1191 ret
= _enumerateGlobalW(enumerator
, lpcCount
,
1192 (LPBYTE
)lpBuffer
+ bytesNeeded
, &bufferSize
);
1193 if (ret
== WN_SUCCESS
)
1195 /* reflect the fact that we already enumerated "Entire Network" */
1197 *lpBufferSize
= bufferSize
+ bytesNeeded
;
1201 /* the provider enumeration failed, but we already succeeded in
1202 * enumerating "Entire Network"--leave type as global to allow a
1203 * retry, but indicate success with a count of one.
1207 *lpBufferSize
= bytesNeeded
;
1210 TRACE("Returning %d\n", ret
);
1214 /*********************************************************************
1215 * WNetEnumResourceW [MPR.@]
1217 DWORD WINAPI
WNetEnumResourceW( HANDLE hEnum
, LPDWORD lpcCount
,
1218 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1222 TRACE( "(%p, %p, %p, %p)\n", hEnum
, lpcCount
, lpBuffer
, lpBufferSize
);
1225 ret
= WN_BAD_POINTER
;
1227 ret
= WN_BAD_POINTER
;
1229 ret
= WN_BAD_POINTER
;
1230 else if (!lpBufferSize
)
1231 ret
= WN_BAD_POINTER
;
1232 else if (*lpBufferSize
< sizeof(NETRESOURCEW
))
1234 *lpBufferSize
= sizeof(NETRESOURCEW
);
1239 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1241 switch (enumerator
->enumType
)
1243 case WNET_ENUMERATOR_TYPE_NULL
:
1244 ret
= WN_NO_MORE_ENTRIES
;
1246 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1247 ret
= _enumerateGlobalW(enumerator
, lpcCount
, lpBuffer
,
1250 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1251 ret
= _enumerateProviderW(enumerator
, lpcCount
, lpBuffer
,
1254 case WNET_ENUMERATOR_TYPE_CONTEXT
:
1255 ret
= _enumerateContextW(enumerator
, lpcCount
, lpBuffer
,
1259 WARN("bogus enumerator type!\n");
1260 ret
= WN_NO_NETWORK
;
1265 TRACE("Returning %d\n", ret
);
1269 /*********************************************************************
1270 * WNetCloseEnum [MPR.@]
1272 DWORD WINAPI
WNetCloseEnum( HANDLE hEnum
)
1276 TRACE( "(%p)\n", hEnum
);
1280 PWNetEnumerator enumerator
= (PWNetEnumerator
)hEnum
;
1282 switch (enumerator
->enumType
)
1284 case WNET_ENUMERATOR_TYPE_NULL
:
1287 case WNET_ENUMERATOR_TYPE_GLOBAL
:
1288 if (enumerator
->lpNet
)
1289 _freeEnumNetResource(enumerator
->lpNet
);
1290 if (enumerator
->handle
)
1291 providerTable
->table
[enumerator
->providerIndex
].
1292 closeEnum(enumerator
->handle
);
1295 case WNET_ENUMERATOR_TYPE_PROVIDER
:
1296 if (enumerator
->handle
)
1297 providerTable
->table
[enumerator
->providerIndex
].
1298 closeEnum(enumerator
->handle
);
1302 WARN("bogus enumerator type!\n");
1303 ret
= WN_BAD_HANDLE
;
1305 HeapFree(GetProcessHeap(), 0, hEnum
);
1308 ret
= WN_BAD_HANDLE
;
1311 TRACE("Returning %d\n", ret
);
1315 /*********************************************************************
1316 * WNetGetResourceInformationA [MPR.@]
1318 * See WNetGetResourceInformationW
1320 DWORD WINAPI
WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource
,
1321 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1326 TRACE( "(%p, %p, %p, %p)\n",
1327 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1329 if (!providerTable
|| providerTable
->numProviders
== 0)
1330 ret
= WN_NO_NETWORK
;
1331 else if (lpNetResource
)
1333 LPNETRESOURCEW lpNetResourceW
= NULL
;
1334 DWORD size
= 1024, count
= 1;
1337 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1338 ret
= _thunkNetResourceArrayAToW(lpNetResource
, &count
, lpNetResourceW
, &size
);
1339 if (ret
== WN_MORE_DATA
)
1341 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1342 lpNetResourceW
= HeapAlloc(GetProcessHeap(), 0, size
);
1344 ret
= _thunkNetResourceArrayAToW(lpNetResource
,
1345 &count
, lpNetResourceW
, &size
);
1347 ret
= WN_OUT_OF_MEMORY
;
1349 if (ret
== WN_SUCCESS
)
1351 LPWSTR lpSystemW
= NULL
;
1354 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1357 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1358 lpBufferW
, &size
, &lpSystemW
);
1359 if (ret
== WN_MORE_DATA
)
1361 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1362 lpBufferW
= HeapAlloc(GetProcessHeap(), 0, size
);
1364 ret
= WNetGetResourceInformationW(lpNetResourceW
,
1365 lpBufferW
, &size
, &lpSystemW
);
1367 ret
= WN_OUT_OF_MEMORY
;
1369 if (ret
== WN_SUCCESS
)
1371 ret
= _thunkNetResourceArrayWToA(lpBufferW
,
1372 &count
, lpBuffer
, cbBuffer
);
1373 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1374 lpNetResourceW
= lpBufferW
;
1375 size
= sizeof(NETRESOURCEA
);
1376 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpRemoteName
,
1377 -1, NULL
, 0, NULL
, NULL
);
1378 size
+= WideCharToMultiByte(CP_ACP
, 0, lpNetResourceW
->lpProvider
,
1379 -1, NULL
, 0, NULL
, NULL
);
1381 len
= WideCharToMultiByte(CP_ACP
, 0, lpSystemW
,
1382 -1, NULL
, 0, NULL
, NULL
);
1383 if ((len
) && ( size
+ len
< *cbBuffer
))
1385 *lplpSystem
= (char*)lpBuffer
+ *cbBuffer
- len
;
1386 WideCharToMultiByte(CP_ACP
, 0, lpSystemW
, -1,
1387 *lplpSystem
, len
, NULL
, NULL
);
1394 ret
= WN_OUT_OF_MEMORY
;
1395 HeapFree(GetProcessHeap(), 0, lpBufferW
);
1398 ret
= WN_OUT_OF_MEMORY
;
1399 HeapFree(GetProcessHeap(), 0, lpSystemW
);
1401 HeapFree(GetProcessHeap(), 0, lpNetResourceW
);
1404 ret
= WN_NO_NETWORK
;
1408 TRACE("Returning %d\n", ret
);
1412 /*********************************************************************
1413 * WNetGetResourceInformationW [MPR.@]
1415 * WNetGetResourceInformationW function identifies the network provider
1416 * that owns the resource and gets information about the type of the resource.
1419 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that
1420 * defines a network resource.
1421 * lpBuffer [ O] the pointer to buffer, containing result. It
1422 * contains NETRESOURCEW structure and strings to
1423 * which the members of the NETRESOURCEW structure
1425 * cbBuffer [I/O] the pointer to DWORD number - size of buffer
1427 * lplpSystem [ O] the pointer to string in the output buffer,
1428 * containing the part of the resource name without
1429 * names of the server and share.
1432 * NO_ERROR if the function succeeds. System error code if the function fails.
1435 DWORD WINAPI
WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource
,
1436 LPVOID lpBuffer
, LPDWORD cbBuffer
,
1437 LPWSTR
*lplpSystem
)
1439 DWORD ret
= WN_NO_NETWORK
;
1442 TRACE( "(%p, %p, %p, %p)\n",
1443 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1446 ret
= WN_OUT_OF_MEMORY
;
1447 else if (providerTable
!= NULL
)
1449 /* FIXME: For function value of a variable is indifferent, it does
1450 * search of all providers in a network.
1452 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1454 if(providerTable
->table
[index
].getCaps(WNNC_DIALOG
) &
1455 WNNC_DLG_GETRESOURCEINFORMATION
)
1457 if (providerTable
->table
[index
].getResourceInformation
)
1458 ret
= providerTable
->table
[index
].getResourceInformation(
1459 lpNetResource
, lpBuffer
, cbBuffer
, lplpSystem
);
1461 ret
= WN_NO_NETWORK
;
1462 if (ret
== WN_SUCCESS
)
1472 /*********************************************************************
1473 * WNetGetResourceParentA [MPR.@]
1475 DWORD WINAPI
WNetGetResourceParentA( LPNETRESOURCEA lpNetResource
,
1476 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1478 FIXME( "(%p, %p, %p): stub\n",
1479 lpNetResource
, lpBuffer
, lpBufferSize
);
1481 SetLastError(WN_NO_NETWORK
);
1482 return WN_NO_NETWORK
;
1485 /*********************************************************************
1486 * WNetGetResourceParentW [MPR.@]
1488 DWORD WINAPI
WNetGetResourceParentW( LPNETRESOURCEW lpNetResource
,
1489 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
1491 FIXME( "(%p, %p, %p): stub\n",
1492 lpNetResource
, lpBuffer
, lpBufferSize
);
1494 SetLastError(WN_NO_NETWORK
);
1495 return WN_NO_NETWORK
;
1501 * Connection Functions
1504 /*********************************************************************
1505 * WNetAddConnectionA [MPR.@]
1507 DWORD WINAPI
WNetAddConnectionA( LPCSTR lpRemoteName
, LPCSTR lpPassword
,
1508 LPCSTR lpLocalName
)
1510 NETRESOURCEA resourcesA
;
1512 memset(&resourcesA
, 0, sizeof(resourcesA
));
1513 resourcesA
.lpRemoteName
= (LPSTR
)lpRemoteName
;
1514 resourcesA
.lpLocalName
= (LPSTR
)lpLocalName
;
1515 return WNetUseConnectionA(NULL
, &resourcesA
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1518 /*********************************************************************
1519 * WNetAddConnectionW [MPR.@]
1521 DWORD WINAPI
WNetAddConnectionW( LPCWSTR lpRemoteName
, LPCWSTR lpPassword
,
1522 LPCWSTR lpLocalName
)
1524 NETRESOURCEW resourcesW
;
1526 memset(&resourcesW
, 0, sizeof(resourcesW
));
1527 resourcesW
.lpRemoteName
= (LPWSTR
)lpRemoteName
;
1528 resourcesW
.lpLocalName
= (LPWSTR
)lpLocalName
;
1529 return WNetUseConnectionW(NULL
, &resourcesW
, lpPassword
, NULL
, 0, NULL
, 0, NULL
);
1532 /*********************************************************************
1533 * WNetAddConnection2A [MPR.@]
1535 DWORD WINAPI
WNetAddConnection2A( LPNETRESOURCEA lpNetResource
,
1536 LPCSTR lpPassword
, LPCSTR lpUserID
,
1539 return WNetUseConnectionA(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1543 /*********************************************************************
1544 * WNetAddConnection2W [MPR.@]
1546 DWORD WINAPI
WNetAddConnection2W( LPNETRESOURCEW lpNetResource
,
1547 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1550 return WNetUseConnectionW(NULL
, lpNetResource
, lpPassword
, lpUserID
, dwFlags
,
1554 /*********************************************************************
1555 * WNetAddConnection3A [MPR.@]
1557 DWORD WINAPI
WNetAddConnection3A( HWND hwndOwner
, LPNETRESOURCEA lpNetResource
,
1558 LPCSTR lpPassword
, LPCSTR lpUserID
,
1561 return WNetUseConnectionA(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1562 dwFlags
, NULL
, 0, NULL
);
1565 /*********************************************************************
1566 * WNetAddConnection3W [MPR.@]
1568 DWORD WINAPI
WNetAddConnection3W( HWND hwndOwner
, LPNETRESOURCEW lpNetResource
,
1569 LPCWSTR lpPassword
, LPCWSTR lpUserID
,
1572 return WNetUseConnectionW(hwndOwner
, lpNetResource
, lpPassword
, lpUserID
,
1573 dwFlags
, NULL
, 0, NULL
);
1576 struct use_connection_context
1579 NETRESOURCEW
*resource
;
1580 NETRESOURCEA
*resourceA
; /* only set for WNetUseConnectionA */
1587 DWORD (*pre_set_accessname
)(struct use_connection_context
*, WCHAR
*);
1588 void (*set_accessname
)(struct use_connection_context
*, WCHAR
*);
1591 static DWORD
use_connection_pre_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1593 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1598 len
= strlenW(local_name
);
1600 len
= strlenW(ctxt
->resource
->lpRemoteName
);
1602 if (++len
> *ctxt
->buffer_size
)
1604 *ctxt
->buffer_size
= len
;
1605 return ERROR_MORE_DATA
;
1609 ctxt
->accessname
= NULL
;
1611 return ERROR_SUCCESS
;
1614 static void use_connection_set_accessnameW(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1616 WCHAR
*accessname
= ctxt
->accessname
;
1619 strcpyW(accessname
, local_name
);
1621 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1624 strcpyW(accessname
, ctxt
->resource
->lpRemoteName
);
1627 static DWORD
wnet_use_provider( struct use_connection_context
*ctxt
, NETRESOURCEW
* netres
, WNetProvider
*provider
, BOOLEAN redirect
)
1631 caps
= provider
->getCaps(WNNC_CONNECTION
);
1632 if (!(caps
& (WNNC_CON_ADDCONNECTION
| WNNC_CON_ADDCONNECTION3
)))
1633 return ERROR_BAD_PROVIDER
;
1635 ret
= WN_ACCESS_DENIED
;
1638 if ((caps
& WNNC_CON_ADDCONNECTION3
) && provider
->addConnection3
)
1639 ret
= provider
->addConnection3(ctxt
->hwndOwner
, netres
, ctxt
->password
, ctxt
->userid
, ctxt
->flags
);
1640 else if ((caps
& WNNC_CON_ADDCONNECTION
) && provider
->addConnection
)
1641 ret
= provider
->addConnection(netres
, ctxt
->password
, ctxt
->userid
);
1643 if (ret
== WN_ALREADY_CONNECTED
&& redirect
)
1644 netres
->lpLocalName
[0] -= 1;
1645 } while (redirect
&& ret
== WN_ALREADY_CONNECTED
&& netres
->lpLocalName
[0] >= 'C');
1647 if (ret
== WN_SUCCESS
&& ctxt
->accessname
)
1648 ctxt
->set_accessname(ctxt
, netres
->lpLocalName
);
1653 static DWORD
wnet_use_connection( struct use_connection_context
*ctxt
)
1655 WNetProvider
*provider
;
1656 DWORD index
, ret
= WN_NO_NETWORK
;
1657 BOOL redirect
= FALSE
;
1658 WCHAR letter
[3] = {'Z', ':', 0};
1659 NETRESOURCEW netres
;
1661 if (!providerTable
|| providerTable
->numProviders
== 0)
1662 return WN_NO_NETWORK
;
1664 if (!ctxt
->resource
)
1665 return ERROR_INVALID_PARAMETER
;
1666 netres
= *ctxt
->resource
;
1668 if (!netres
.lpLocalName
&& (ctxt
->flags
& CONNECT_REDIRECT
))
1670 if (netres
.dwType
!= RESOURCETYPE_DISK
&& netres
.dwType
!= RESOURCETYPE_PRINT
)
1671 return ERROR_BAD_DEV_TYPE
;
1673 if (netres
.dwType
== RESOURCETYPE_PRINT
)
1675 FIXME("Local device selection is not implemented for printers.\n");
1676 return WN_NO_NETWORK
;
1680 netres
.lpLocalName
= letter
;
1683 if (ctxt
->flags
& CONNECT_INTERACTIVE
)
1684 return ERROR_BAD_NET_NAME
;
1686 if ((ret
= ctxt
->pre_set_accessname(ctxt
, netres
.lpLocalName
)))
1689 if (netres
.lpProvider
)
1691 index
= _findProviderIndexW(netres
.lpProvider
);
1692 if (index
== BAD_PROVIDER_INDEX
)
1693 return ERROR_BAD_PROVIDER
;
1695 provider
= &providerTable
->table
[index
];
1696 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
1700 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1702 provider
= &providerTable
->table
[index
];
1703 ret
= wnet_use_provider(ctxt
, &netres
, provider
, redirect
);
1704 if (ret
== WN_SUCCESS
|| ret
== WN_ALREADY_CONNECTED
)
1712 /*****************************************************************
1713 * WNetUseConnectionW [MPR.@]
1715 DWORD WINAPI
WNetUseConnectionW( HWND hwndOwner
, NETRESOURCEW
*resource
, LPCWSTR password
,
1716 LPCWSTR userid
, DWORD flags
, LPWSTR accessname
, DWORD
*buffer_size
, DWORD
*result
)
1718 struct use_connection_context ctxt
;
1720 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
1721 hwndOwner
, resource
, password
, debugstr_w(userid
), flags
,
1722 accessname
, buffer_size
, result
);
1724 ctxt
.hwndOwner
= hwndOwner
;
1725 ctxt
.resource
= resource
;
1726 ctxt
.resourceA
= NULL
;
1727 ctxt
.password
= (WCHAR
*)password
;
1728 ctxt
.userid
= (WCHAR
*)userid
;
1730 ctxt
.accessname
= accessname
;
1731 ctxt
.buffer_size
= buffer_size
;
1732 ctxt
.result
= result
;
1733 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameW
;
1734 ctxt
.set_accessname
= use_connection_set_accessnameW
;
1736 return wnet_use_connection(&ctxt
);
1739 static DWORD
use_connection_pre_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1741 if (ctxt
->accessname
&& ctxt
->buffer_size
&& *ctxt
->buffer_size
)
1746 len
= WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, NULL
, 0, NULL
, NULL
) - 1;
1748 len
= strlen(ctxt
->resourceA
->lpRemoteName
);
1750 if (++len
> *ctxt
->buffer_size
)
1752 *ctxt
->buffer_size
= len
;
1753 return ERROR_MORE_DATA
;
1757 ctxt
->accessname
= NULL
;
1759 return ERROR_SUCCESS
;
1762 static void use_connection_set_accessnameA(struct use_connection_context
*ctxt
, WCHAR
*local_name
)
1764 char *accessname
= ctxt
->accessname
;
1767 WideCharToMultiByte(CP_ACP
, 0, local_name
, -1, accessname
, *ctxt
->buffer_size
, NULL
, NULL
);
1769 *ctxt
->result
= CONNECT_LOCALDRIVE
;
1772 strcpy(accessname
, ctxt
->resourceA
->lpRemoteName
);
1775 static LPWSTR
strdupAtoW( LPCSTR str
)
1780 if (!str
) return NULL
;
1781 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
1782 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1783 if (ret
) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
1787 static void netresource_a_to_w( NETRESOURCEA
*resourceA
, NETRESOURCEW
*resourceW
)
1789 resourceW
->dwScope
= resourceA
->dwScope
;
1790 resourceW
->dwType
= resourceA
->dwType
;
1791 resourceW
->dwDisplayType
= resourceA
->dwDisplayType
;
1792 resourceW
->dwUsage
= resourceA
->dwUsage
;
1793 resourceW
->lpLocalName
= strdupAtoW(resourceA
->lpLocalName
);
1794 resourceW
->lpRemoteName
= strdupAtoW(resourceA
->lpRemoteName
);
1795 resourceW
->lpComment
= strdupAtoW(resourceA
->lpComment
);
1796 resourceW
->lpProvider
= strdupAtoW(resourceA
->lpProvider
);
1799 static void free_netresourceW( NETRESOURCEW
*resource
)
1801 HeapFree(GetProcessHeap(), 0, resource
->lpLocalName
);
1802 HeapFree(GetProcessHeap(), 0, resource
->lpRemoteName
);
1803 HeapFree(GetProcessHeap(), 0, resource
->lpComment
);
1804 HeapFree(GetProcessHeap(), 0, resource
->lpProvider
);
1807 /*****************************************************************
1808 * WNetUseConnectionA [MPR.@]
1810 DWORD WINAPI
WNetUseConnectionA( HWND hwndOwner
, NETRESOURCEA
*resource
,
1811 LPCSTR password
, LPCSTR userid
, DWORD flags
, LPSTR accessname
,
1812 DWORD
*buffer_size
, DWORD
*result
)
1814 struct use_connection_context ctxt
;
1815 NETRESOURCEW resourceW
;
1818 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner
, resource
, password
, debugstr_a(userid
), flags
,
1819 accessname
, buffer_size
, result
);
1821 netresource_a_to_w(resource
, &resourceW
);
1823 ctxt
.hwndOwner
= hwndOwner
;
1824 ctxt
.resource
= &resourceW
;
1825 ctxt
.resourceA
= resource
;
1826 ctxt
.password
= strdupAtoW(password
);
1827 ctxt
.userid
= strdupAtoW(userid
);
1829 ctxt
.accessname
= accessname
;
1830 ctxt
.buffer_size
= buffer_size
;
1831 ctxt
.result
= result
;
1832 ctxt
.pre_set_accessname
= use_connection_pre_set_accessnameA
;
1833 ctxt
.set_accessname
= use_connection_set_accessnameA
;
1835 ret
= wnet_use_connection(&ctxt
);
1837 free_netresourceW(&resourceW
);
1838 HeapFree(GetProcessHeap(), 0, ctxt
.password
);
1839 HeapFree(GetProcessHeap(), 0, ctxt
.userid
);
1844 /*********************************************************************
1845 * WNetCancelConnectionA [MPR.@]
1847 DWORD WINAPI
WNetCancelConnectionA( LPCSTR lpName
, BOOL fForce
)
1849 return WNetCancelConnection2A(lpName
, 0, fForce
);
1852 /*********************************************************************
1853 * WNetCancelConnectionW [MPR.@]
1855 DWORD WINAPI
WNetCancelConnectionW( LPCWSTR lpName
, BOOL fForce
)
1857 return WNetCancelConnection2W(lpName
, 0, fForce
);
1860 /*********************************************************************
1861 * WNetCancelConnection2A [MPR.@]
1863 DWORD WINAPI
WNetCancelConnection2A( LPCSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1866 WCHAR
* name
= strdupAtoW(lpName
);
1868 return ERROR_NOT_CONNECTED
;
1870 ret
= WNetCancelConnection2W(name
, dwFlags
, fForce
);
1871 HeapFree(GetProcessHeap(), 0, name
);
1876 /*********************************************************************
1877 * WNetCancelConnection2W [MPR.@]
1879 DWORD WINAPI
WNetCancelConnection2W( LPCWSTR lpName
, DWORD dwFlags
, BOOL fForce
)
1881 DWORD ret
= WN_NO_NETWORK
;
1884 if (providerTable
!= NULL
)
1886 for (index
= 0; index
< providerTable
->numProviders
; index
++)
1888 if(providerTable
->table
[index
].getCaps(WNNC_CONNECTION
) &
1889 WNNC_CON_CANCELCONNECTION
)
1891 if (providerTable
->table
[index
].cancelConnection
)
1892 ret
= providerTable
->table
[index
].cancelConnection((LPWSTR
)lpName
, fForce
);
1894 ret
= WN_NO_NETWORK
;
1895 if (ret
== WN_SUCCESS
|| ret
== WN_OPEN_FILES
)
1903 /*****************************************************************
1904 * WNetRestoreConnectionA [MPR.@]
1906 DWORD WINAPI
WNetRestoreConnectionA( HWND hwndOwner
, LPCSTR lpszDevice
)
1908 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_a(lpszDevice
) );
1910 SetLastError(WN_NO_NETWORK
);
1911 return WN_NO_NETWORK
;
1914 /*****************************************************************
1915 * WNetRestoreConnectionW [MPR.@]
1917 DWORD WINAPI
WNetRestoreConnectionW( HWND hwndOwner
, LPCWSTR lpszDevice
)
1919 FIXME( "(%p, %s), stub\n", hwndOwner
, debugstr_w(lpszDevice
) );
1921 SetLastError(WN_NO_NETWORK
);
1922 return WN_NO_NETWORK
;
1925 /**************************************************************************
1926 * WNetGetConnectionA [MPR.@]
1929 * - WN_BAD_LOCALNAME lpLocalName makes no sense
1930 * - WN_NOT_CONNECTED drive is a local drive
1931 * - WN_MORE_DATA buffer isn't big enough
1932 * - WN_SUCCESS success (net path in buffer)
1934 * FIXME: need to test return values under different errors
1936 DWORD WINAPI
WNetGetConnectionA( LPCSTR lpLocalName
,
1937 LPSTR lpRemoteName
, LPDWORD lpBufferSize
)
1942 ret
= WN_BAD_POINTER
;
1943 else if (!lpBufferSize
)
1944 ret
= WN_BAD_POINTER
;
1945 else if (!lpRemoteName
&& *lpBufferSize
)
1946 ret
= WN_BAD_POINTER
;
1949 int len
= MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, NULL
, 0);
1953 PWSTR wideLocalName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1957 WCHAR wideRemoteStatic
[MAX_PATH
];
1958 DWORD wideRemoteSize
= sizeof(wideRemoteStatic
) / sizeof(WCHAR
);
1960 MultiByteToWideChar(CP_ACP
, 0, lpLocalName
, -1, wideLocalName
, len
);
1962 /* try once without memory allocation */
1963 ret
= WNetGetConnectionW(wideLocalName
, wideRemoteStatic
,
1965 if (ret
== WN_SUCCESS
)
1967 int len
= WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1968 -1, NULL
, 0, NULL
, NULL
);
1970 if (len
<= *lpBufferSize
)
1972 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
, -1,
1973 lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
1978 *lpBufferSize
= len
;
1982 else if (ret
== WN_MORE_DATA
)
1984 PWSTR wideRemote
= HeapAlloc(GetProcessHeap(), 0,
1985 wideRemoteSize
* sizeof(WCHAR
));
1989 ret
= WNetGetConnectionW(wideLocalName
, wideRemote
,
1991 if (ret
== WN_SUCCESS
)
1993 if (len
<= *lpBufferSize
)
1995 WideCharToMultiByte(CP_ACP
, 0, wideRemoteStatic
,
1996 -1, lpRemoteName
, *lpBufferSize
, NULL
, NULL
);
2001 *lpBufferSize
= len
;
2005 HeapFree(GetProcessHeap(), 0, wideRemote
);
2008 ret
= WN_OUT_OF_MEMORY
;
2010 HeapFree(GetProcessHeap(), 0, wideLocalName
);
2013 ret
= WN_OUT_OF_MEMORY
;
2016 ret
= WN_BAD_LOCALNAME
;
2020 TRACE("Returning %d\n", ret
);
2024 /* find the network connection for a given drive; helper for WNetGetConnection */
2025 static DWORD
get_drive_connection( WCHAR letter
, LPWSTR remote
, LPDWORD size
)
2028 struct mountmgr_unix_drive
*data
= (struct mountmgr_unix_drive
*)buffer
;
2030 DWORD ret
= WN_NOT_CONNECTED
;
2031 DWORD bytes_returned
;
2033 if ((mgr
= CreateFileW( MOUNTMGR_DOS_DEVICE_NAME
, GENERIC_READ
|GENERIC_WRITE
,
2034 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
2035 0, 0 )) == INVALID_HANDLE_VALUE
)
2037 ERR( "failed to open mount manager err %u\n", GetLastError() );
2040 memset( data
, 0, sizeof(*data
) );
2041 data
->letter
= letter
;
2042 if (DeviceIoControl( mgr
, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
, data
, sizeof(*data
),
2043 data
, sizeof(buffer
), &bytes_returned
, NULL
))
2045 char *p
, *mount_point
= buffer
+ data
->mount_point_offset
;
2048 if (data
->mount_point_offset
&& !strncmp( mount_point
, "unc/", 4 ))
2051 mount_point
[0] = '\\';
2052 for (p
= mount_point
; *p
; p
++) if (*p
== '/') *p
= '\\';
2054 len
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, NULL
, 0 );
2062 *size
= MultiByteToWideChar( CP_UNIXCP
, 0, mount_point
, -1, remote
, *size
);
2071 /**************************************************************************
2072 * WNetGetConnectionW [MPR.@]
2074 * FIXME: need to test return values under different errors
2076 DWORD WINAPI
WNetGetConnectionW( LPCWSTR lpLocalName
,
2077 LPWSTR lpRemoteName
, LPDWORD lpBufferSize
)
2081 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName
), lpRemoteName
,
2085 ret
= WN_BAD_POINTER
;
2086 else if (!lpBufferSize
)
2087 ret
= WN_BAD_POINTER
;
2088 else if (!lpRemoteName
&& *lpBufferSize
)
2089 ret
= WN_BAD_POINTER
;
2090 else if (!lpLocalName
[0])
2091 ret
= WN_BAD_LOCALNAME
;
2094 if (lpLocalName
[1] == ':')
2096 switch(GetDriveTypeW(lpLocalName
))
2099 ret
= get_drive_connection( lpLocalName
[0], lpRemoteName
, lpBufferSize
);
2101 case DRIVE_REMOVABLE
:
2104 TRACE("file is local\n");
2105 ret
= WN_NOT_CONNECTED
;
2108 ret
= WN_BAD_LOCALNAME
;
2112 ret
= WN_BAD_LOCALNAME
;
2116 TRACE("Returning %d\n", ret
);
2120 /**************************************************************************
2121 * WNetSetConnectionA [MPR.@]
2123 DWORD WINAPI
WNetSetConnectionA( LPCSTR lpName
, DWORD dwProperty
,
2126 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName
), dwProperty
, pvValue
);
2128 SetLastError(WN_NO_NETWORK
);
2129 return WN_NO_NETWORK
;
2132 /**************************************************************************
2133 * WNetSetConnectionW [MPR.@]
2135 DWORD WINAPI
WNetSetConnectionW( LPCWSTR lpName
, DWORD dwProperty
,
2138 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName
), dwProperty
, pvValue
);
2140 SetLastError(WN_NO_NETWORK
);
2141 return WN_NO_NETWORK
;
2144 /*****************************************************************
2145 * WNetGetUniversalNameA [MPR.@]
2147 DWORD WINAPI
WNetGetUniversalNameA ( LPCSTR lpLocalPath
, DWORD dwInfoLevel
,
2148 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2152 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2153 debugstr_a(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2155 switch (dwInfoLevel
)
2157 case UNIVERSAL_NAME_INFO_LEVEL
:
2159 LPUNIVERSAL_NAME_INFOA info
= lpBuffer
;
2161 if (GetDriveTypeA(lpLocalPath
) != DRIVE_REMOTE
)
2163 err
= ERROR_NOT_CONNECTED
;
2167 size
= sizeof(*info
) + lstrlenA(lpLocalPath
) + 1;
2168 if (*lpBufferSize
< size
)
2173 info
->lpUniversalName
= (char *)info
+ sizeof(*info
);
2174 lstrcpyA(info
->lpUniversalName
, lpLocalPath
);
2178 case REMOTE_NAME_INFO_LEVEL
:
2179 err
= WN_NO_NETWORK
;
2191 /*****************************************************************
2192 * WNetGetUniversalNameW [MPR.@]
2194 DWORD WINAPI
WNetGetUniversalNameW ( LPCWSTR lpLocalPath
, DWORD dwInfoLevel
,
2195 LPVOID lpBuffer
, LPDWORD lpBufferSize
)
2199 FIXME( "(%s, 0x%08X, %p, %p): stub\n",
2200 debugstr_w(lpLocalPath
), dwInfoLevel
, lpBuffer
, lpBufferSize
);
2202 switch (dwInfoLevel
)
2204 case UNIVERSAL_NAME_INFO_LEVEL
:
2206 LPUNIVERSAL_NAME_INFOW info
= lpBuffer
;
2208 if (GetDriveTypeW(lpLocalPath
) != DRIVE_REMOTE
)
2210 err
= ERROR_NOT_CONNECTED
;
2214 size
= sizeof(*info
) + (lstrlenW(lpLocalPath
) + 1) * sizeof(WCHAR
);
2215 if (*lpBufferSize
< size
)
2220 info
->lpUniversalName
= (LPWSTR
)((char *)info
+ sizeof(*info
));
2221 lstrcpyW(info
->lpUniversalName
, lpLocalPath
);
2225 case REMOTE_NAME_INFO_LEVEL
:
2226 err
= WN_NO_NETWORK
;
2234 if (err
!= WN_NO_ERROR
) SetLastError(err
);
2244 /**************************************************************************
2245 * WNetGetUserA [MPR.@]
2247 * FIXME: we should not return ourselves, but the owner of the drive lpName
2249 DWORD WINAPI
WNetGetUserA( LPCSTR lpName
, LPSTR lpUserID
, LPDWORD lpBufferSize
)
2251 if (GetUserNameA( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2252 return GetLastError();
2255 /*****************************************************************
2256 * WNetGetUserW [MPR.@]
2258 * FIXME: we should not return ourselves, but the owner of the drive lpName
2260 DWORD WINAPI
WNetGetUserW( LPCWSTR lpName
, LPWSTR lpUserID
, LPDWORD lpBufferSize
)
2262 if (GetUserNameW( lpUserID
, lpBufferSize
)) return WN_SUCCESS
;
2263 return GetLastError();
2266 /*********************************************************************
2267 * WNetConnectionDialog [MPR.@]
2269 DWORD WINAPI
WNetConnectionDialog( HWND hwnd
, DWORD dwType
)
2271 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2273 SetLastError(WN_NO_NETWORK
);
2274 return WN_NO_NETWORK
;
2277 /*********************************************************************
2278 * WNetConnectionDialog1A [MPR.@]
2280 DWORD WINAPI
WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct
)
2282 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2284 SetLastError(WN_NO_NETWORK
);
2285 return WN_NO_NETWORK
;
2288 /*********************************************************************
2289 * WNetConnectionDialog1W [MPR.@]
2291 DWORD WINAPI
WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct
)
2293 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2295 SetLastError(WN_NO_NETWORK
);
2296 return WN_NO_NETWORK
;
2299 /*********************************************************************
2300 * WNetDisconnectDialog [MPR.@]
2302 DWORD WINAPI
WNetDisconnectDialog( HWND hwnd
, DWORD dwType
)
2304 FIXME( "(%p, %08X): stub\n", hwnd
, dwType
);
2306 SetLastError(WN_NO_NETWORK
);
2307 return WN_NO_NETWORK
;
2310 /*********************************************************************
2311 * WNetDisconnectDialog1A [MPR.@]
2313 DWORD WINAPI
WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct
)
2315 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2317 SetLastError(WN_NO_NETWORK
);
2318 return WN_NO_NETWORK
;
2321 /*********************************************************************
2322 * WNetDisconnectDialog1W [MPR.@]
2324 DWORD WINAPI
WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct
)
2326 FIXME( "(%p): stub\n", lpConnDlgStruct
);
2328 SetLastError(WN_NO_NETWORK
);
2329 return WN_NO_NETWORK
;
2332 /*********************************************************************
2333 * WNetGetLastErrorA [MPR.@]
2335 DWORD WINAPI
WNetGetLastErrorA( LPDWORD lpError
,
2336 LPSTR lpErrorBuf
, DWORD nErrorBufSize
,
2337 LPSTR lpNameBuf
, DWORD nNameBufSize
)
2339 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2340 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2342 SetLastError(WN_NO_NETWORK
);
2343 return WN_NO_NETWORK
;
2346 /*********************************************************************
2347 * WNetGetLastErrorW [MPR.@]
2349 DWORD WINAPI
WNetGetLastErrorW( LPDWORD lpError
,
2350 LPWSTR lpErrorBuf
, DWORD nErrorBufSize
,
2351 LPWSTR lpNameBuf
, DWORD nNameBufSize
)
2353 FIXME( "(%p, %p, %d, %p, %d): stub\n",
2354 lpError
, lpErrorBuf
, nErrorBufSize
, lpNameBuf
, nNameBufSize
);
2356 SetLastError(WN_NO_NETWORK
);
2357 return WN_NO_NETWORK
;
2360 /*********************************************************************
2361 * WNetGetNetworkInformationA [MPR.@]
2363 DWORD WINAPI
WNetGetNetworkInformationA( LPCSTR lpProvider
,
2364 LPNETINFOSTRUCT lpNetInfoStruct
)
2368 TRACE( "(%s, %p)\n", debugstr_a(lpProvider
), lpNetInfoStruct
);
2371 ret
= WN_BAD_POINTER
;
2376 len
= MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, NULL
, 0);
2379 LPWSTR wideProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2383 MultiByteToWideChar(CP_ACP
, 0, lpProvider
, -1, wideProvider
,
2385 ret
= WNetGetNetworkInformationW(wideProvider
, lpNetInfoStruct
);
2386 HeapFree(GetProcessHeap(), 0, wideProvider
);
2389 ret
= WN_OUT_OF_MEMORY
;
2392 ret
= GetLastError();
2396 TRACE("Returning %d\n", ret
);
2400 /*********************************************************************
2401 * WNetGetNetworkInformationW [MPR.@]
2403 DWORD WINAPI
WNetGetNetworkInformationW( LPCWSTR lpProvider
,
2404 LPNETINFOSTRUCT lpNetInfoStruct
)
2408 TRACE( "(%s, %p)\n", debugstr_w(lpProvider
), lpNetInfoStruct
);
2411 ret
= WN_BAD_POINTER
;
2412 else if (!lpNetInfoStruct
)
2413 ret
= WN_BAD_POINTER
;
2414 else if (lpNetInfoStruct
->cbStructure
< sizeof(NETINFOSTRUCT
))
2418 if (providerTable
&& providerTable
->numProviders
)
2420 DWORD providerIndex
= _findProviderIndexW(lpProvider
);
2422 if (providerIndex
!= BAD_PROVIDER_INDEX
)
2424 lpNetInfoStruct
->cbStructure
= sizeof(NETINFOSTRUCT
);
2425 lpNetInfoStruct
->dwProviderVersion
=
2426 providerTable
->table
[providerIndex
].dwSpecVersion
;
2427 lpNetInfoStruct
->dwStatus
= NO_ERROR
;
2428 lpNetInfoStruct
->dwCharacteristics
= 0;
2429 lpNetInfoStruct
->dwHandle
= 0;
2430 lpNetInfoStruct
->wNetType
=
2431 HIWORD(providerTable
->table
[providerIndex
].dwNetType
);
2432 lpNetInfoStruct
->dwPrinters
= -1;
2433 lpNetInfoStruct
->dwDrives
= -1;
2437 ret
= WN_BAD_PROVIDER
;
2440 ret
= WN_NO_NETWORK
;
2444 TRACE("Returning %d\n", ret
);
2448 /*****************************************************************
2449 * WNetGetProviderNameA [MPR.@]
2451 DWORD WINAPI
WNetGetProviderNameA( DWORD dwNetType
,
2452 LPSTR lpProvider
, LPDWORD lpBufferSize
)
2456 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_a(lpProvider
),
2460 ret
= WN_BAD_POINTER
;
2461 else if (!lpBufferSize
)
2462 ret
= WN_BAD_POINTER
;
2469 ret
= WN_NO_NETWORK
;
2470 for (i
= 0; i
< providerTable
->numProviders
&&
2471 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2474 if (i
< providerTable
->numProviders
)
2476 DWORD sizeNeeded
= WideCharToMultiByte(CP_ACP
, 0,
2477 providerTable
->table
[i
].name
, -1, NULL
, 0, NULL
, NULL
);
2479 if (*lpBufferSize
< sizeNeeded
)
2481 *lpBufferSize
= sizeNeeded
;
2486 WideCharToMultiByte(CP_ACP
, 0, providerTable
->table
[i
].name
,
2487 -1, lpProvider
, *lpBufferSize
, NULL
, NULL
);
2489 /* FIXME: is *lpBufferSize set to the number of characters
2495 ret
= WN_NO_NETWORK
;
2499 TRACE("Returning %d\n", ret
);
2503 /*****************************************************************
2504 * WNetGetProviderNameW [MPR.@]
2506 DWORD WINAPI
WNetGetProviderNameW( DWORD dwNetType
,
2507 LPWSTR lpProvider
, LPDWORD lpBufferSize
)
2511 TRACE("(0x%08x, %s, %p)\n", dwNetType
, debugstr_w(lpProvider
),
2515 ret
= WN_BAD_POINTER
;
2516 else if (!lpBufferSize
)
2517 ret
= WN_BAD_POINTER
;
2524 ret
= WN_NO_NETWORK
;
2525 for (i
= 0; i
< providerTable
->numProviders
&&
2526 HIWORD(providerTable
->table
[i
].dwNetType
) != HIWORD(dwNetType
);
2529 if (i
< providerTable
->numProviders
)
2531 DWORD sizeNeeded
= strlenW(providerTable
->table
[i
].name
) + 1;
2533 if (*lpBufferSize
< sizeNeeded
)
2535 *lpBufferSize
= sizeNeeded
;
2540 strcpyW(lpProvider
, providerTable
->table
[i
].name
);
2542 /* FIXME: is *lpBufferSize set to the number of characters
2548 ret
= WN_NO_NETWORK
;
2552 TRACE("Returning %d\n", ret
);