841 lines
26 KiB
C++
841 lines
26 KiB
C++
/**********************************************************************/
|
|
/** Microsoft Windows/NT **/
|
|
/** Copyright(c) Microsoft Corp., 1991 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
WNETENUM.CXX
|
|
This file contains the implementation of
|
|
NPOpenEnum - open a resource enumeration handle
|
|
NPEnumResource - walk through all the resource
|
|
NPCloseEnum - end of walk through
|
|
|
|
FILE HISTORY:
|
|
terryk 27-Sep-91 Created
|
|
terryk 01-Nov-91 WIN32 conversion
|
|
terryk 08-Nov-91 Code review changes
|
|
terryk 18-Nov-91 Split to 2 files - wnetenum.cxx and
|
|
enumnode.cxx
|
|
terryk 10-Dec-91 check parameters in WNetOpenEnum
|
|
terryk 28-Dec-91 changed DWORD to UINT
|
|
Yi-HsinS31-Dec-91 Unicode work
|
|
terryk 03-Jan-92 Capitalize the Resource_XXX manifest
|
|
terryk 10-Jan-92 Returned WN_SUCCESS if the buffer is too
|
|
small for 1 entry.
|
|
*/
|
|
|
|
#define INCL_WINDOWS
|
|
#define INCL_DOSERRORS
|
|
#define INCL_NETERRORS
|
|
#define INCL_NETCONS
|
|
#define INCL_NETUSE
|
|
#define INCL_NETWKSTA
|
|
#define INCL_NETACCESS // NetPasswordSet declaration
|
|
#define INCL_NETCONFIG
|
|
#define INCL_NETREMUTIL
|
|
#define INCL_NETSHARE
|
|
#define INCL_NETSERVER
|
|
#define INCL_NETSERVICE
|
|
#define INCL_NETLIB
|
|
#define INCL_ICANON
|
|
#define _WINNETWK_
|
|
#include <lmui.hxx>
|
|
#undef _WINNETWK_
|
|
|
|
#define INCL_BLT_WINDOW
|
|
#include <blt.hxx>
|
|
#include <dbgstr.hxx>
|
|
|
|
#include <winnetwk.h>
|
|
#include <winnetp.h>
|
|
#include <npapi.h>
|
|
#include <wnetenum.h>
|
|
#include <winlocal.h>
|
|
#include <mnet.h>
|
|
|
|
#include <lmobj.hxx>
|
|
#include <lmoshare.hxx>
|
|
#include <lmoesh.hxx>
|
|
#include <lmoeuse.hxx>
|
|
#include <lmodev.hxx>
|
|
#include <lmosrv.hxx>
|
|
#include <lmowks.hxx>
|
|
#include <lmoesrv.hxx>
|
|
#include <lmsvc.hxx>
|
|
#include <uibuffer.hxx>
|
|
#include <uitrace.hxx>
|
|
#include <uiassert.hxx>
|
|
#include <uatom.hxx>
|
|
#include <regkey.hxx>
|
|
#include <array.hxx>
|
|
#include <string.hxx>
|
|
#include <strchlit.hxx> // for SERVER_INIT_STRING
|
|
#include <miscapis.hxx>
|
|
#include <wnetenum.hxx>
|
|
|
|
//
|
|
// Macros for rounding a value up/down to a TCHAR boundary.
|
|
// Note: These macros assume that sizeof(TCHAR) is a power of 2.
|
|
//
|
|
|
|
#define ROUND_DOWN(x) ((x) & ~(sizeof(TCHAR) - 1))
|
|
#define ROUND_UP(x) (((x) + sizeof(TCHAR) - 1) & ~(sizeof(TCHAR) - 1))
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
Global variables
|
|
|
|
********************************************************************/
|
|
|
|
#define ARRAY_SIZE 64
|
|
|
|
extern NET_ENUM_HANDLE_TABLE *vpNetEnumArray;
|
|
|
|
/* Winnet locking handle
|
|
*/
|
|
HANDLE vhSemaphore ;
|
|
|
|
/* Name of the provider
|
|
*/
|
|
const TCHAR * pszNTLanMan = NULL ;
|
|
|
|
#define LM_WKSTA_NODE SZ("System\\CurrentControlSet\\Services\\LanmanWorkstation\\NetworkProvider")
|
|
#define LM_PROVIDER_VALUE_NAME SZ("Name")
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: InitWNetEnum
|
|
|
|
SYNOPSIS: Initialize the Enum handle array
|
|
|
|
RETURN: APIERR - it will return ERROR_OUT_OF_MEMORY if it does
|
|
not have enough space
|
|
|
|
HISTORY:
|
|
terryk 24-Oct-91 Created
|
|
davidhov 20-Oct-92 updated REG_KEY usage
|
|
|
|
********************************************************************/
|
|
|
|
APIERR InitWNetEnum()
|
|
{
|
|
TRACEEOL( "NTLANMAN.DLL: InitWNetEnum()" );
|
|
vpNetEnumArray = new NET_ENUM_HANDLE_TABLE( ARRAY_SIZE );
|
|
if ( vpNetEnumArray == NULL )
|
|
{
|
|
DBGEOL( "NTLANMAN.DLL: InitWNetEnum() ERROR_NOT_ENOUGH_MEMORY" );
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
APIERR err = vpNetEnumArray->QueryError();
|
|
|
|
if ( !err )
|
|
{
|
|
if ( (vhSemaphore = ::CreateSemaphore( NULL, 1, 1, NULL )) == NULL)
|
|
{
|
|
err = ::GetLastError() ;
|
|
DBGEOL( "NTLANMAN.DLL: InitWNetEnum() semaphore error " << err );
|
|
}
|
|
}
|
|
return err ;
|
|
}
|
|
|
|
/********************************************************************
|
|
NAME: GetLMProviderName
|
|
|
|
SYNOPSIS: Get Provider Name into the global variable pszNTLanMan
|
|
|
|
RETURN: APIERR - it will return ERROR_OUT_OF_MEMORY if it does
|
|
not have enough space
|
|
|
|
HISTORY:
|
|
congpay 14-Dec-92 Created
|
|
********************************************************************/
|
|
APIERR GetLMProviderName()
|
|
{
|
|
if (pszNTLanMan)
|
|
{
|
|
return NERR_Success;
|
|
}
|
|
|
|
APIERR err = NERR_Success;
|
|
REG_KEY *pRegKeyFocusServer = NULL;
|
|
|
|
do { // error breakout
|
|
/* Traverse the registry and get the list of computer alert
|
|
* names.
|
|
*/
|
|
pRegKeyFocusServer = REG_KEY::QueryLocalMachine();
|
|
|
|
if ( ( pRegKeyFocusServer == NULL ) ||
|
|
((err = pRegKeyFocusServer->QueryError())) )
|
|
{
|
|
err = err? err : ERROR_NOT_ENOUGH_MEMORY ;
|
|
break ;
|
|
}
|
|
|
|
ALIAS_STR nlsRegKeyName( LM_WKSTA_NODE ) ;
|
|
REG_KEY regkeyLMProviderNode( *pRegKeyFocusServer, nlsRegKeyName );
|
|
REG_KEY_INFO_STRUCT regKeyInfo;
|
|
REG_VALUE_INFO_STRUCT regValueInfo ;
|
|
|
|
if ( (err = regkeyLMProviderNode.QueryError()) ||
|
|
(err = regkeyLMProviderNode.QueryInfo( ®KeyInfo )) )
|
|
{
|
|
break ;
|
|
}
|
|
|
|
BUFFER buf( (UINT) regKeyInfo.ulMaxValueLen ) ;
|
|
regValueInfo.nlsValueName = LM_PROVIDER_VALUE_NAME ;
|
|
if ( (err = buf.QueryError() ) ||
|
|
(err = regValueInfo.nlsValueName.QueryError()) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
regValueInfo.pwcData = buf.QueryPtr();
|
|
regValueInfo.ulDataLength = buf.QuerySize() ;
|
|
|
|
if ( (err = regkeyLMProviderNode.QueryValue( ®ValueInfo )))
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* Null terminate the computer list string we just retrieved from
|
|
* the registry.
|
|
*/
|
|
TCHAR * pszProviderName = (TCHAR *)( buf.QueryPtr() +
|
|
regValueInfo.ulDataLengthOut -
|
|
sizeof(TCHAR) );
|
|
*pszProviderName = TCH('\0') ;
|
|
ALIAS_STR nlsComputerList( (TCHAR *) buf.QueryPtr()) ;
|
|
|
|
pszNTLanMan = new TCHAR[ nlsComputerList.QueryTextSize() ] ;
|
|
if ( pszNTLanMan == NULL )
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
break ;
|
|
}
|
|
|
|
nlsComputerList.CopyTo( (TCHAR *) pszNTLanMan,
|
|
nlsComputerList.QueryTextSize()) ;
|
|
} while (FALSE) ;
|
|
|
|
delete pRegKeyFocusServer ;
|
|
|
|
return err;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: TermWNetEnum
|
|
|
|
SYNOPSIS: clear up the Enum handle array
|
|
|
|
HISTORY:
|
|
terryk 24-Oct-91 Created
|
|
|
|
********************************************************************/
|
|
|
|
VOID TermWNetEnum()
|
|
{
|
|
TRACEEOL( "NTLANMAN.DLL: TermWNetEnum()" );
|
|
delete vpNetEnumArray;
|
|
vpNetEnumArray = NULL;
|
|
REQUIRE( ::CloseHandle( vhSemaphore ) ) ;
|
|
vhSemaphore = NULL ;
|
|
delete (void *) pszNTLanMan ;
|
|
pszNTLanMan = NULL ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: NPOpenEnum
|
|
|
|
SYNOPSIS: Create a new Enum handle
|
|
|
|
ENTRY: UINT dwScope - determine the scope of the enumeration.
|
|
This can be one of:
|
|
RESOURCE_CONNECTED - all currently connected resource
|
|
RESOURCE_GLOBALNET - all resources on the network
|
|
RESOURCE_CONTEXT - resources in the user's current
|
|
and default network context
|
|
UINT dwType - used to specify the type of resources of
|
|
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.
|
|
UINT dwUsage - Used to specify the usage of resources
|
|
of interested. 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.
|
|
RESOURCEUSAGE_ATTACHED - signifies that the function
|
|
should fail if the caller is not authenticated (even
|
|
if the network allows enumeration without authenti-
|
|
cation).
|
|
This parameter is ignored if dwScope is not
|
|
RESOURCE_GLOBALNET.
|
|
NETRESOURCE * lpNetResource - This specifies the
|
|
container to perform the enumeration. The
|
|
NETRESOURCE must have been obtained via
|
|
NPEnumResource( and must have the
|
|
RESOURCEUSAGE_Connectable bit set ), or NULL. If it
|
|
is NULL,the logical root of the network is assumed.
|
|
An application would normally start off by calling
|
|
NPOpenEnum with this parameter set to NULL, and
|
|
then use the returned results for further
|
|
enumeration. If dwScope is RESOURCE_CONNECTED, this
|
|
must be NULL.
|
|
If dwScope is RESOURCE_CONTEXT, this is ignored.
|
|
HANDLE * lphEnum - If function call is successful, this
|
|
will contain a handle that can then be used for
|
|
NPEnumResource.
|
|
|
|
EXIT: HANDLE * lphEnum - will contain the handle number
|
|
|
|
RETURNS: WN_SUCCESS if the call is successful. Otherwise,
|
|
GetLastError should be called for extended error
|
|
information. Extened error codes include:
|
|
WN_NOT_CONTAINER - lpNetResource does not point to a
|
|
container
|
|
WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType,
|
|
or bad combination of parameters is specified
|
|
WN_NOT_NETWORK - network is not present
|
|
WN_NET_ERROR - a network specific error occured.
|
|
WNetGetLastError should be called to obtain further
|
|
information.
|
|
|
|
HISTORY:
|
|
terryk 24-Oct-91 Created
|
|
Johnl 06-Mar-1992 Added Computer validation check
|
|
on container enumeration
|
|
JohnL 03-Apr-1992 Fixed dwUsage == CONNECTED|CONTAINER
|
|
bug (would return WN_BAD_VALUE)
|
|
ChuckC 01-Aug-1992 Simplified, corrected and commented
|
|
the messy cases wrt to dwUsage.
|
|
AnirudhS 03-Mar-1995 Added support for RESOURCE_CONTEXT
|
|
AnirudhS 26-Apr-1996 Simplified, corrected and commented
|
|
the messy cases wrt dwScope.
|
|
|
|
********************************************************************/
|
|
|
|
DWORD APIENTRY
|
|
NPOpenEnum(
|
|
UINT dwScope,
|
|
UINT dwType,
|
|
UINT dwUsage,
|
|
LPNETRESOURCE lpNetResource,
|
|
HANDLE * lphEnum )
|
|
{
|
|
UIASSERT( lphEnum != NULL );
|
|
|
|
APIERR err ;
|
|
if ( err = CheckLMService() )
|
|
return err ;
|
|
|
|
if ( dwType & ~( RESOURCETYPE_DISK | RESOURCETYPE_PRINT ) )
|
|
{
|
|
return WN_BAD_VALUE;
|
|
}
|
|
|
|
NET_ENUMNODE *pNetEnum;
|
|
|
|
if ( dwScope == RESOURCE_CONNECTED )
|
|
{
|
|
/*
|
|
* we are looking for current uses
|
|
*/
|
|
if ( lpNetResource != NULL )
|
|
{
|
|
return WN_BAD_VALUE;
|
|
}
|
|
|
|
err = GetLMProviderName();
|
|
if (err)
|
|
return(err);
|
|
|
|
pNetEnum = new USE_ENUMNODE( dwScope, dwType, dwUsage, lpNetResource );
|
|
}
|
|
else if ( dwScope == RESOURCE_CONTEXT )
|
|
{
|
|
/*
|
|
* we are looking for servers in the domain
|
|
* Note that lpNetResource is ignored
|
|
* dwType is decoded in the CONTEXT_ENUMNODE constructor
|
|
*/
|
|
pNetEnum = new CONTEXT_ENUMNODE( dwScope, dwType, dwUsage, NULL );
|
|
}
|
|
else if ( dwScope == RESOURCE_SHAREABLE )
|
|
{
|
|
/*
|
|
* We are looking for shareable resources
|
|
* Use SHARE_ENUMNODE, which decodes dwScope when it enumerates
|
|
* If we're not given a server, return an EMPTY_ENUMNODE
|
|
*/
|
|
if (lpNetResource != NULL
|
|
&&
|
|
lpNetResource->lpRemoteName != NULL
|
|
&&
|
|
lpNetResource->lpRemoteName[0] == TCH('\\')
|
|
&&
|
|
lpNetResource->lpRemoteName[1] == TCH('\\'))
|
|
{
|
|
pNetEnum = new SHARE_ENUMNODE( dwScope, dwType, dwUsage, lpNetResource );
|
|
}
|
|
else
|
|
{
|
|
pNetEnum = new EMPTY_ENUMNODE( dwScope, dwType, dwUsage, lpNetResource );
|
|
}
|
|
}
|
|
else if ( dwScope == RESOURCE_GLOBALNET )
|
|
{
|
|
/* Look for the combination of all bits and substitute "All" for
|
|
* them. Ignore bits we don't know about.
|
|
* Note: RESOURCEUSAGE_ATTACHED is a no-op for us, since LanMan
|
|
* always tries to authenticate when doing an enumeration.
|
|
*/
|
|
dwUsage &= (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER);
|
|
|
|
if ( dwUsage == (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER) )
|
|
{
|
|
dwUsage = 0 ;
|
|
}
|
|
|
|
/*
|
|
* we are looking for global resources out on the net
|
|
*/
|
|
if ( lpNetResource == NULL || lpNetResource->lpRemoteName == NULL)
|
|
{
|
|
/*
|
|
* at top level, therefore enumerating domains. if user
|
|
* asked for connectable, well, there aint none.
|
|
*/
|
|
if ( dwUsage == RESOURCEUSAGE_CONNECTABLE )
|
|
{
|
|
pNetEnum = new EMPTY_ENUMNODE( dwScope,
|
|
dwType,
|
|
dwUsage,
|
|
lpNetResource );
|
|
}
|
|
else
|
|
{
|
|
pNetEnum = new DOMAIN_ENUMNODE( dwScope,
|
|
dwType,
|
|
dwUsage,
|
|
lpNetResource );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* we are assured of lpRemoteName != NULL.
|
|
* things get interesting here. the cases are as follows:
|
|
*
|
|
* if (dwUsage == 0)
|
|
* if have \\ in front
|
|
* return shares
|
|
* else
|
|
* return servers
|
|
* else if (dwUsage == CONNECTABLE)
|
|
* if have \\ in front
|
|
* return shares
|
|
* else
|
|
* empty enum
|
|
* else if (dwUsage == CONTAINER)
|
|
* if have \\ in front
|
|
* empty enum
|
|
* else
|
|
* return server
|
|
*
|
|
* In interest of code size, i've reorganized the above
|
|
* cases to minimized the bodies of the ifs.
|
|
*
|
|
* chuckc.
|
|
*/
|
|
|
|
if ( ((dwUsage == RESOURCEUSAGE_CONNECTABLE) ||
|
|
(dwUsage == 0)
|
|
)
|
|
&&
|
|
((lpNetResource->lpRemoteName[0] == TCH('\\')) &&
|
|
(lpNetResource->lpRemoteName[1] == TCH('\\'))
|
|
)
|
|
)
|
|
{
|
|
/* Confirm that this really is a computer name (i.e., a
|
|
* container we can enumerate).
|
|
*/
|
|
if ( ::I_MNetNameValidate( NULL,
|
|
&(lpNetResource->lpRemoteName[2]),
|
|
NAMETYPE_COMPUTER,
|
|
0L))
|
|
{
|
|
return WN_BAD_VALUE ;
|
|
}
|
|
|
|
pNetEnum = new SHARE_ENUMNODE( dwScope, dwType, dwUsage,
|
|
lpNetResource );
|
|
}
|
|
else if ( ((dwUsage == RESOURCEUSAGE_CONTAINER) ||
|
|
(dwUsage == 0)
|
|
)
|
|
&&
|
|
(lpNetResource->lpRemoteName[0] != TCH('\\'))
|
|
)
|
|
{
|
|
pNetEnum = new SERVER_ENUMNODE( dwScope, dwType, dwUsage,
|
|
lpNetResource );
|
|
}
|
|
else if (
|
|
// ask for share but aint starting from server
|
|
(
|
|
(dwUsage == RESOURCEUSAGE_CONNECTABLE)
|
|
&&
|
|
(lpNetResource->lpRemoteName[0] != TCH('\\'))
|
|
)
|
|
||
|
|
// ask for server but is starting from server
|
|
(
|
|
(dwUsage == RESOURCEUSAGE_CONTAINER)
|
|
&&
|
|
((lpNetResource->lpRemoteName[0] == TCH('\\')) &&
|
|
(lpNetResource->lpRemoteName[1] == TCH('\\'))
|
|
)
|
|
)
|
|
)
|
|
{
|
|
pNetEnum = new EMPTY_ENUMNODE( dwScope,
|
|
dwType,
|
|
dwUsage,
|
|
lpNetResource );
|
|
}
|
|
else
|
|
{
|
|
// incorrect dwUsage
|
|
return WN_BAD_VALUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// invalid dwScope
|
|
return WN_BAD_VALUE;
|
|
}
|
|
|
|
if ( pNetEnum == NULL )
|
|
{
|
|
return WN_OUT_OF_MEMORY;
|
|
}
|
|
else if ( err = pNetEnum->QueryError() )
|
|
{
|
|
delete pNetEnum;
|
|
return MapError(err);
|
|
}
|
|
|
|
if ( pNetEnum->IsFirstGetInfo() )
|
|
{
|
|
if (( err = pNetEnum->GetInfo()) != WN_SUCCESS )
|
|
{
|
|
delete pNetEnum;
|
|
return MapError(err);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////// Enter critical section
|
|
|
|
if ( err = WNetEnterCriticalSection() )
|
|
{
|
|
delete pNetEnum;
|
|
return err ;
|
|
}
|
|
|
|
ASSERT( vpNetEnumArray != NULL );
|
|
INT iPos = vpNetEnumArray->QueryNextAvail();
|
|
if ( iPos < 0 )
|
|
{
|
|
WNetLeaveCriticalSection() ;
|
|
delete pNetEnum;
|
|
return WN_OUT_OF_MEMORY;
|
|
}
|
|
|
|
vpNetEnumArray->SetNode( (UINT)iPos, pNetEnum );
|
|
*lphEnum = UintToPtr((UINT)iPos);
|
|
|
|
WNetLeaveCriticalSection() ;
|
|
|
|
////////////////////////////////////////// Leave critical section
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: NPEnumResource
|
|
|
|
SYNOPSIS: Perform an enumeration based on handle returned by
|
|
NPOpenEnum.
|
|
|
|
ENTRY: HANDLE hEnum - This must be a handle obtained from
|
|
NPOpenEnum call
|
|
UINT *lpcRequested - Specifies the number of entries
|
|
requested. It may be 0xFFFFFFFF to request as many as
|
|
possible. On successful call, this location will receive
|
|
the number of entries actually read.
|
|
VOID *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.
|
|
UINT * lpBufferSize - This specifies the size of the
|
|
buffer passed to the function call. If WN_MORE_DATA
|
|
is returned and no entries were enumerated, then this
|
|
will be set to the minimum buffer size required.
|
|
|
|
EXIT: UINT *lpcRequested - will receive the number of entries
|
|
actually read.
|
|
|
|
RETURNS: WN_SUCCESS if the call is successful, the caller should
|
|
continue to call NPEnumResource to continue the
|
|
enumeration.
|
|
WN_NO_MORE_ENTRIES - no more entries found, the
|
|
enumeration completed successfully ( the contents of the
|
|
return buffer is undefined). Otherwise, GetLastError
|
|
should be called for extended error information.
|
|
Extended error codes include:
|
|
WN_MORE_DATA - the buffer is too small even for one
|
|
entry
|
|
WN_BAD_HANDLE - hEnum is not a valid handle
|
|
WN_NOT_NETWORK - network is not present. This
|
|
condition is checked for before hEnum is tested for
|
|
validity.
|
|
WN_NET_ERROR - a network specific error occured.
|
|
WNetGetLastError should be called to obtain further
|
|
information.
|
|
|
|
HISTORY:
|
|
terryk 24-Oct-91 Created
|
|
KeithMo 15-Sep-92 Align *lpcBufferSize as needed.
|
|
|
|
********************************************************************/
|
|
|
|
DWORD APIENTRY
|
|
NPEnumResource(
|
|
HANDLE hEnum,
|
|
UINT * lpcRequested,
|
|
LPVOID lpBuffer,
|
|
UINT * lpcBufferSize )
|
|
{
|
|
APIERR err ;
|
|
|
|
if (( lpBuffer == NULL ) ||
|
|
( lpcRequested == NULL ) ||
|
|
( lpcBufferSize == NULL ))
|
|
{
|
|
return WN_BAD_VALUE;
|
|
}
|
|
|
|
if ( err = WNetEnterCriticalSection() )
|
|
{
|
|
return err ;
|
|
}
|
|
|
|
ASSERT( vpNetEnumArray != NULL );
|
|
NET_ENUMNODE *pNode = vpNetEnumArray->QueryNode(PtrToUint(hEnum));
|
|
WNetLeaveCriticalSection() ;
|
|
|
|
if ( pNode == NULL )
|
|
{
|
|
return WN_BAD_HANDLE;
|
|
}
|
|
else if ( pNode->IsFirstGetInfo() )
|
|
{
|
|
if ( err = CheckLMService() )
|
|
{
|
|
return err ;
|
|
}
|
|
if (( err = pNode->GetInfo()) != WN_SUCCESS )
|
|
{
|
|
return ( MapError(err) );
|
|
}
|
|
}
|
|
|
|
LPNETRESOURCE pNetResource = ( LPNETRESOURCE ) lpBuffer;
|
|
UINT cbRemainSize = ROUND_DOWN(*lpcBufferSize);
|
|
|
|
UINT cRequested = (*lpcRequested);
|
|
*lpcRequested = 0;
|
|
while ( *lpcRequested < cRequested )
|
|
{
|
|
err = pNode->GetNetResource((BYTE *)pNetResource, &cbRemainSize );
|
|
|
|
if ( err == WN_MORE_DATA )
|
|
{
|
|
/* If we can't even fit one into the buffer, then set the required
|
|
* buffer size and return WN_MORE_DATA.
|
|
*/
|
|
if ( *lpcRequested == 0 )
|
|
{
|
|
*lpcBufferSize = ROUND_UP(cbRemainSize);
|
|
}
|
|
else
|
|
{
|
|
err = NERR_Success ;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if ( err == WN_NO_MORE_ENTRIES )
|
|
{
|
|
if ( *lpcRequested != 0 )
|
|
{
|
|
err = NERR_Success ;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if ( err != WN_SUCCESS )
|
|
{
|
|
break ;
|
|
}
|
|
|
|
/* err == WN_SUCCESS
|
|
*/
|
|
|
|
(*lpcRequested) ++;
|
|
|
|
if ( sizeof( NETRESOURCE ) > cbRemainSize )
|
|
{
|
|
break ;
|
|
}
|
|
|
|
pNetResource ++;
|
|
cbRemainSize -= (UINT)sizeof( NETRESOURCE );
|
|
}
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: NPCloseEnum
|
|
|
|
SYNOPSIS: Closes an enumeration.
|
|
|
|
ENTRY: HANDLE hEnum - this must be a handle obtained from
|
|
NPOpenEnum call.
|
|
|
|
RETURNS: WN_SUCCESS if the call is successful. Otherwise,
|
|
GetLastError should be called for extended error information.
|
|
Extended error codes include:
|
|
WN_NO_NETWORK - network is not present. this condition is
|
|
checked for before hEnum is tested for validity.
|
|
WN_BAD_HANDLE - hEnum is not a valid handle.
|
|
WN_NET_ERROR - a network specific error occured.
|
|
WNetGetLastError should be called to obtain further
|
|
information.
|
|
|
|
HISTORY:
|
|
terryk 24-Oct-91 Created
|
|
|
|
********************************************************************/
|
|
|
|
DWORD APIENTRY
|
|
NPCloseEnum(
|
|
HANDLE hEnum )
|
|
{
|
|
APIERR err ;
|
|
if ( err = WNetEnterCriticalSection() )
|
|
{
|
|
return err ;
|
|
}
|
|
|
|
ASSERT( vpNetEnumArray != NULL );
|
|
NET_ENUMNODE *pNode = vpNetEnumArray->QueryNode(PtrToUint(hEnum));
|
|
if ( pNode == NULL )
|
|
{
|
|
// cannot find the node
|
|
|
|
err = WN_BAD_HANDLE;
|
|
}
|
|
else
|
|
{
|
|
vpNetEnumArray->ClearNode(PtrToUint(hEnum));
|
|
}
|
|
|
|
WNetLeaveCriticalSection() ;
|
|
return err ;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: WNetEnterCriticalSection
|
|
|
|
SYNOPSIS: Locks the LM network provider enumeration code
|
|
|
|
EXIT: vhSemaphore will be locked
|
|
|
|
RETURNS: NERR_Success if successful, error code otherwise
|
|
|
|
NOTES: We wait for 7 seconds for the semaphonre to be freed
|
|
|
|
HISTORY:
|
|
Johnl 27-Apr-1992 Created
|
|
|
|
********************************************************************/
|
|
|
|
APIERR WNetEnterCriticalSection( void )
|
|
{
|
|
APIERR err = NERR_Success ;
|
|
switch( WaitForSingleObject( vhSemaphore, 7000L ))
|
|
{
|
|
case 0:
|
|
break ;
|
|
|
|
case WAIT_TIMEOUT:
|
|
err = WN_FUNCTION_BUSY ;
|
|
break ;
|
|
|
|
case 0xFFFFFFFF:
|
|
err = ::GetLastError() ;
|
|
break ;
|
|
|
|
default:
|
|
UIASSERT(FALSE) ;
|
|
err = WN_WINDOWS_ERROR ;
|
|
break ;
|
|
}
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: WNetLeaveCriticalSection
|
|
|
|
SYNOPSIS: Unlocks the enumeration methods
|
|
|
|
RETURNS:
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
Johnl 27-Apr-1992 Created
|
|
|
|
********************************************************************/
|
|
|
|
void WNetLeaveCriticalSection( void )
|
|
{
|
|
REQUIRE( ReleaseSemaphore( vhSemaphore, 1, NULL ) ) ;
|
|
}
|