2437 lines
69 KiB
C++
2437 lines
69 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
enum.cxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Contains the entry points for the WinNet Enum API supported by the
|
|||
|
Multi-Provider Router. The following functions are in this file:
|
|||
|
|
|||
|
WNetOpenEnumW
|
|||
|
WNetEnumResourceW
|
|||
|
WNetCloseEnum
|
|||
|
|
|||
|
MprOpenEnumConnect
|
|||
|
MprOpenEnumNetwork
|
|||
|
MprEnumConnect
|
|||
|
MprEnumNetwork
|
|||
|
MprProviderEnum
|
|||
|
MprCopyResource
|
|||
|
MprCopyProviderEnum
|
|||
|
MprProviderOpen
|
|||
|
MprOpenRemember
|
|||
|
MprEnumRemembered
|
|||
|
MprMultiStrBuffSize
|
|||
|
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Dan Lafferty (danl) 14-Oct-1991
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
User Mode -Win32
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
14-Oct-1991 danl
|
|||
|
created
|
|||
|
|
|||
|
21-Sep-1992 KeithMo
|
|||
|
Handle odd-sized buffers.
|
|||
|
|
|||
|
02-Nov-1992 danl
|
|||
|
Fail with NO_NETWORK if there are no providers.
|
|||
|
|
|||
|
02-Mar-1995 anirudhs
|
|||
|
Add support for RESOURCE_CONTEXT.
|
|||
|
|
|||
|
17-Jul-1995 anirudhs
|
|||
|
Add recognition (but not true support) of RESOURCE_RECENT.
|
|||
|
Clean up code for detecting top-level enum.
|
|||
|
|
|||
|
03-Aug-1995 anirudhs
|
|||
|
WNetEnumResourceW: Allow a *lpcCount of 0.
|
|||
|
|
|||
|
15-Sep-1995 anirudhs
|
|||
|
MprEnumRemembered: Fail after all resources have been enumerated.
|
|||
|
|
|||
|
24-Sep-1995 anirudhs
|
|||
|
Add support for customization of the RESOURCE_CONTEXT enumeration
|
|||
|
based on policy settings.
|
|||
|
|
|||
|
11-Apr-1996 anirudhs
|
|||
|
Use CRoutedOperation in one case of WNetOpenEnumW.
|
|||
|
|
|||
|
--*/
|
|||
|
//
|
|||
|
// INCLUDES
|
|||
|
//
|
|||
|
#include "precomp.hxx"
|
|||
|
|
|||
|
#include "mprres.h" // IDS_NETROOT
|
|||
|
#include <memory.h> // memcpy
|
|||
|
#include <lmcons.h> // needed for netlib.h
|
|||
|
#include <tstring.h> // STRLEN
|
|||
|
#include <regstr.h> // Registry keys and value names
|
|||
|
|
|||
|
//
|
|||
|
// EXTERNALS
|
|||
|
//
|
|||
|
|
|||
|
extern DWORD GlobalNumActiveProviders;
|
|||
|
extern HMODULE hDLL;
|
|||
|
|
|||
|
//
|
|||
|
// DATA STRUCTURES
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _CONNECT_HEADER{
|
|||
|
DWORD Key;
|
|||
|
DWORD ReturnRoot;
|
|||
|
}CONNECT_HEADER, *LPCONNECT_HEADER;
|
|||
|
|
|||
|
typedef struct _CONNECT_ENUM{
|
|||
|
DWORD State;
|
|||
|
HANDLE ProviderEnumHandle;
|
|||
|
}CONNECT_ENUM, *LPCONNECT_ENUM;
|
|||
|
|
|||
|
typedef struct _ENUM_HANDLE{
|
|||
|
DWORD Key;
|
|||
|
LPPROVIDER Provider;
|
|||
|
HANDLE EnumHandle;
|
|||
|
}ENUM_HANDLE, *LPENUM_HANDLE;
|
|||
|
|
|||
|
typedef struct _REMEMBER_HANDLE{
|
|||
|
DWORD Key;
|
|||
|
HKEY ConnectKey;
|
|||
|
DWORD KeyIndex;
|
|||
|
DWORD ConnectionType;
|
|||
|
}REMEMBER_HANDLE, *LPREMEMBER_HANDLE;
|
|||
|
|
|||
|
//
|
|||
|
// CONSTANTS
|
|||
|
//
|
|||
|
#define DONE 1
|
|||
|
#define MORE_ENTRIES 2
|
|||
|
#define NOT_OPENED 3
|
|||
|
#define CONNECT_TABLE_KEY 0x6e6e4f63 // "cOnn"
|
|||
|
#define STATE_TABLE_KEY 0x74417473 // "stAt"
|
|||
|
#define PROVIDER_ENUM_KEY 0x764f7270 // "prOv"
|
|||
|
#define REMEMBER_KEY 0x626D4572 // "rEmb"
|
|||
|
#define REGSTR_PATH_NETWORK_POLICIES \
|
|||
|
REGSTR_PATH_POLICIES L"\\" REGSTR_KEY_NETWORK
|
|||
|
|
|||
|
//
|
|||
|
// Macros for rounding a value up/down to a WCHAR boundary.
|
|||
|
// Note: These macros assume that sizeof(WCHAR) is a power of 2.
|
|||
|
//
|
|||
|
|
|||
|
#define ROUND_DOWN(x) ((x) & ~(sizeof(WCHAR) - 1))
|
|||
|
#define ROUND_UP(x) (((x) + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1))
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// LOCAL FUNCTION PROTOTYPES
|
|||
|
//
|
|||
|
|
|||
|
DWORD
|
|||
|
MprCopyProviderEnum(
|
|||
|
IN LPNETRESOURCEW ProviderBuffer,
|
|||
|
IN OUT LPDWORD EntryCount,
|
|||
|
IN OUT LPBYTE *TempBufPtr,
|
|||
|
IN OUT LPDWORD BytesLeft
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MprCopyResource(
|
|||
|
IN OUT LPBYTE *BufPtr,
|
|||
|
IN const NETRESOURCEW *Resource,
|
|||
|
IN OUT LPDWORD BytesLeft
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MprEnumNetwork(
|
|||
|
IN OUT LPDWORD StateTable,
|
|||
|
IN OUT LPDWORD NumEntries,
|
|||
|
IN OUT LPVOID lpBuffer,
|
|||
|
IN OUT LPDWORD lpBufferSize
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MprEnumConnect(
|
|||
|
IN OUT LPCONNECT_HEADER ConnectEnumHeader,
|
|||
|
IN OUT LPDWORD NumEntries,
|
|||
|
IN OUT LPVOID lpBuffer,
|
|||
|
IN OUT LPDWORD lpBufferSize
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MprOpenEnumNetwork(
|
|||
|
OUT LPHANDLE lphEnum
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MprOpenEnumConnect(
|
|||
|
IN DWORD dwScope,
|
|||
|
IN DWORD dwType,
|
|||
|
IN DWORD dwUsage,
|
|||
|
OUT LPHANDLE lphEnum
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MprProviderEnum(
|
|||
|
IN LPENUM_HANDLE EnumHandlePtr,
|
|||
|
IN OUT LPDWORD lpcCount,
|
|||
|
IN LPVOID lpBuffer,
|
|||
|
IN OUT LPDWORD lpBufferSize
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MprOpenRemember(
|
|||
|
IN DWORD dwType,
|
|||
|
OUT LPHANDLE lphRemember
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MprEnumRemembered(
|
|||
|
IN OUT LPREMEMBER_HANDLE RememberInfo,
|
|||
|
IN OUT LPDWORD NumEntries,
|
|||
|
IN OUT LPBYTE lpBuffer,
|
|||
|
IN OUT LPDWORD lpBufferSize
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MprMultiStrBuffSize(
|
|||
|
IN LPTSTR lpString1,
|
|||
|
IN LPTSTR lpString2,
|
|||
|
IN LPTSTR lpString3,
|
|||
|
IN LPTSTR lpString4,
|
|||
|
IN LPTSTR lpString5
|
|||
|
) ;
|
|||
|
|
|||
|
class CProviderOpenEnum : public CRoutedOperation
|
|||
|
{
|
|||
|
public:
|
|||
|
CProviderOpenEnum(
|
|||
|
DWORD dwScope,
|
|||
|
DWORD dwType,
|
|||
|
DWORD dwUsage,
|
|||
|
LPNETRESOURCEW lpNetResource,
|
|||
|
LPHANDLE lphEnum
|
|||
|
) :
|
|||
|
CRoutedOperation(DBGPARM("ProviderOpenEnum")
|
|||
|
PROVIDERFUNC(OpenEnum)),
|
|||
|
_dwScope (dwScope ),
|
|||
|
_dwType (dwType ),
|
|||
|
_dwUsage (dwUsage ),
|
|||
|
_lpNetResource(lpNetResource),
|
|||
|
_lphEnum (lphEnum )
|
|||
|
{ }
|
|||
|
|
|||
|
protected:
|
|||
|
|
|||
|
DWORD GetResult(); // overrides CRoutedOperation implementation
|
|||
|
|
|||
|
private:
|
|||
|
|
|||
|
DWORD _dwScope;
|
|||
|
DWORD _dwType;
|
|||
|
DWORD _dwUsage;
|
|||
|
LPNETRESOURCEW _lpNetResource;
|
|||
|
LPHANDLE _lphEnum;
|
|||
|
|
|||
|
HANDLE _ProviderEnumHandle; // Enum handle returned by provider
|
|||
|
|
|||
|
DECLARE_CROUTED
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
WNetOpenEnumW (
|
|||
|
IN DWORD dwScope,
|
|||
|
IN DWORD dwType,
|
|||
|
IN DWORD dwUsage,
|
|||
|
IN LPNETRESOURCEW lpNetResource,
|
|||
|
OUT LPHANDLE lphEnum
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This API is used to open an enumeration of network resources or existing
|
|||
|
connections. It must be called to obtain a valid handle for enumeration.
|
|||
|
|
|||
|
NOTE:
|
|||
|
For GlobalNet Enum, the caller must get a new handle for each level that
|
|||
|
is desired. For the other scopes, the caller gets a single handle and
|
|||
|
with that can enumerate all resources.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
dwScope - Determines the scope of the enumeration. This can be one of:
|
|||
|
RESOURCE_CONNECTED - All Currently connected resources.
|
|||
|
RESOURCE_GLOBALNET - All resources on the network.
|
|||
|
RESOURCE_REMEMBERED - All persistent connections.
|
|||
|
RESOURCE_RECENT - Same as RESOURCE_REMEMBERED (supported for Win95
|
|||
|
semi-compatibility)
|
|||
|
RESOURCE_CONTEXT - The resources associated with the user's current
|
|||
|
and default network context (as defined by the providers).
|
|||
|
|
|||
|
dwType - Used to specify the type of resources on interest. This is a
|
|||
|
bitmask which may be any combination of:
|
|||
|
RESOURCETYPE_DISK - All disk resources
|
|||
|
RESOURCETYPE_PRINT - All print resources
|
|||
|
If this is 0. all types of resources are returned. If a provider does
|
|||
|
not have the capability to distinguish between print and disk
|
|||
|
resources at a level, it may return all resources.
|
|||
|
|
|||
|
dwUsage - Used to specify the usage of resources of interest. This is a
|
|||
|
bitmask which may be any combination of:
|
|||
|
RESOURCEUSAGE_CONNECTABLE - all connectable resources.
|
|||
|
RESOURCEUSAGE_CONTAINER - all container resources.
|
|||
|
The bitmask may be 0 to match all.
|
|||
|
|
|||
|
lpNetResource - This specifies the container to perform the enumeration.
|
|||
|
If it is NULL, the logical root of the network is assumed, and the
|
|||
|
router is responsible for obtaining the information for return.
|
|||
|
|
|||
|
lphEnum - If the Open was successful, this will contain a handle that
|
|||
|
can be used for future calls to WNetEnumResource.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
WN_SUCCESS - Indicates the operation was successful.
|
|||
|
|
|||
|
WN_NOT_CONTAINER - Indicates that lpNetResource does not point to a
|
|||
|
container.
|
|||
|
|
|||
|
WN_BAD_VALUE - Invalid dwScope or dwType, or bad combination of parameters
|
|||
|
is specified.
|
|||
|
|
|||
|
WN_NO_NETWORK - network is not present.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD status = WN_SUCCESS;
|
|||
|
|
|||
|
INIT_IF_NECESSARY(NETWORK_LEVEL,status);
|
|||
|
|
|||
|
//
|
|||
|
// dwScope MUST be set to either GLOBALNET or CONNECTED or REMEMBERED
|
|||
|
// or RECENT or CONTEXT.
|
|||
|
// This is verified in the switch statement below.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// dwType is a bit mask that can have any combination of the DISK
|
|||
|
// or PRINT bits set. Or it can be the value 0.
|
|||
|
//
|
|||
|
if (dwType & ~(RESOURCETYPE_DISK | RESOURCETYPE_PRINT)) {
|
|||
|
status = WN_BAD_VALUE;
|
|||
|
goto CleanExit;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// dwUsage is a bit mask that can have any combination of the CONNECTABLE
|
|||
|
// or CONTAINER bits set. Or it can be the value 0. This field is
|
|||
|
// ignored if dwScope is not RESOURCE_GLOBALNET.
|
|||
|
//
|
|||
|
if (dwScope == RESOURCE_GLOBALNET) {
|
|||
|
if (dwUsage & ~(RESOURCEUSAGE_ALL)) {
|
|||
|
status = WN_BAD_VALUE;
|
|||
|
goto CleanExit;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if it is a top-level enum request.
|
|||
|
//
|
|||
|
if (lpNetResource == NULL ||
|
|||
|
(IS_EMPTY_STRING(lpNetResource->lpProvider) &&
|
|||
|
IS_EMPTY_STRING(lpNetResource->lpRemoteName))) {
|
|||
|
//
|
|||
|
// lpNetResource is NULL or represents no resource.
|
|||
|
// This is a top-level enum request, therefore, the MPR must provide
|
|||
|
// the information.
|
|||
|
//
|
|||
|
switch(dwScope) {
|
|||
|
|
|||
|
case RESOURCE_CONNECTED:
|
|||
|
case RESOURCE_CONTEXT:
|
|||
|
if (MprNetIsAvailable())
|
|||
|
status = MprOpenEnumConnect(dwScope, dwType, dwUsage, lphEnum);
|
|||
|
else
|
|||
|
status = WN_NO_NETWORK ;
|
|||
|
break;
|
|||
|
|
|||
|
case RESOURCE_GLOBALNET:
|
|||
|
if (MprNetIsAvailable())
|
|||
|
status = MprOpenEnumNetwork(lphEnum);
|
|||
|
else
|
|||
|
status = WN_NO_NETWORK ;
|
|||
|
break;
|
|||
|
|
|||
|
case RESOURCE_REMEMBERED:
|
|||
|
case RESOURCE_RECENT:
|
|||
|
MPR_LOG(TRACE,"OpenEnum RESOURCE_REMEMBERED\n",0);
|
|||
|
status = MprOpenRemember(dwType, lphEnum);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
status = WN_BAD_VALUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// Request is for one of the providers. It should be for a
|
|||
|
// GLOBALNET enumeration. It is not allowed to request any
|
|||
|
// other type of enumeration with a pointer to a resource
|
|||
|
// buffer.
|
|||
|
//
|
|||
|
if (dwScope != RESOURCE_GLOBALNET) {
|
|||
|
status = WN_BAD_VALUE;
|
|||
|
goto CleanExit;
|
|||
|
}
|
|||
|
|
|||
|
CProviderOpenEnum ProviderOpenEnum(
|
|||
|
dwScope,
|
|||
|
dwType,
|
|||
|
dwUsage,
|
|||
|
lpNetResource,
|
|||
|
lphEnum);
|
|||
|
|
|||
|
status = ProviderOpenEnum.Perform();
|
|||
|
}
|
|||
|
|
|||
|
CleanExit:
|
|||
|
if (status != WN_SUCCESS) {
|
|||
|
SetLastError(status);
|
|||
|
}
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WNetEnumResourceW (
|
|||
|
IN HANDLE hEnum,
|
|||
|
IN OUT LPDWORD lpcCount,
|
|||
|
OUT LPVOID lpBuffer,
|
|||
|
IN OUT LPDWORD lpBufferSize
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is used to obtain an array of NETRESOURCE structures each
|
|||
|
of which describes a network resource.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hEnum - This is a handle that was obtained from an WNetOpenEnum call.
|
|||
|
|
|||
|
lpcCount - Specifies the number of entries requested. -1 indicates
|
|||
|
as many entries as possible are requested. If the operation is
|
|||
|
successful, this location will receive the number of entries
|
|||
|
actually read.
|
|||
|
|
|||
|
lpBuffer - A pointer to the buffer to receive the enumeration result,
|
|||
|
which are returned as an array of NETRESOURCE entries. The buffer
|
|||
|
is valid until the next call using hEnum.
|
|||
|
|
|||
|
lpBufferSize - This specifies the size of the buffer passed to the function
|
|||
|
call. It will contain the required buffer size if WN_MORE_DATA is
|
|||
|
returned.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
WN_SUCCESS - Indicates that the call is successful, and that the caller
|
|||
|
should continue to call WNetEnumResource to continue the enumeration.
|
|||
|
|
|||
|
WN_NO_MORE_ENTRIES - Indicates that the enumeration completed successfully.
|
|||
|
|
|||
|
The following return codes indicate an error occured and GetLastError
|
|||
|
may be used to obtain another copy of the error code:
|
|||
|
|
|||
|
WN_MORE_DATA - Indicates that the buffer is too small for even one
|
|||
|
entry.
|
|||
|
|
|||
|
WN_BAD_HANDLE - hEnum is not a valid handle.
|
|||
|
|
|||
|
WN_NO_NETWORK - The Network is not present. This condition is checked
|
|||
|
for before hEnum is tested for validity.
|
|||
|
|
|||
|
History:
|
|||
|
12-Feb-1992 Johnl Removed requirement that buffersize must be at
|
|||
|
least as large as NETRESOURCEW (bug 5790)
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD status = WN_SUCCESS;
|
|||
|
|
|||
|
INIT_IF_NECESSARY(NETWORK_LEVEL,status);
|
|||
|
|
|||
|
//
|
|||
|
// Screen the parameters as best we can.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Probe the handle
|
|||
|
//
|
|||
|
__try {
|
|||
|
*(volatile DWORD *)hEnum;
|
|||
|
}
|
|||
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
status = GetExceptionCode();
|
|||
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|||
|
MPR_LOG(ERROR,"WNetEnumResource:Unexpected Exception 0x%lx\n",status);
|
|||
|
}
|
|||
|
status = WN_BAD_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
__try {
|
|||
|
PROBE_FOR_WRITE(lpcCount);
|
|||
|
|
|||
|
if (IS_BAD_BYTE_BUFFER(lpBuffer, lpBufferSize)) {
|
|||
|
status = WN_BAD_POINTER;
|
|||
|
}
|
|||
|
}
|
|||
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
|
|||
|
status = GetExceptionCode();
|
|||
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|||
|
MPR_LOG(ERROR,"WNetEnumResource:Unexpected Exception 0x%lx\n",status);
|
|||
|
}
|
|||
|
status = WN_BAD_POINTER;
|
|||
|
}
|
|||
|
|
|||
|
if (status != WN_SUCCESS) {
|
|||
|
goto CleanExit;
|
|||
|
}
|
|||
|
|
|||
|
switch(*(LPDWORD)hEnum){
|
|||
|
case CONNECT_TABLE_KEY:
|
|||
|
//
|
|||
|
// Call on Providers to enumerate connections.
|
|||
|
//
|
|||
|
status = MprEnumConnect(
|
|||
|
(LPCONNECT_HEADER)hEnum, // key is part of structure
|
|||
|
lpcCount,
|
|||
|
lpBuffer,
|
|||
|
lpBufferSize);
|
|||
|
break;
|
|||
|
|
|||
|
case STATE_TABLE_KEY:
|
|||
|
//
|
|||
|
// Enumerate the top level NetResource structure maintained by
|
|||
|
// the router.
|
|||
|
//
|
|||
|
status = MprEnumNetwork(
|
|||
|
(LPDWORD)hEnum + 1, // Point beyond the key
|
|||
|
lpcCount,
|
|||
|
lpBuffer,
|
|||
|
lpBufferSize);
|
|||
|
break;
|
|||
|
|
|||
|
case PROVIDER_ENUM_KEY:
|
|||
|
//
|
|||
|
// Call on providers to enumerate resources on the network.
|
|||
|
//
|
|||
|
status = MprProviderEnum(
|
|||
|
(LPENUM_HANDLE)hEnum, // key is part of structure
|
|||
|
lpcCount,
|
|||
|
lpBuffer,
|
|||
|
lpBufferSize);
|
|||
|
break;
|
|||
|
case REMEMBER_KEY:
|
|||
|
|
|||
|
//
|
|||
|
// Enumerate the connections in the current user section of the
|
|||
|
// registry.
|
|||
|
//
|
|||
|
|
|||
|
status = MprEnumRemembered(
|
|||
|
(LPREMEMBER_HANDLE)hEnum,
|
|||
|
lpcCount,
|
|||
|
(LPBYTE)lpBuffer,
|
|||
|
lpBufferSize);
|
|||
|
break;
|
|||
|
default:
|
|||
|
status = WN_BAD_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
CleanExit:
|
|||
|
if(status != WN_SUCCESS) {
|
|||
|
SetLastError(status);
|
|||
|
}
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
WNetCloseEnum (
|
|||
|
IN HANDLE hEnum
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Closes an enumeration handle that is owned by the router.
|
|||
|
In cases where the router is acting as a proxy for a single provider,
|
|||
|
an attempt is made to return any error information from this provider
|
|||
|
back to the user. This makes the router as transparent as possible.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hEnum - This must be a handle obtained from a call to WNetOpenEnum.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
WN_SUCCESS - The operation was successful.
|
|||
|
|
|||
|
WN_NO_NETWORK - The Network is not present. This condition is checked
|
|||
|
before hEnum is tested for validity.
|
|||
|
|
|||
|
WN_BAD_HANDLE - hEnum is not a valid handle.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD status=WN_SUCCESS;
|
|||
|
LPCONNECT_ENUM connectEnumTable;
|
|||
|
LPENUM_HANDLE enumHandle;
|
|||
|
LPREMEMBER_HANDLE rememberHandle;
|
|||
|
DWORD i;
|
|||
|
LPPROVIDER provider;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
INIT_IF_NECESSARY(NETWORK_LEVEL,status);
|
|||
|
|
|||
|
//
|
|||
|
// Probe the handle
|
|||
|
//
|
|||
|
__try {
|
|||
|
*(volatile DWORD *)hEnum;
|
|||
|
}
|
|||
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
status = GetExceptionCode();
|
|||
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|||
|
MPR_LOG(ERROR,"WNetCloseEnum:Unexpected Exception 0x%lx\n",status);
|
|||
|
}
|
|||
|
|
|||
|
status = WN_BAD_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
if (status != WN_SUCCESS) {
|
|||
|
SetLastError(WN_BAD_HANDLE);
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Use hEnum as a pointer and check the DWORD value at its location.
|
|||
|
// If it contains a CONNECT_TABLE_KEY, we must close all handles to
|
|||
|
// the providers before freeing the memory for the table.
|
|||
|
// If it is a STATE_TABLE_KEY, we just free the memory.
|
|||
|
//
|
|||
|
switch(*(LPDWORD)hEnum){
|
|||
|
|
|||
|
case CONNECT_TABLE_KEY:
|
|||
|
|
|||
|
connectEnumTable = (LPCONNECT_ENUM)((LPCONNECT_HEADER)hEnum + 1);
|
|||
|
//
|
|||
|
// Close all the open provider handles
|
|||
|
//
|
|||
|
MPR_LOG(TRACE,"Closing Connection Enum Handles from Providers\n",0);
|
|||
|
|
|||
|
for(i=0; i<GlobalNumProviders; i++) {
|
|||
|
|
|||
|
provider = GlobalProviderInfo + i;
|
|||
|
|
|||
|
if((connectEnumTable[i].State != NOT_OPENED) &&
|
|||
|
(provider->CloseEnum != NULL)) {
|
|||
|
|
|||
|
status = provider->CloseEnum(
|
|||
|
connectEnumTable[i].ProviderEnumHandle);
|
|||
|
|
|||
|
if(status != WN_SUCCESS) {
|
|||
|
//
|
|||
|
// Because we are closing many handles at once, the failure
|
|||
|
// is noted for debug purposes only.
|
|||
|
//
|
|||
|
MPR_LOG(ERROR,"WNetCloseEnum:(connect-provider #%d) failed\n",i);
|
|||
|
MPR_LOG(ERROR,"WNetCloseEnum: error code = %d\n",status);
|
|||
|
//
|
|||
|
// Error information is returned if there is only one
|
|||
|
// provider.
|
|||
|
//
|
|||
|
if (GlobalNumProviders != 1) {
|
|||
|
status = WN_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
//
|
|||
|
// Free the Table Memory
|
|||
|
//
|
|||
|
if (LocalFree(hEnum)) {
|
|||
|
MPR_LOG(ERROR,"WNetCloseEnum:LocalFree(connect) failed %d\n",
|
|||
|
GetLastError());
|
|||
|
}
|
|||
|
if (status != WN_SUCCESS)
|
|||
|
{
|
|||
|
SetLastError(status);
|
|||
|
}
|
|||
|
return(status);
|
|||
|
|
|||
|
case STATE_TABLE_KEY:
|
|||
|
//
|
|||
|
// Free the State Table Memory.
|
|||
|
//
|
|||
|
MPR_LOG(TRACE,"Free State Table for Network Enum\n",0);
|
|||
|
|
|||
|
if (LocalFree((PDWORD)hEnum)) {
|
|||
|
MPR_LOG(ERROR,"WNetCloseEnum:LocalFree(network) failed %d\n",
|
|||
|
GetLastError());
|
|||
|
}
|
|||
|
return(WN_SUCCESS);
|
|||
|
|
|||
|
case PROVIDER_ENUM_KEY:
|
|||
|
//
|
|||
|
// Close the providers enumeration handle, and free the
|
|||
|
// ENUM_HANDLE structure.
|
|||
|
//
|
|||
|
MPR_LOG(TRACE,"Closing Provider Enum Handle\n",0);
|
|||
|
|
|||
|
enumHandle = (LPENUM_HANDLE)hEnum;
|
|||
|
status = (enumHandle->Provider->CloseEnum)(enumHandle->EnumHandle);
|
|||
|
|
|||
|
if (LocalFree(enumHandle)!=0) {
|
|||
|
MPR_LOG(ERROR,"WNetCloseEnum:LocalFree(provider) failed %d\n",
|
|||
|
GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check the status returned from the Provider's CloseEnum
|
|||
|
//
|
|||
|
if(status != WN_SUCCESS) {
|
|||
|
|
|||
|
MPR_LOG(ERROR,"WNetCloseEnum:(provider) failed %d\n",status);
|
|||
|
|
|||
|
SetLastError(status);
|
|||
|
}
|
|||
|
|
|||
|
return(status);
|
|||
|
|
|||
|
case REMEMBER_KEY:
|
|||
|
|
|||
|
rememberHandle = (LPREMEMBER_HANDLE)hEnum;
|
|||
|
|
|||
|
//
|
|||
|
// Close the RegistryKey Handle associated with this handle.
|
|||
|
//
|
|||
|
if (rememberHandle->ConnectKey != NULL) {
|
|||
|
RegCloseKey(rememberHandle->ConnectKey);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free up the memory for the handle.
|
|||
|
//
|
|||
|
|
|||
|
if (LocalFree(rememberHandle)!=0) {
|
|||
|
MPR_LOG(ERROR,"WNetCloseEnum:LocalFree(remember) failed %d\n",
|
|||
|
GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
return(WN_SUCCESS);
|
|||
|
|
|||
|
default:
|
|||
|
SetLastError(WN_BAD_HANDLE);
|
|||
|
return(WN_BAD_HANDLE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MprOpenEnumConnect(
|
|||
|
IN DWORD dwScope,
|
|||
|
IN DWORD dwType,
|
|||
|
IN DWORD dwUsage,
|
|||
|
OUT LPHANDLE lphEnum
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function handles the opening of connection enumerations and context
|
|||
|
enumerations. It does this by sending an OpenEnum to all Providers, and
|
|||
|
storing the returned handles in a table. The handle that is returned is
|
|||
|
a pointer to this table.
|
|||
|
|
|||
|
The first DWORD in the table is a key that will help to identify a
|
|||
|
correct table. The second DWORD is a Boolean value that tells whether
|
|||
|
a NETRESOURCE structure representing the root of the network needs to be
|
|||
|
returned in the enumeration.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
dwScope - Either RESOURCE_CONNECTED or RESOURCE_CONTEXT
|
|||
|
|
|||
|
dwType -
|
|||
|
|
|||
|
dwUsage -
|
|||
|
|
|||
|
lphEnum - This is a pointer to a location where the handle for
|
|||
|
the connection enumeration is to be stored.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
WN_SUCCESS - The operation was successful.
|
|||
|
|
|||
|
WN_OUT_OF_MEMORY - The memory allocation for the handle was unsuccessful.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD i;
|
|||
|
DWORD status;
|
|||
|
LPCONNECT_HEADER connectEnumHeader;
|
|||
|
LPCONNECT_ENUM connectEnumTable;
|
|||
|
LPPROVIDER provider;
|
|||
|
BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
|
|||
|
BOOL atLeastOne=FALSE;
|
|||
|
BOOL bDynamicEntries = TRUE; // Whether to show dynamic entries
|
|||
|
// in the net neighborhood
|
|||
|
HKEY hkPolicies = NULL;
|
|||
|
|
|||
|
ASSERT(dwScope == RESOURCE_CONNECTED || dwScope == RESOURCE_CONTEXT);
|
|||
|
|
|||
|
//
|
|||
|
// If there are no providers, return NO_NETWORK
|
|||
|
//
|
|||
|
if (GlobalNumActiveProviders == 0) {
|
|||
|
return(WN_NO_NETWORK);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate the handle table with enough room for a header.
|
|||
|
//
|
|||
|
connectEnumHeader = (LPCONNECT_HEADER) LocalAlloc(
|
|||
|
LPTR,
|
|||
|
sizeof(CONNECT_HEADER) +
|
|||
|
(sizeof(CONNECT_ENUM)*(GlobalNumProviders))
|
|||
|
);
|
|||
|
|
|||
|
if (connectEnumHeader == NULL) {
|
|||
|
MPR_LOG(ERROR,"MprOpenEnumConnect:LocalAlloc Failed %d\n",GetLastError());
|
|||
|
return(WN_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the key used in the connect table.
|
|||
|
//
|
|||
|
connectEnumHeader->Key = CONNECT_TABLE_KEY;
|
|||
|
connectEnumHeader->ReturnRoot = FALSE;
|
|||
|
connectEnumTable = (LPCONNECT_ENUM)(connectEnumHeader + 1);
|
|||
|
|
|||
|
//
|
|||
|
// Check the policy on whether dynamic entries are to be shown in the
|
|||
|
// network neighborhood. By default, they are shown.
|
|||
|
//
|
|||
|
if (dwScope == RESOURCE_CONTEXT)
|
|||
|
{
|
|||
|
if (MprOpenKey(
|
|||
|
HKEY_CURRENT_USER,
|
|||
|
REGSTR_PATH_NETWORK_POLICIES,
|
|||
|
&hkPolicies,
|
|||
|
KEY_READ))
|
|||
|
{
|
|||
|
bDynamicEntries = ! (MprGetKeyNumberValue(
|
|||
|
hkPolicies,
|
|||
|
REGSTR_VAL_NOWORKGROUPCONTENTS,
|
|||
|
FALSE));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
hkPolicies = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize all state flags for providers to the NOT_OPENED state, so
|
|||
|
// we won't try to enumerate or close their handles unless we actually
|
|||
|
// got handles from them.
|
|||
|
// Initialize handles for the network providers by calling them with
|
|||
|
// OpenEnum.
|
|||
|
//
|
|||
|
|
|||
|
for(i=0; i<GlobalNumProviders; i++) {
|
|||
|
|
|||
|
connectEnumTable[i].State = NOT_OPENED;
|
|||
|
|
|||
|
provider = GlobalProviderInfo + i;
|
|||
|
|
|||
|
if ((provider->InitClass & NETWORK_TYPE) &&
|
|||
|
(provider->OpenEnum != NULL)) {
|
|||
|
|
|||
|
if (dwScope == RESOURCE_CONTEXT)
|
|||
|
{
|
|||
|
DWORD dwCaps = provider->GetCaps(WNNC_ENUMERATION);
|
|||
|
|
|||
|
if (dwCaps & WNNC_ENUM_GLOBAL)
|
|||
|
{
|
|||
|
// A browsing network is present, so show root,
|
|||
|
// even if network is down, and even if ENUM_CONTEXT
|
|||
|
// isn't supported.
|
|||
|
connectEnumHeader->ReturnRoot = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if ((dwCaps & WNNC_ENUM_CONTEXT) == 0)
|
|||
|
{
|
|||
|
// This provider can't show hood entries, so skip it.
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
fcnSupported = TRUE;
|
|||
|
|
|||
|
if (bDynamicEntries)
|
|||
|
{
|
|||
|
status = provider->OpenEnum(
|
|||
|
dwScope, // Scope
|
|||
|
dwType, // Type
|
|||
|
dwUsage, // Usage
|
|||
|
NULL, // NetResource
|
|||
|
&(connectEnumTable[i].ProviderEnumHandle)); // hEnum
|
|||
|
|
|||
|
if (status != WN_SUCCESS) {
|
|||
|
|
|||
|
MPR_LOG(ERROR,"MprOpenEnumConnect:OpenEnum Failed %d\n",status);
|
|||
|
MPR_LOG(ERROR,
|
|||
|
"That was for the %ws Provider\n",
|
|||
|
provider->Resource.lpProvider);
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// At least one provider has returned a handle.
|
|||
|
//
|
|||
|
atLeastOne = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Set the state to MORE_ENTRIES, so we later enumerate from the
|
|||
|
// handle and/or close it.
|
|||
|
//
|
|||
|
connectEnumTable[i].State = MORE_ENTRIES;
|
|||
|
|
|||
|
MPR_LOG(TRACE,"MprOpenEnumConnect: OpenEnum Handle = 0x%lx\n",
|
|||
|
connectEnumTable[i].ProviderEnumHandle);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Succeed the WNetOpenEnum but leave this provider as NOT_OPENED
|
|||
|
atLeastOne = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (connectEnumHeader->ReturnRoot)
|
|||
|
{
|
|||
|
// Able to show the root object. Check the policy on whether
|
|||
|
// to show it.
|
|||
|
connectEnumHeader->ReturnRoot = ! (MprGetKeyNumberValue(
|
|||
|
hkPolicies,
|
|||
|
REGSTR_VAL_NOENTIRENETWORK,
|
|||
|
FALSE));
|
|||
|
fcnSupported = TRUE;
|
|||
|
atLeastOne = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if (hkPolicies)
|
|||
|
{
|
|||
|
RegCloseKey(hkPolicies);
|
|||
|
}
|
|||
|
|
|||
|
if (fcnSupported == FALSE) {
|
|||
|
//
|
|||
|
// No providers in the list support the API function. Therefore,
|
|||
|
// we assume that no networks are installed.
|
|||
|
// Note that in this case, atLeastOne will always be FALSE.
|
|||
|
//
|
|||
|
status = WN_NOT_SUPPORTED;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// return the handle (pointer to connectEnumTable);
|
|||
|
//
|
|||
|
*lphEnum = connectEnumHeader;
|
|||
|
|
|||
|
if (atLeastOne == FALSE) {
|
|||
|
//
|
|||
|
// If none of the providers returned a handle, then return the
|
|||
|
// status from the last provider.
|
|||
|
//
|
|||
|
|
|||
|
*lphEnum = NULL;
|
|||
|
LocalFree( connectEnumHeader);
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
return(WN_SUCCESS);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MprOpenEnumNetwork(
|
|||
|
OUT LPHANDLE lphEnum
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function handles the opening of net resource enumerations.
|
|||
|
It does this by allocating a table of Provider State Flags and returning
|
|||
|
a handle to that table. The state flags (or for each provider) will
|
|||
|
be set to MORE_ENTRIES. Later, when enumerations take place, the state
|
|||
|
for each provider is changed to DONE after the buffer is successfully
|
|||
|
loaded with the the NETRESOURCE info for that provider.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
lphEnum - This is a pointer to a location where the handle for
|
|||
|
the network resource enumeration is to be stored.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
WN_SUCCESS - The operation was successful.
|
|||
|
|
|||
|
WN_OUT_OF_MEMORY - The memory allocation for the handle was unsuccessful.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LPDWORD stateTable;
|
|||
|
LPDWORD stateTableKeyPtr;
|
|||
|
DWORD i;
|
|||
|
|
|||
|
//
|
|||
|
// If there are no providers, return NO_NETWORK
|
|||
|
//
|
|||
|
if (GlobalNumActiveProviders == 0) {
|
|||
|
return(WN_NO_NETWORK);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate the state table with enough room for a key.
|
|||
|
//
|
|||
|
stateTableKeyPtr = (DWORD *) LocalAlloc(
|
|||
|
LPTR,
|
|||
|
sizeof(DWORD) * (GlobalNumProviders+1));
|
|||
|
|
|||
|
if (stateTableKeyPtr == NULL) {
|
|||
|
MPR_LOG(ERROR,"MprOpenEnumNetwork:LocalAlloc Failed %d\n",GetLastError());
|
|||
|
return(WN_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
*stateTableKeyPtr = STATE_TABLE_KEY;
|
|||
|
stateTable = stateTableKeyPtr + 1;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize state flags for all network providers to the MORE_ENTRIES state.
|
|||
|
//
|
|||
|
for(i=0; i<GlobalNumProviders; i++) {
|
|||
|
if (GlobalProviderInfo[i].InitClass & NETWORK_TYPE) {
|
|||
|
stateTable[i]=MORE_ENTRIES;
|
|||
|
}
|
|||
|
else {
|
|||
|
stateTable[i]=DONE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// return the handle (pointer to stateTable);
|
|||
|
//
|
|||
|
*lphEnum = stateTableKeyPtr;
|
|||
|
|
|||
|
return(WN_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MprEnumConnect(
|
|||
|
IN OUT LPCONNECT_HEADER ConnectEnumHeader,
|
|||
|
IN OUT LPDWORD NumEntries,
|
|||
|
IN OUT LPVOID lpBuffer,
|
|||
|
IN OUT LPDWORD lpBufferSize
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function looks in the ConnectEnumTable for the next provider that
|
|||
|
has MORE_ENTRIES. It begins requesting Enum Data from that provider -
|
|||
|
each time copying data that is returned from the provider enum into the
|
|||
|
users enum buffer (lpBuffer). This continues until we finish, or
|
|||
|
we reach the requested number of elements, or the user buffer is full.
|
|||
|
Each time we enumerate a provider to completion, that provider is
|
|||
|
marked as DONE.
|
|||
|
|
|||
|
Note, for a context enumeration, the first NETRESOURCE returned in the
|
|||
|
enumeration is a constant NETRESOURCE representing the root of the
|
|||
|
network. This is done to make it easy for the shell to display a
|
|||
|
"Rest of Network" object in a "Network Neighborhood" view.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ConnectEnumHeader - This is a pointer to a CONNECT_HEADER structure
|
|||
|
followed by an array of CONNECT_ENUM structures. The ReturnRoot
|
|||
|
member of the header tells whether the root object needs to be
|
|||
|
returned at the start of the enumeration. On exit, if the root
|
|||
|
object has been returned, the ReturnRoot member is set to FALSE.
|
|||
|
|
|||
|
NumEntries - On entry this points to the maximum number of entries
|
|||
|
that the user desires to receive. On exit it points to the
|
|||
|
number of entries that were placed in the users buffer.
|
|||
|
|
|||
|
lpBuffer - This is a pointer to the users buffer in which the
|
|||
|
enumeration data is to be placed.
|
|||
|
|
|||
|
lpBufferSize - This is the size (in bytes) of the users buffer. It will
|
|||
|
be set to the size of the required buffer size of WN_MORE_DATA is
|
|||
|
returned.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
WN_SUCCESS - This indicates that the call is returning some entries.
|
|||
|
However, the enumeration is not complete due to one of the following:
|
|||
|
1) There was not enough buffer space.
|
|||
|
2) The requested number of entries was reached.
|
|||
|
3) There is no more data to enumerate - the next call will
|
|||
|
return WN_NO_MORE_ENTRIES.
|
|||
|
|
|||
|
WN_MORE_DATA - This indicates that the buffer was not large enough
|
|||
|
to receive one enumeration entry.
|
|||
|
|
|||
|
WN_NO_MORE_ENTRIES - This indicates that there are no more entries
|
|||
|
to enumerate. No data is returned with this return code.
|
|||
|
|
|||
|
WN_NO_NETWORK - If there are no providers loaded.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
DWORD i; // provider index
|
|||
|
DWORD status=WN_NO_MORE_ENTRIES;
|
|||
|
DWORD entriesRead=0; // number of entries read into the buffer.
|
|||
|
LPBYTE tempBufPtr; // pointer to top of remaining free buffer space.
|
|||
|
LPNETRESOURCEW providerBuffer; // buffer for data returned from provider
|
|||
|
DWORD bytesLeft; // Numer of bytes left in the buffer
|
|||
|
DWORD entryCount; // number of entries read from provider
|
|||
|
LPCONNECT_ENUM ConnectEnumTable = (LPCONNECT_ENUM) (ConnectEnumHeader + 1);
|
|||
|
// Start of array
|
|||
|
|
|||
|
//
|
|||
|
// If there are no providers, return NO_NETWORK
|
|||
|
//
|
|||
|
if (GlobalNumActiveProviders == 0) {
|
|||
|
return(WN_NO_NETWORK);
|
|||
|
}
|
|||
|
|
|||
|
bytesLeft = ROUND_DOWN(*lpBufferSize);
|
|||
|
tempBufPtr = (LPBYTE) lpBuffer;
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if there are any flags in state table that indicate
|
|||
|
// MORE_ENTRIES. If not, we want to return WN_NO_MORE_ENTRIES.
|
|||
|
//
|
|||
|
|
|||
|
for(i=0; i<GlobalNumProviders; i++) {
|
|||
|
if(ConnectEnumTable[i].State == MORE_ENTRIES) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( (i == GlobalNumProviders) && (! ConnectEnumHeader->ReturnRoot) ) {
|
|||
|
*NumEntries = 0;
|
|||
|
return(WN_NO_MORE_ENTRIES);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If no entries are requested, we have nothing to do
|
|||
|
//
|
|||
|
if (*NumEntries == 0) {
|
|||
|
return WN_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer for the provider to return data in.
|
|||
|
// The buffer size must equal the number of bytes left in the
|
|||
|
// user buffer.
|
|||
|
// (We can't have the provider write data directly to the caller's
|
|||
|
// buffer because NPEnumResource is not required to place strings
|
|||
|
// at the end of the buffer -- only at the end of the array of
|
|||
|
// NETRESOURCEs.)
|
|||
|
//
|
|||
|
providerBuffer = (LPNETRESOURCEW) LocalAlloc(LPTR, bytesLeft);
|
|||
|
if (providerBuffer == NULL) {
|
|||
|
MPR_LOG(ERROR,"MprEnumConnect:LocalAlloc Failed %d\n",
|
|||
|
GetLastError());
|
|||
|
|
|||
|
*NumEntries = 0;
|
|||
|
return(WN_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Copy the root-of-network resource if required.
|
|||
|
//
|
|||
|
if (ConnectEnumHeader->ReturnRoot)
|
|||
|
{
|
|||
|
static WCHAR wszEntireNetwork[40];
|
|||
|
NETRESOURCEW RootResource = {
|
|||
|
RESOURCE_GLOBALNET, // dwScope
|
|||
|
RESOURCETYPE_ANY, // dwType
|
|||
|
RESOURCEDISPLAYTYPE_ROOT, // dwDisplayType
|
|||
|
RESOURCEUSAGE_CONTAINER, // dwUsage
|
|||
|
NULL, // lpLocalName
|
|||
|
NULL, // lpRemoteName
|
|||
|
wszEntireNetwork, // lpComment
|
|||
|
NULL // lpProvider
|
|||
|
};
|
|||
|
|
|||
|
//
|
|||
|
// Load the "Entire Network" string if it hasn't been loaded already
|
|||
|
//
|
|||
|
if (wszEntireNetwork[0] == L'\0')
|
|||
|
{
|
|||
|
int cch = LoadString(hDLL,
|
|||
|
IDS_NETROOT,
|
|||
|
wszEntireNetwork,
|
|||
|
LENGTH(wszEntireNetwork));
|
|||
|
ASSERT(cch > 0 && cch < LENGTH(wszEntireNetwork));
|
|||
|
}
|
|||
|
|
|||
|
status = MprCopyResource(&tempBufPtr, &RootResource, &bytesLeft);
|
|||
|
|
|||
|
if (status == WN_SUCCESS)
|
|||
|
{
|
|||
|
entriesRead = 1;
|
|||
|
ConnectEnumHeader->ReturnRoot = FALSE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (status == WN_MORE_DATA)
|
|||
|
{
|
|||
|
//
|
|||
|
// Not even enough room for one NETRESOURCE
|
|||
|
//
|
|||
|
*lpBufferSize = bytesLeft;
|
|||
|
}
|
|||
|
|
|||
|
goto CleanExit;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Loop until we have copied from all Providers or until the
|
|||
|
// the maximum number of entries has been reached.
|
|||
|
//
|
|||
|
for ( ; i < GlobalNumProviders && entriesRead < *NumEntries; i++)
|
|||
|
{
|
|||
|
LPPROVIDER provider = &GlobalProviderInfo[i];
|
|||
|
|
|||
|
if (ConnectEnumTable[i].State != MORE_ENTRIES)
|
|||
|
{
|
|||
|
//
|
|||
|
// Skip providers that don't have more entries
|
|||
|
//
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (provider->Handle == NULL) {
|
|||
|
//
|
|||
|
// If the provider has not been initialized because it is
|
|||
|
// not "ACTIVE", then skip it.
|
|||
|
//
|
|||
|
ConnectEnumTable[i].State = DONE;
|
|||
|
status = WN_SUCCESS;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Adjust the entry count for any entries that have been read
|
|||
|
// so far.
|
|||
|
//
|
|||
|
entryCount = *NumEntries - entriesRead;
|
|||
|
|
|||
|
//
|
|||
|
// Call the provider to get the enumerated data
|
|||
|
//
|
|||
|
status = provider->EnumResource(
|
|||
|
ConnectEnumTable[i].ProviderEnumHandle,
|
|||
|
&entryCount,
|
|||
|
providerBuffer,
|
|||
|
&bytesLeft ); // (note, the provider updates
|
|||
|
// bytesLeft only if it returns
|
|||
|
// WN_MORE_DATA)
|
|||
|
|
|||
|
switch (status)
|
|||
|
{
|
|||
|
case WN_SUCCESS:
|
|||
|
|
|||
|
MPR_LOG(TRACE,"EnumResourceHandle = 0x%lx\n",
|
|||
|
ConnectEnumTable[i].ProviderEnumHandle);
|
|||
|
|
|||
|
status = MprCopyProviderEnum(
|
|||
|
providerBuffer,
|
|||
|
&entryCount,
|
|||
|
&tempBufPtr,
|
|||
|
&bytesLeft);
|
|||
|
|
|||
|
entriesRead += entryCount;
|
|||
|
|
|||
|
if (status != WN_SUCCESS) {
|
|||
|
//
|
|||
|
// An internal error occured - for some reason the
|
|||
|
// buffer space left in the user buffer was smaller
|
|||
|
// than the buffer space that the provider filled in.
|
|||
|
// The best we can do in this case is return what data
|
|||
|
// we have. WARNING: the data that didn't make it
|
|||
|
// will become lost since the provider thinks it
|
|||
|
// enumerated successfully, but we couldn't do anything
|
|||
|
// with it.
|
|||
|
//
|
|||
|
MPR_LOG(ERROR,
|
|||
|
"MprEnumConnect:MprCopyProviderEnum Internal Error %d\n",
|
|||
|
status);
|
|||
|
|
|||
|
if(entriesRead > 0) {
|
|||
|
status = WN_SUCCESS;
|
|||
|
}
|
|||
|
goto CleanExit;
|
|||
|
}
|
|||
|
//
|
|||
|
// We successfully placed all the received data from
|
|||
|
// that provider into the user buffer. In this case,
|
|||
|
// if we haven't reached the requested number of entries,
|
|||
|
// we want to loop around and ask the same provider
|
|||
|
// to enumerate more. This time the provider should
|
|||
|
// indicate why it quit last time - either there are
|
|||
|
// no more entries, or we ran out of buffer space.
|
|||
|
//
|
|||
|
break;
|
|||
|
|
|||
|
case WN_NO_MORE_ENTRIES:
|
|||
|
//
|
|||
|
// This Provider has completed its enumeration, mark it
|
|||
|
// as done and increment to the next provider. We don't
|
|||
|
// want to return NO_MORE_ENTRIES status. That should
|
|||
|
// only be returned by the check at beginning or end
|
|||
|
// of this function.
|
|||
|
//
|
|||
|
ConnectEnumTable[i].State = DONE;
|
|||
|
status = WN_SUCCESS;
|
|||
|
break;
|
|||
|
|
|||
|
case WN_MORE_DATA:
|
|||
|
//
|
|||
|
// This provider has more data, but there is not enough
|
|||
|
// room left in the user buffer to place any more data
|
|||
|
// from this provider. We don't want to go on to the
|
|||
|
// next provider until we're finished with this one. So
|
|||
|
// if we have any entries at all to return, we send back
|
|||
|
// a SUCCESS status. Otherwise, the WN_MORE_DATA status
|
|||
|
// is appropriate.
|
|||
|
//
|
|||
|
if(entriesRead > 0) {
|
|||
|
status = WN_SUCCESS;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// If 0 entries were read, then the provider should
|
|||
|
// have set bytesLeft with the required buffer size
|
|||
|
//
|
|||
|
*lpBufferSize = ROUND_UP(bytesLeft);
|
|||
|
}
|
|||
|
goto CleanExit;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
//
|
|||
|
// We received an unexpected error from the Provider Enum
|
|||
|
// call.
|
|||
|
//
|
|||
|
MPR_LOG(ERROR,"MprEnumConnect:ProviderEnum Error %d\n",status);
|
|||
|
if(entriesRead > 0) {
|
|||
|
//
|
|||
|
// If we have received data so far, ignore this error
|
|||
|
// and move on to the next provider. This provider will
|
|||
|
// be left in the MORE_ENTRIES state, so that on some other
|
|||
|
// pass - when all other providers are done, this error
|
|||
|
// will be returned.
|
|||
|
//
|
|||
|
status = WN_SUCCESS;
|
|||
|
}
|
|||
|
else{
|
|||
|
//
|
|||
|
// No entries have been read so far. We can return
|
|||
|
// immediately with the error.
|
|||
|
//
|
|||
|
goto CleanExit;
|
|||
|
}
|
|||
|
|
|||
|
} // end switch (status)
|
|||
|
|
|||
|
} // end for (each provider)
|
|||
|
|
|||
|
//
|
|||
|
// If we looped through all providers and they are all DONE.
|
|||
|
// If there were no connections, then return proper error code.
|
|||
|
//
|
|||
|
if ((entriesRead == 0) && (status == WN_SUCCESS)) {
|
|||
|
status = WN_NO_MORE_ENTRIES;
|
|||
|
}
|
|||
|
|
|||
|
CleanExit:
|
|||
|
//
|
|||
|
// Update the number of entries to be returned to user.
|
|||
|
//
|
|||
|
*NumEntries = entriesRead;
|
|||
|
LocalFree(providerBuffer);
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
MprEnumNetwork(
|
|||
|
IN OUT LPDWORD StateTable,
|
|||
|
IN OUT LPDWORD NumEntries,
|
|||
|
IN OUT LPVOID lpBuffer,
|
|||
|
IN OUT LPDWORD lpBufferSize
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function Looks in the state table for the next provider that has
|
|||
|
MORE_ENTRIES. It begins by copying the NETRESOURCE info for that one.
|
|||
|
This continues until we finish, or we reach the requested number of
|
|||
|
elements, or the buffer is full. Each time we copy a complete structure,
|
|||
|
we mark that provider as DONE.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
StateTable - This is a pointer to the state table that is managed by
|
|||
|
the handle used in this request. The state table is a table of
|
|||
|
flags used to indicate the enumeration state for a given
|
|||
|
provider. These flags are in the same order as the provider
|
|||
|
information in the GlobalProviderInfo Array. The state can be
|
|||
|
either DONE or MORE_ENTRIES.
|
|||
|
|
|||
|
NumEntries - On entry this points to the maximum number of entries
|
|||
|
that the user desires to receive. On exit it points to the
|
|||
|
number of entries that were placed in the users buffer.
|
|||
|
|
|||
|
lpBuffer - This is a pointer to the users buffer in which the
|
|||
|
enumeration data is to be placed.
|
|||
|
|
|||
|
lpBufferSize - This is the size (in bytes) of the users buffer.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
WN_SUCCESS - This indicates that the call is returning some entries.
|
|||
|
However, the enumeration is not complete due to one of the following:
|
|||
|
1) There was not enough buffer space.
|
|||
|
2) The requested number of entries was reached.
|
|||
|
3) There is no more data to enumerate - the next call will
|
|||
|
return WN_NO_MORE_ENTRIES.
|
|||
|
|
|||
|
WN_MORE_DATA - This indicates that the buffer was not large enough
|
|||
|
to receive one enumeration entry.
|
|||
|
|
|||
|
WN_NO_MORE_ENTRIES - This indicates that there are no more entries
|
|||
|
to enumerate. No data is returned with this return code.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
CAUTION: "DONE" entries may appear anywhere in the statetable.
|
|||
|
You cannot always rely on the fact that all of the entries
|
|||
|
after a MORE_ENTRIES entry are also in the MORE_ENTRIES state.
|
|||
|
This is because a provider that would not pass back a handle
|
|||
|
at open time will be marked as DONE so that it gets skipped
|
|||
|
at Enum Time.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD i;
|
|||
|
DWORD status;
|
|||
|
DWORD entriesRead=0; // number of entries read into the buffer.
|
|||
|
LPBYTE tempBufPtr; // pointer to top of remaining free buffer space.
|
|||
|
DWORD bytesLeft; // num bytes left in free buffer space
|
|||
|
|
|||
|
//
|
|||
|
// If there are no providers, return NO_NETWORK
|
|||
|
//
|
|||
|
if (GlobalNumActiveProviders == 0) {
|
|||
|
return(WN_NO_NETWORK);
|
|||
|
}
|
|||
|
|
|||
|
bytesLeft = ROUND_DOWN(*lpBufferSize);
|
|||
|
tempBufPtr = (LPBYTE) lpBuffer;
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if there are any flags in state table that indicate
|
|||
|
// MORE_ENTRIES. If not, we want to return WN_NO_MORE_ENTRIES.
|
|||
|
//
|
|||
|
|
|||
|
for(i=0; i<GlobalNumProviders; i++) {
|
|||
|
if(StateTable[i] == MORE_ENTRIES) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( i >= GlobalNumProviders ) {
|
|||
|
*NumEntries = 0;
|
|||
|
return(WN_NO_MORE_ENTRIES);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Loop until we have copied from all Providers or until the
|
|||
|
// the maximum number of entries has been reached.
|
|||
|
//
|
|||
|
for(; (i<GlobalNumProviders) && (entriesRead < *NumEntries); i++) {
|
|||
|
|
|||
|
LPPROVIDER provider = &GlobalProviderInfo[i];
|
|||
|
|
|||
|
if(StateTable[i] == MORE_ENTRIES) {
|
|||
|
|
|||
|
if (provider->Handle == NULL) {
|
|||
|
//
|
|||
|
// If the provider is not ACTIVE, skip it.
|
|||
|
//
|
|||
|
StateTable[i] = DONE;
|
|||
|
}
|
|||
|
else {
|
|||
|
status = MprCopyResource(
|
|||
|
&tempBufPtr,
|
|||
|
(&provider->Resource),
|
|||
|
&bytesLeft);
|
|||
|
|
|||
|
if (status == WN_SUCCESS) {
|
|||
|
StateTable[i] = DONE;
|
|||
|
entriesRead++;
|
|||
|
}
|
|||
|
else {
|
|||
|
//
|
|||
|
// The buffer must be full - so exit.
|
|||
|
// If no entries are being returned, we will indicate
|
|||
|
// that the buffer was not large enough for even one entry.
|
|||
|
//
|
|||
|
*NumEntries = entriesRead;
|
|||
|
|
|||
|
if (entriesRead > 0) {
|
|||
|
return(WN_SUCCESS);
|
|||
|
}
|
|||
|
else {
|
|||
|
*lpBufferSize = ROUND_UP(bytesLeft);
|
|||
|
return(WN_MORE_DATA);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
} // EndIf (state == MORE_ENTRIES)
|
|||
|
} // EndFor (each provider)
|
|||
|
|
|||
|
//
|
|||
|
// Update the number of entries to be returned to user
|
|||
|
//
|
|||
|
*NumEntries = entriesRead;
|
|||
|
|
|||
|
return(WN_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
MprProviderEnum(
|
|||
|
IN LPENUM_HANDLE EnumHandlePtr,
|
|||
|
IN OUT LPDWORD lpcCount,
|
|||
|
IN LPVOID lpBuffer,
|
|||
|
IN OUT LPDWORD lpBufferSize
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function calls the provider (identified by the EnumHandlePtr)
|
|||
|
with a WNetEnumResource request. Aside from the EnumHandlePtr, all the
|
|||
|
rest of the parameters are simply passed thru to the provider.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
EnumHandlePtr - This is a pointer to an ENUM_HANDLE structure which
|
|||
|
contains a pointer to the provider structure and the handle for
|
|||
|
that provider's enumeration.
|
|||
|
|
|||
|
lpcCount - A pointer to a value that on entry contains the requested
|
|||
|
number of elements to enumerate. On exit this contains the
|
|||
|
actual number of elements enumerated.
|
|||
|
|
|||
|
lpBuffer - A pointer to the users buffer that the enumeration data
|
|||
|
is to be placed into.
|
|||
|
|
|||
|
lpBufferSize - The number of bytes of free space in the user's buffer.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
This function can return any return code that WNetEnumResource()
|
|||
|
can return.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD status;
|
|||
|
|
|||
|
//
|
|||
|
// Call the provider listed in the ENUM_HANDLE structure and ask it
|
|||
|
// to enumerate.
|
|||
|
//
|
|||
|
status = EnumHandlePtr->Provider->EnumResource(
|
|||
|
EnumHandlePtr->EnumHandle,
|
|||
|
lpcCount,
|
|||
|
lpBuffer,
|
|||
|
lpBufferSize);
|
|||
|
|
|||
|
if (status == WN_SUCCESS) {
|
|||
|
MPR_LOG(TRACE,"EnumResourceHandle = 0x%lx\n",
|
|||
|
EnumHandlePtr->EnumHandle);
|
|||
|
}
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
MprCopyResource(
|
|||
|
IN OUT LPBYTE *BufPtr,
|
|||
|
IN const NETRESOURCEW *Resource,
|
|||
|
IN OUT LPDWORD BytesLeft
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function copies a single NETRESOURCE structure into a buffer.
|
|||
|
The structure gets copied to the top of the buffer, and the strings
|
|||
|
that the structure references are copied to the bottom of the
|
|||
|
buffer. So any remaining free buffer space is left in the middle.
|
|||
|
|
|||
|
Upon successful return from this function, BufPtr will point to
|
|||
|
the top of this remaining free space, and BytesLeft will be updated
|
|||
|
to indicate how many bytes of free space are remaining.
|
|||
|
|
|||
|
If there is not enough room in the buffer to copy the Resource and its
|
|||
|
strings, an error is returned, and BufPtr is not changed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BufPtr - This is a pointer to a location that upon entry, contains a
|
|||
|
pointer to the buffer that the copied data is to be placed into.
|
|||
|
Upon exit, this pointer location points to the next free location
|
|||
|
in the buffer.
|
|||
|
|
|||
|
Resource - This points to the Resource Structure that is to be copied
|
|||
|
into the buffer.
|
|||
|
|
|||
|
BytesLeft - This points to a location to where a count of the remaining
|
|||
|
free bytes in the buffer is stored. This is updated on exit to
|
|||
|
indicate the adjusted number of free bytes left in the buffer.
|
|||
|
If the buffer is not large enough, and WN_MORE_DATA is returned, then
|
|||
|
the size of the buffer required to fit all the data is returned in
|
|||
|
this field.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
WN_SUCCESS - The operation was successful
|
|||
|
|
|||
|
WN_MORE_DATA - The buffer was not large enough to contain the
|
|||
|
Resource structure an its accompanying strings.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
|
|||
|
History:
|
|||
|
02-Apr-1992 JohnL
|
|||
|
Changed error return code to WN_MORE_DATA, added code to set the
|
|||
|
required buffer size if WN_MORE_DATA is returned.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LPTSTR startOfFreeBuf;
|
|||
|
LPTSTR endOfFreeBuf;
|
|||
|
LPNETRESOURCEW newResource;
|
|||
|
|
|||
|
//
|
|||
|
// The buffer must be at least large enough to hold a resource structure.
|
|||
|
//
|
|||
|
if (*BytesLeft < sizeof(NETRESOURCEW)) {
|
|||
|
*BytesLeft = MprMultiStrBuffSize( Resource->lpRemoteName,
|
|||
|
Resource->lpLocalName,
|
|||
|
Resource->lpComment,
|
|||
|
Resource->lpProvider,
|
|||
|
NULL ) + sizeof(NETRESOURCEW) ;
|
|||
|
return(WN_MORE_DATA);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Copy the Resource structure into the beginning of the buffer.
|
|||
|
//
|
|||
|
newResource = (LPNETRESOURCEW) *BufPtr;
|
|||
|
memcpy(newResource, Resource, sizeof(NETRESOURCEW));
|
|||
|
|
|||
|
startOfFreeBuf = (LPTSTR)((PCHAR)newResource + sizeof(NETRESOURCEW));
|
|||
|
endOfFreeBuf = (LPTSTR)((LPBYTE)newResource + *BytesLeft);
|
|||
|
|
|||
|
//
|
|||
|
// If a REMOTE_NAME string is to be copied, copy that and update the
|
|||
|
// pointer in the structure.
|
|||
|
//
|
|||
|
if (Resource->lpRemoteName != NULL) {
|
|||
|
//
|
|||
|
// If we must copy the remote name,
|
|||
|
//
|
|||
|
if (!NetpCopyStringToBuffer(
|
|||
|
Resource->lpRemoteName, // pointer to string
|
|||
|
STRLEN(Resource->lpRemoteName), // num chars in string
|
|||
|
startOfFreeBuf, // start of open space
|
|||
|
&endOfFreeBuf, // end of open space
|
|||
|
&newResource->lpRemoteName)) { // where string pointer goes
|
|||
|
|
|||
|
*BytesLeft = MprMultiStrBuffSize( Resource->lpRemoteName,
|
|||
|
Resource->lpLocalName,
|
|||
|
Resource->lpComment,
|
|||
|
Resource->lpProvider,
|
|||
|
NULL ) ;
|
|||
|
goto ErrorMoreData ;
|
|||
|
}
|
|||
|
}
|
|||
|
else{
|
|||
|
newResource->lpRemoteName = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If a LOCAL_NAME string is to be copied, copy that and update the
|
|||
|
// pointer in the structure.
|
|||
|
//
|
|||
|
if( ((Resource->dwScope == RESOURCE_CONNECTED) ||
|
|||
|
(Resource->dwScope == RESOURCE_REMEMBERED))
|
|||
|
&&
|
|||
|
(Resource->lpLocalName != NULL) ) {
|
|||
|
|
|||
|
//
|
|||
|
// If we must copy the local name,
|
|||
|
//
|
|||
|
if (!NetpCopyStringToBuffer(
|
|||
|
Resource->lpLocalName, // pointer to string
|
|||
|
STRLEN(Resource->lpLocalName), // num chars in string
|
|||
|
startOfFreeBuf, // start of open space
|
|||
|
&endOfFreeBuf, // end of open space
|
|||
|
&newResource->lpLocalName)) // where string pointer goes
|
|||
|
{
|
|||
|
goto ErrorMoreData ;
|
|||
|
}
|
|||
|
}
|
|||
|
else{
|
|||
|
newResource->lpLocalName = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If a COMMENT string is to be copied, copy that and update the
|
|||
|
// pointer in the structure.
|
|||
|
//
|
|||
|
if (Resource->lpComment != NULL) {
|
|||
|
//
|
|||
|
// If we must copy the comment string,
|
|||
|
//
|
|||
|
if (!NetpCopyStringToBuffer(
|
|||
|
Resource->lpComment, // pointer to string
|
|||
|
STRLEN(Resource->lpComment), // num chars in string
|
|||
|
startOfFreeBuf, // start of open space
|
|||
|
&endOfFreeBuf, // end of open space
|
|||
|
&newResource->lpComment)) // where string pointer goes
|
|||
|
{
|
|||
|
goto ErrorMoreData ;
|
|||
|
}
|
|||
|
}
|
|||
|
else{
|
|||
|
newResource->lpComment = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If a PROVIDRER string is to be copied, copy that and update the
|
|||
|
// pointer in the structure.
|
|||
|
//
|
|||
|
if (Resource->lpProvider != NULL) {
|
|||
|
//
|
|||
|
// If we must copy the provider name,
|
|||
|
//
|
|||
|
if (!NetpCopyStringToBuffer(
|
|||
|
Resource->lpProvider, // pointer to string
|
|||
|
STRLEN(Resource->lpProvider), // num chars in string
|
|||
|
startOfFreeBuf, // start of open space
|
|||
|
&endOfFreeBuf, // end of open space
|
|||
|
&newResource->lpProvider)) // where string pointer goes
|
|||
|
{
|
|||
|
goto ErrorMoreData ;
|
|||
|
}
|
|||
|
}
|
|||
|
else{
|
|||
|
newResource->lpProvider = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Update the returned information
|
|||
|
//
|
|||
|
*BufPtr = (LPBYTE)startOfFreeBuf;
|
|||
|
|
|||
|
*BytesLeft = (DWORD) ((LPBYTE) endOfFreeBuf - (LPBYTE) startOfFreeBuf);
|
|||
|
|
|||
|
return (WN_SUCCESS);
|
|||
|
|
|||
|
//
|
|||
|
// This is reached when we couldn't fill the buffer because the given
|
|||
|
// buffer size is too small. We therefore need to set the required
|
|||
|
// buffer size before returning.
|
|||
|
|
|||
|
ErrorMoreData:
|
|||
|
|
|||
|
*BytesLeft = MprMultiStrBuffSize( Resource->lpRemoteName,
|
|||
|
Resource->lpLocalName,
|
|||
|
Resource->lpComment,
|
|||
|
Resource->lpProvider,
|
|||
|
NULL ) + sizeof(NETRESOURCEW) ;
|
|||
|
|
|||
|
return (WN_MORE_DATA);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MprCopyProviderEnum(
|
|||
|
IN LPNETRESOURCEW ProviderBuffer,
|
|||
|
IN OUT LPDWORD EntryCount,
|
|||
|
IN OUT LPBYTE *TempBufPtr,
|
|||
|
IN OUT LPDWORD BytesLeft
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function moves the enumerated NETRESOURCE structures that are
|
|||
|
returned from a provider to a buffer that can be returned to the user.
|
|||
|
The buffer that is returned to the user may contain enum data from
|
|||
|
several providers. Because, we don't know how strings are packed in
|
|||
|
the buffer that is returned from the provider, we must simply walk
|
|||
|
through each structure and copy the information into the user buffer
|
|||
|
in a format that we do know about. Then the amount of free space
|
|||
|
left in the user buffer can be determined so that enum data from
|
|||
|
another provider can be added to it.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ProviderBuffer - This is a pointer to the top of an array of NETRESOURCE
|
|||
|
structures that is returned from one of the providers.
|
|||
|
|
|||
|
EntryCount - This points to the number of elements in the array that
|
|||
|
was returned from the provider. On exit, this points to the number
|
|||
|
of elements that was successfully copied. This should always be
|
|||
|
the same as the number of elements passed in.
|
|||
|
|
|||
|
TempBufPtr - This is a pointer to the top of the free space in the user
|
|||
|
buffer.
|
|||
|
|
|||
|
BytesLeft - Upon entry, this contains the number of free space bytes
|
|||
|
in the user buffer. Upon exit, this contains the updated number
|
|||
|
of free space bytes in the user buffer.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
WN_SUCCESS - The operation was successful
|
|||
|
|
|||
|
WN_OUT_OF_MEMORY - The buffer was not large enough to contain all of
|
|||
|
data the provider returned. This should never happen.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD i;
|
|||
|
DWORD status;
|
|||
|
DWORD entriesRead=0;
|
|||
|
|
|||
|
//
|
|||
|
// Loop for each element in the array of NetResource Structures.
|
|||
|
//
|
|||
|
for(i=0; i<*EntryCount; i++,ProviderBuffer++) {
|
|||
|
|
|||
|
status = MprCopyResource(
|
|||
|
TempBufPtr,
|
|||
|
ProviderBuffer,
|
|||
|
BytesLeft);
|
|||
|
|
|||
|
if (status != WN_SUCCESS) {
|
|||
|
MPR_LOG(ERROR,"MprCopyProviderEnum: Buffer Size Mismatch\n",0);
|
|||
|
//
|
|||
|
// The buffer must be full - this should never happen since
|
|||
|
// the amount of data placed in the ProviderBuffer is limited
|
|||
|
// by the number of bytes left in the user buffer.
|
|||
|
//
|
|||
|
ASSERT(0);
|
|||
|
*EntryCount = entriesRead;
|
|||
|
return(status);
|
|||
|
}
|
|||
|
entriesRead++;
|
|||
|
}
|
|||
|
*EntryCount = entriesRead;
|
|||
|
return(WN_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//===================================================================
|
|||
|
// CProviderOpenEnum - open an enumeration by a provider
|
|||
|
//===================================================================
|
|||
|
|
|||
|
DWORD
|
|||
|
CProviderOpenEnum::ValidateRoutedParameters(
|
|||
|
LPCWSTR * ppProviderName,
|
|||
|
LPCWSTR * ppRemoteName
|
|||
|
)
|
|||
|
{
|
|||
|
//
|
|||
|
// Let the base class validate any specified provider name.
|
|||
|
// Note: This must be done before setting _lpNetResource to NULL!
|
|||
|
//
|
|||
|
*ppProviderName = _lpNetResource->lpProvider;
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if a top level enumeration for the provider is requested.
|
|||
|
// (This is different from a top level MPR enumeration.)
|
|||
|
// A top level enum is signified by a net resource with either a special
|
|||
|
// bit set in the dwUsage field, or a provider name but no remote name.
|
|||
|
//
|
|||
|
if ((_lpNetResource->dwUsage & RESOURCEUSAGE_RESERVED) ||
|
|||
|
IS_EMPTY_STRING(_lpNetResource->lpRemoteName))
|
|||
|
{
|
|||
|
//
|
|||
|
// Top level enum. Don't pass the net resource to the provider.
|
|||
|
//
|
|||
|
ASSERT(! IS_EMPTY_STRING(_lpNetResource->lpProvider));
|
|||
|
_lpNetResource = NULL;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// Use the remote name as a hint to pick the provider order.
|
|||
|
//
|
|||
|
*ppRemoteName = _lpNetResource->lpRemoteName;
|
|||
|
}
|
|||
|
|
|||
|
return WN_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
CProviderOpenEnum::TestProvider(
|
|||
|
const PROVIDER * pProvider
|
|||
|
)
|
|||
|
{
|
|||
|
if ((pProvider->GetCaps(WNNC_ENUMERATION) & WNNC_ENUM_GLOBAL) == 0)
|
|||
|
{
|
|||
|
return WN_NOT_SUPPORTED;
|
|||
|
}
|
|||
|
|
|||
|
return ( pProvider->OpenEnum(
|
|||
|
_dwScope,
|
|||
|
_dwType,
|
|||
|
_dwUsage,
|
|||
|
_lpNetResource,
|
|||
|
&_ProviderEnumHandle) );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
CProviderOpenEnum::GetResult()
|
|||
|
{
|
|||
|
//
|
|||
|
// Let the base class try the providers until one responds
|
|||
|
//
|
|||
|
DWORD status = CRoutedOperation::GetResult();
|
|||
|
if (status != WN_SUCCESS)
|
|||
|
{
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
MPR_LOG(TRACE,"CProviderOpenEnum: OpenEnum Handle = 0x%lx\n",
|
|||
|
_ProviderEnumHandle);
|
|||
|
|
|||
|
//
|
|||
|
// Allocate memory to store the handle.
|
|||
|
//
|
|||
|
LPENUM_HANDLE enumHandleStruct =
|
|||
|
(ENUM_HANDLE *) LocalAlloc(LPTR, sizeof(ENUM_HANDLE));
|
|||
|
|
|||
|
if (enumHandleStruct == NULL)
|
|||
|
{
|
|||
|
//
|
|||
|
// If we can't allocate memory to store the handle
|
|||
|
// away, then we must close it, and change the status
|
|||
|
// to indicate a memory failure.
|
|||
|
//
|
|||
|
MPR_LOG(ERROR,"CProviderOpenEnum: LocalAlloc failed %d\n",
|
|||
|
GetLastError());
|
|||
|
|
|||
|
LastProvider()->CloseEnum(_ProviderEnumHandle);
|
|||
|
|
|||
|
status = WN_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// Store the handle in the ENUM_HANDLE structure and
|
|||
|
// return the pointer to that structure as a handle
|
|||
|
// for the user.
|
|||
|
//
|
|||
|
enumHandleStruct->Key = PROVIDER_ENUM_KEY;
|
|||
|
enumHandleStruct->Provider = LastProvider();
|
|||
|
enumHandleStruct->EnumHandle = _ProviderEnumHandle;
|
|||
|
*_lphEnum = enumHandleStruct;
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MprOpenRemember(
|
|||
|
IN DWORD dwType,
|
|||
|
OUT LPHANDLE lphRemember
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LPREMEMBER_HANDLE rememberInfo;
|
|||
|
|
|||
|
rememberInfo = (REMEMBER_HANDLE *) LocalAlloc(LPTR, sizeof(REMEMBER_HANDLE));
|
|||
|
|
|||
|
if (rememberInfo == NULL) {
|
|||
|
MPR_LOG(ERROR,"MprOpenRemember:LocalAlloc Failed %d\n",GetLastError());
|
|||
|
return(WN_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
rememberInfo->Key = REMEMBER_KEY;
|
|||
|
rememberInfo->KeyIndex = 0;
|
|||
|
rememberInfo->ConnectionType = dwType;
|
|||
|
|
|||
|
//
|
|||
|
// Open the key to the connection information in the current user
|
|||
|
// section of the registry.
|
|||
|
//
|
|||
|
// NOTE: If this fails, we must assume that there is no connection
|
|||
|
// information stored. This is not an error condition.
|
|||
|
// In this case, we store a NULL for the handle so that we know
|
|||
|
// the situation. Each time EnumResource is called, we can try
|
|||
|
// to open the key again.
|
|||
|
//
|
|||
|
|
|||
|
if (!MprOpenKey(
|
|||
|
HKEY_CURRENT_USER,
|
|||
|
CONNECTION_KEY_NAME,
|
|||
|
&(rememberInfo->ConnectKey),
|
|||
|
DA_READ)) {
|
|||
|
|
|||
|
MPR_LOG(ERROR,"MprOpenRemember: MprOpenKey Failed\n",0);
|
|||
|
rememberInfo->ConnectKey = NULL;
|
|||
|
}
|
|||
|
|
|||
|
*lphRemember = (HANDLE)rememberInfo;
|
|||
|
|
|||
|
return(WN_SUCCESS);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
MprEnumRemembered(
|
|||
|
IN OUT LPREMEMBER_HANDLE RememberInfo,
|
|||
|
IN OUT LPDWORD NumEntries,
|
|||
|
IN OUT LPBYTE lpBuffer,
|
|||
|
IN OUT LPDWORD lpBufferSize
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RememberInfo - This is a pointer to REMEMBER_HANDLE data structure
|
|||
|
that contains the context information for this enumeration handle.
|
|||
|
|
|||
|
NumEntries - On entry this points to the maximum number of entries
|
|||
|
that the user desires to receive. On exit it points to the
|
|||
|
number of entries that were placed in the users buffer.
|
|||
|
|
|||
|
lpBuffer - This is a pointer to the users buffer in which the
|
|||
|
enumeration data is to be placed.
|
|||
|
|
|||
|
lpBufferSize - This is the size (in bytes) of the users buffer.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
WN_SUCCESS - The call was successful, and some entries were returned.
|
|||
|
However, there are still more entries to be enumerated.
|
|||
|
|
|||
|
WN_NO_MORE_ENTRIES - This function has no data to return because
|
|||
|
there was no further connection information in the registry.
|
|||
|
|
|||
|
WN_CONNOT_OPEN_PROFILE - This function could open a key to the
|
|||
|
connection information, but could not get any information about
|
|||
|
that key.
|
|||
|
|
|||
|
WN_MORE_DATA - The caller's buffer was too small for even one entry.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
History:
|
|||
|
Changed to return "status" instead of WN_SUCCESS
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD status = WN_SUCCESS ;
|
|||
|
LPTSTR userName;
|
|||
|
NETRESOURCEW netResource;
|
|||
|
LPBYTE tempBufPtr;
|
|||
|
DWORD bytesLeft;
|
|||
|
DWORD entriesRead = 0;
|
|||
|
DWORD numSubKeys;
|
|||
|
DWORD maxSubKeyLen;
|
|||
|
DWORD maxValueLen;
|
|||
|
|
|||
|
if ((RememberInfo->ConnectKey == NULL) && (RememberInfo->KeyIndex == 0)) {
|
|||
|
|
|||
|
//
|
|||
|
// If we failed to open the key at Open-time, attempt to open it
|
|||
|
// now. This registry key is closed when the CloseEnum function is
|
|||
|
// called.
|
|||
|
//
|
|||
|
|
|||
|
if (!MprOpenKey(
|
|||
|
HKEY_CURRENT_USER,
|
|||
|
CONNECTION_KEY_NAME,
|
|||
|
&(RememberInfo->ConnectKey),
|
|||
|
DA_READ)) {
|
|||
|
|
|||
|
//
|
|||
|
// We couldn't open the key. So we must assume that it doesn't
|
|||
|
// exist because there if no connection information stored.
|
|||
|
//
|
|||
|
|
|||
|
MPR_LOG(ERROR,"MprEnumRemembered: MprOpenKey Failed\n",0);
|
|||
|
RememberInfo->ConnectKey = NULL;
|
|||
|
return(WN_NO_MORE_ENTRIES);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find out the size of the largest key name.
|
|||
|
//
|
|||
|
|
|||
|
if(!MprGetKeyInfo(
|
|||
|
RememberInfo->ConnectKey,
|
|||
|
NULL,
|
|||
|
&numSubKeys,
|
|||
|
&maxSubKeyLen,
|
|||
|
NULL,
|
|||
|
&maxValueLen)) {
|
|||
|
|
|||
|
MPR_LOG(ERROR,"MprEnumRemembered: MprGetKeyInfo Failed\n",0);
|
|||
|
return(WN_CANNOT_OPEN_PROFILE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we've already enumerated all the subkeys, there are no more entries.
|
|||
|
//
|
|||
|
if (RememberInfo->KeyIndex >= numSubKeys) {
|
|||
|
return(WN_NO_MORE_ENTRIES);
|
|||
|
}
|
|||
|
tempBufPtr = lpBuffer;
|
|||
|
bytesLeft = ROUND_DOWN(*lpBufferSize);
|
|||
|
tempBufPtr = lpBuffer;
|
|||
|
|
|||
|
netResource.lpComment = NULL;
|
|||
|
netResource.dwScope = RESOURCE_REMEMBERED;
|
|||
|
netResource.dwUsage = 0;
|
|||
|
|
|||
|
while(
|
|||
|
(RememberInfo->KeyIndex < numSubKeys) &&
|
|||
|
(entriesRead < *NumEntries) &&
|
|||
|
(bytesLeft > sizeof(NETRESOURCE))
|
|||
|
)
|
|||
|
{
|
|||
|
//
|
|||
|
// Get the connection info from the key and stuff it into
|
|||
|
// a NETRESOURCE structure.
|
|||
|
//
|
|||
|
BOOL fMatch = FALSE;
|
|||
|
DWORD ProviderFlags; // ignored
|
|||
|
DWORD DeferFlags; // ignored
|
|||
|
|
|||
|
if(!MprReadConnectionInfo(
|
|||
|
RememberInfo->ConnectKey,
|
|||
|
NULL,
|
|||
|
RememberInfo->KeyIndex,
|
|||
|
&ProviderFlags,
|
|||
|
&DeferFlags,
|
|||
|
&userName,
|
|||
|
&netResource,
|
|||
|
maxSubKeyLen)) {
|
|||
|
|
|||
|
//
|
|||
|
// NOTE: The ReadConnectionInfo call could return FALSE
|
|||
|
// if it failed in a memory allocation.
|
|||
|
//
|
|||
|
if (entriesRead == 0) {
|
|||
|
status = WN_NO_MORE_ENTRIES;
|
|||
|
}
|
|||
|
else {
|
|||
|
status = WN_SUCCESS;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if ((netResource.dwType == RememberInfo->ConnectionType) ||
|
|||
|
(RememberInfo->ConnectionType == RESOURCETYPE_ANY)) {
|
|||
|
|
|||
|
fMatch = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Copy the new netResource information into the user's
|
|||
|
// buffer. Each time this function is called, the tempBufPtr
|
|||
|
// gets updated to point to the next free space in the user's
|
|||
|
// buffer.
|
|||
|
//
|
|||
|
if ( fMatch )
|
|||
|
{
|
|||
|
status = MprCopyResource(
|
|||
|
&tempBufPtr,
|
|||
|
&netResource,
|
|||
|
&bytesLeft);
|
|||
|
|
|||
|
if (status != WN_SUCCESS) {
|
|||
|
|
|||
|
if (entriesRead == 0) {
|
|||
|
*lpBufferSize = ROUND_UP(bytesLeft);
|
|||
|
status = WN_MORE_DATA;
|
|||
|
}
|
|||
|
else {
|
|||
|
status = WN_SUCCESS;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
entriesRead++;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the allocated memory resources.
|
|||
|
//
|
|||
|
LocalFree(netResource.lpLocalName);
|
|||
|
LocalFree(netResource.lpRemoteName);
|
|||
|
LocalFree(netResource.lpProvider);
|
|||
|
if (userName != NULL) {
|
|||
|
LocalFree(userName);
|
|||
|
}
|
|||
|
|
|||
|
(RememberInfo->KeyIndex)++;
|
|||
|
}
|
|||
|
|
|||
|
*NumEntries = entriesRead;
|
|||
|
|
|||
|
return(status);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MprMultiStrBuffSize(
|
|||
|
IN LPTSTR lpString1,
|
|||
|
IN LPTSTR lpString2,
|
|||
|
IN LPTSTR lpString3,
|
|||
|
IN LPTSTR lpString4,
|
|||
|
IN LPTSTR lpString5
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is a worker function that simply determines the total
|
|||
|
storage requirements needed by the passed set of strings. Any of the
|
|||
|
strings maybe NULL in which case the string will be ignored.
|
|||
|
|
|||
|
The NULL terminator is added into the total memory requirements.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
lpString1 -> 5 - Pointers to valid strings or NULL.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The count of bytes required to store the passed strings.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD cbRequired = 0 ;
|
|||
|
|
|||
|
if ( lpString1 != NULL )
|
|||
|
{
|
|||
|
cbRequired += (STRLEN( lpString1 ) + 1) * sizeof(TCHAR) ;
|
|||
|
}
|
|||
|
|
|||
|
if ( lpString2 != NULL )
|
|||
|
{
|
|||
|
cbRequired += (STRLEN( lpString2 ) + 1) * sizeof(TCHAR) ;
|
|||
|
}
|
|||
|
|
|||
|
if ( lpString3 != NULL )
|
|||
|
{
|
|||
|
cbRequired += (STRLEN( lpString3 ) + 1) * sizeof(TCHAR) ;
|
|||
|
}
|
|||
|
|
|||
|
if ( lpString4 != NULL )
|
|||
|
{
|
|||
|
cbRequired += (STRLEN( lpString4 ) + 1) * sizeof(TCHAR) ;
|
|||
|
}
|
|||
|
|
|||
|
if ( lpString5 != NULL )
|
|||
|
{
|
|||
|
cbRequired += (STRLEN( lpString5 ) + 1) * sizeof(TCHAR) ;
|
|||
|
}
|
|||
|
|
|||
|
return cbRequired ;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
MprNetIsAvailable(
|
|||
|
VOID)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function checks if the net is available by calling the GetCaps
|
|||
|
of each provider to make sure it is started.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE is yes, FALSE otherwise
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD status = WN_SUCCESS;
|
|||
|
LPDWORD index;
|
|||
|
DWORD indexArray[DEFAULT_MAX_PROVIDERS];
|
|||
|
DWORD numProviders, i;
|
|||
|
LPPROVIDER provider;
|
|||
|
DWORD dwResult ;
|
|||
|
|
|||
|
//
|
|||
|
// Find the list of providers to call for this request.
|
|||
|
// If there are no active providers, MprFindCallOrder returns
|
|||
|
// WN_NO_NETWORK.
|
|||
|
//
|
|||
|
index = indexArray;
|
|||
|
status = MprFindCallOrder(
|
|||
|
NULL,
|
|||
|
&index,
|
|||
|
&numProviders,
|
|||
|
NETWORK_TYPE);
|
|||
|
if (status != WN_SUCCESS)
|
|||
|
return(FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Loop through the list of providers, making sure at least one
|
|||
|
// is started
|
|||
|
//
|
|||
|
for (i=0; i<numProviders; i++)
|
|||
|
{
|
|||
|
//
|
|||
|
// Call the appropriate providers API entry point
|
|||
|
//
|
|||
|
provider = GlobalProviderInfo + index[i];
|
|||
|
|
|||
|
if (provider->GetCaps != NULL)
|
|||
|
{
|
|||
|
dwResult = provider->GetCaps( WNNC_START );
|
|||
|
if (dwResult != 0)
|
|||
|
{
|
|||
|
if (index != indexArray)
|
|||
|
LocalFree(index);
|
|||
|
return (TRUE) ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If memory was allocated by MprFindCallOrder, free it.
|
|||
|
//
|
|||
|
if (index != indexArray)
|
|||
|
LocalFree(index);
|
|||
|
|
|||
|
return(FALSE);
|
|||
|
}
|