windows-nt/Source/XPSP1/NT/printscan/ui/printui/dsinterf.cxx
2020-09-26 16:20:57 +08:00

819 lines
15 KiB
C++

/*++
Copyright (C) Microsoft Corporation, 1996 - 1998
All rights reserved.
Module Name:
dsinterf.hxx
Abstract:
Directory service interface
Author:
Steve Kiraly (SteveKi) 09-Sept-1996
Revision History:
--*/
#include "precomp.hxx"
#pragma hdrstop
#include "dsinterf.hxx"
/*++
Name:
TDirectoryService constructor.
Description:
TDirectoryService is a helper class for encapsulating DS
related functions.
Arguments:
None.
Return Value:
Nothing, use bValid for class state check.
--*/
TDirectoryService::
TDirectoryService(
VOID
) : _bValid( FALSE )
{
DBGMSG( DBG_TRACE, ( "TDirectoryService::ctor\n" ) );
//
// We must initialize OLE for in each thread. In this
// case we assume the user of this class only creates
// one per thread.
//
HRESULT hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
if( hr == S_OK || hr == S_FALSE )
{
_bValid = TRUE;
}
}
/*++
Name:
~TDirectoryService destructor
Description:
Destructs this class, all clean up code should be placed here.
Arguments:
None.
Return Value:
Nothing.
--*/
TDirectoryService::
~TDirectoryService(
VOID
)
{
DBGMSG( DBG_TRACE, ( "TDirectoryService::dtor.\n" ) );
//
// Coinitlize was only called if we had
// a valid object.
//
if( _bValid )
{
//
// Balance the CoInitialize.
//
CoUninitialize();
}
}
/*++
Name:
bValid
Description:
Indicates if the class is valid.
Arguments:
None.
Return Value:
TRUE class is valid, FALSE class is in an invalid state.
--*/
BOOL
TDirectoryService::
bValid(
VOID
)
{
DBGMSG( DBG_TRACE, ( "TDirectoryService::bValid.\n" ) );
//
// This class is always valid.
//
return TRUE;
}
/*++
Name:
bGetDirectoryName
Description:
Retrives the directory display name from the shell, i.e. ds folder.
Arguments:
strName - refrence to string object where to return
directory display name.
Return Value:
TRUE name returne, FALSE error occurred.
--*/
BOOL
TDirectoryService::
bGetDirectoryName(
IN TString &strName
)
{
TStatusB bStatus;
if( _strDirectoryName.bEmpty() )
{
TLibrary Lib( TEXT("dsuiext.dll") );
if( VALID_OBJ( Lib ) )
{
typedef HRESULT (WINAPI *PF_FORMATDIRECTORYNAME)( LPTSTR *, PVOID, UINT );
typedef VOID (WINAPI *PF_LOCALFREESTRING)( LPTSTR * );
PF_FORMATDIRECTORYNAME pfFormatDirectoryName = (PF_FORMATDIRECTORYNAME)Lib.pfnGetProc( 578 );
PF_LOCALFREESTRING pfLocalFreeString = (PF_LOCALFREESTRING)Lib.pfnGetProc( 542 );
if( pfFormatDirectoryName && pfLocalFreeString )
{
HRESULT hr;
LPTSTR pName = NULL;
hr = pfFormatDirectoryName( &pName, NULL, 0 );
if ( SUCCEEDED(hr) )
{
bStatus DBGCHK = _strDirectoryName.bUpdate( pName );
pfLocalFreeString(&pName);
}
}
}
}
//
// If the directory name is empty indicate we cannot
// get the directory name.
//
if( _strDirectoryName.bEmpty() )
{
bStatus DBGNOCHK = FALSE;
}
else
{
//
// Return the directory name.
//
bStatus DBGCHK = strName.bUpdate( _strDirectoryName );
}
return bStatus;
}
/*++
Name:
bIsDsAvailable
Description:
Indicates if the directory service is available either for the
user or from the machines perspective.
Arguments:
pName - pointer to a machine name, i.e. this call is remoteable.
bForUser - TRUE indicate it is a user check, FALSE for machine.
Return Value:
TRUE if directory is available, otherwize false.
--*/
BOOL
TDirectoryService::
bIsDsAvailable(
IN LPCTSTR pName,
IN BOOL bForUser
)
{
BOOL bReturn = FALSE;
DWORD dwStatus = ERROR_SUCCESS;
DWORD dwAccess = SERVER_READ;
DWORD dwDsStatus = 0;
HANDLE hServer = NULL;
//
// Open the server for read access.
//
dwStatus = TPrinter::sOpenPrinter( pName, &dwAccess, &hServer );
//
// If server handle opened.
//
if( dwStatus == ERROR_SUCCESS )
{
DWORD dwNeeded = 0;
DWORD dwDsStatusType = REG_DWORD;
if( dwStatus == ERROR_SUCCESS )
{
//
// If the request for user or for machine.
//
LPTSTR pszKey = bForUser ? SPLREG_DS_PRESENT_FOR_USER : SPLREG_DS_PRESENT;
//
// Get the printer data key which indicates the DS is available.
//
dwStatus = GetPrinterData( hServer,
pszKey,
&dwDsStatusType,
(PBYTE)&dwDsStatus,
sizeof( dwDsStatus ),
&dwNeeded );
}
if( dwStatus == ERROR_SUCCESS )
{
bReturn = dwDsStatus;
}
}
//
// Close the server handle.
//
if( hServer )
{
ClosePrinter( hServer );
}
return bReturn;
}
/*++
Name:
bIsDsAvailable
Description:
Indicates if the directory service is available either for the
using the same check the shell uses.
Arguments:
None.
Return Value:
TRUE if directory is available, otherwize false.
--*/
BOOL
TDirectoryService::
bIsDsAvailable(
VOID
)
{
DBGMSG( DBG_TRACE, ( "TDirectoryService::bIsDsAvailble - ShowDirectoryUI.\n" ) );
BOOL bStatus = FALSE;
TLibrary Lib( TEXT("dsuiext.dll") );
if( VALID_OBJ( Lib ) )
{
typedef BOOL (WINAPI *PF_SHOWDIRECTORYUI)( VOID );
PF_SHOWDIRECTORYUI pfShowDirectoryUI = (PF_SHOWDIRECTORYUI)Lib.pfnGetProc( 577 );
if( pfShowDirectoryUI )
{
bStatus = pfShowDirectoryUI();
}
}
return bStatus;
}
HRESULT
TDirectoryService::
ADsGetObject(
IN LPWSTR lpszPathName,
IN REFIID riid,
IN OUT VOID **ppObject
)
{
return ::ADsGetObject( lpszPathName, riid, ppObject );
}
HRESULT
TDirectoryService::
ADsBuildEnumerator(
IADsContainer *pADsContainer,
IEnumVARIANT **ppEnumVariant
)
{
return ::ADsBuildEnumerator( pADsContainer, ppEnumVariant);
}
HRESULT
TDirectoryService::
ADsFreeEnumerator(
IEnumVARIANT *pEnumVariant
)
{
return ::ADsFreeEnumerator( pEnumVariant );
}
HRESULT
TDirectoryService::
ADsEnumerateNext(
IEnumVARIANT *pEnumVariant,
ULONG cElements,
VARIANT FAR *pvar,
ULONG FAR *pcElementsFetched
)
{
return ::ADsEnumerateNext( pEnumVariant, cElements, pvar, pcElementsFetched);
}
/*++
Name:
Get
Description:
This routine gets a string value from the specified DS object using
the specified property. A copy of the string is made and placed into
the provided string object.
Arguments:
pDsObject - pointer to the DS object interface
pszPropertyName - DS object property name
strString - refrence to string object where to return string
Return Value:
TRUE string put successfully, FALSE error occurred.
--*/
BOOL
TDirectoryService::
Get(
IN IADs *pDsObject,
IN LPCTSTR pszPropertyName,
IN TString &strString
)
{
SPLASSERT( pDsObject );
SPLASSERT( pszPropertyName );
VARIANT var;
VariantInit( &var );
HRESULT hr = pDsObject->Get( const_cast<LPTSTR>( pszPropertyName ), &var );
if( SUCCEEDED( hr ) && ( var.vt == VT_BSTR ) )
{
hr = strString.bUpdate( V_BSTR(&var) ) ? S_OK : E_FAIL;
}
VariantClear (&var);
return SUCCEEDED( hr );
}
/*++
Name:
Put
Description:
This routine puts a string value on the specified DS object
for the specified property. This routine does not make a copy
of the string but places it into a variant that is inturn passed
to Ads::Put method.
Arguments:
pDsObject - pointer to the DS object interface
pszPropertyName - DS object property name
pszString - string value to put
Return Value:
TRUE string put successfully, FALSE error occurred.
--*/
BOOL
TDirectoryService::
Put(
IN IADs *pDsObject,
IN LPCTSTR pszPropertyName,
IN LPCTSTR pszString
)
{
SPLASSERT( pDsObject );
SPLASSERT( pszPropertyName );
VARIANT var;
HRESULT hr;
VariantInit (&var);
if( !pszString || !*pszString )
{
hr = pDsObject->PutEx( ADS_PROPERTY_CLEAR, const_cast<LPTSTR>( pszPropertyName ), var );
}
else
{
var.vt = VT_BSTR;
var.bstrVal = const_cast<LPTSTR>( pszString );
hr = pDsObject->Put( const_cast<LPTSTR>( pszPropertyName ), var );
}
if( SUCCEEDED( hr ) )
{
hr = pDsObject->SetInfo();
if( FAILED(hr) && ( !pszString || !*pszString ) )
{
//
// From our perspective if we fail to delete a property because it does not exist
// the operation actually succeeded.
//
if( HRESULT_CODE(hr) == ERROR_DS_NO_ATTRIBUTE_OR_VALUE )
{
hr = S_OK;
}
}
}
var.bstrVal = NULL;
VariantClear (&var);
return SUCCEEDED(hr);
}
/*++
Name:
TReadStringProperty
Description:
This routine reads the specified string using the specified path
and property name from the DS.
Arguments:
strString - refrence to class where to returned read string.
Return Value:
TRUE string was read, FALSE error occurred.
Notes:
--*/
BOOL
TDirectoryService::
ReadStringProperty(
IN LPCTSTR pszPath,
IN LPCTSTR pszProperty,
IN OUT TString &strString
)
{
IADs *pADs;
HRESULT hStatus;
hStatus = ADsGetObject( const_cast<LPTSTR>( pszPath ), IID_IADs, (void **)&pADs);
if (SUCCEEDED(hStatus))
{
VARIANT var;
VariantInit(&var);
hStatus = pADs->Get( const_cast<LPTSTR>( pszProperty ), &var);
if (SUCCEEDED(hStatus))
{
hStatus = strString.bUpdate( V_BSTR(&var) ) ? S_OK : E_FAIL;
}
VariantClear (&var);
pADs->Release();
}
if (FAILED(hStatus))
{
DBGMSG( DBG_TRACE, ("ReadStringProperty Path " TSTR " Property " TSTR " failed %x\n", pszPath, pszProperty, hStatus ) );
}
return SUCCEEDED(hStatus);
}
/*++
Name:
GetConfigurationContainer
Description:
This routine figures out the and returnes the path of the
longged on DS's configuration containter.
Arguments:
strConfig - Refrence to a string where to return the configuration string.
Return Value:
TRUE configuration containter returned. FALSE error occurred.
Notes:
--*/
BOOL
TDirectoryService::
GetConfigurationContainer(
IN OUT TString &strConfig
)
{
TStatusB bStatus;
//
// If we have not already read the configuration container
// then read it now.
//
if (_strConfigurationContainer.bEmpty())
{
TString strRootDSE;
TString strLDAPPrefix;
bStatus DBGCHK = GetLDAPPrefix( strLDAPPrefix ) &&
strRootDSE.bCat( strLDAPPrefix ) &&
strRootDSE.bCat( gszRootDSE );
if (bStatus)
{
bStatus DBGCHK = ReadStringProperty( strRootDSE, gszConfigurationNameingContext, _strConfigurationContainer );
}
}
bStatus DBGCHK = strConfig.bUpdate( _strConfigurationContainer );
DBGMSG( DBG_TRACE, ( "Configuration Container " TSTR ".\n", (LPCTSTR)strConfig ) );
return bStatus;
}
/*++
Name:
GetDsName
Description:
Returns a the DS UNC name that can be used in the call to
AddressToSiteNames.
Arguments:
strDsName - refrence to string where to return the Ds name.
Return Value:
TRUE success, FALSE error occurred.
Notes:
--*/
BOOL
TDirectoryService::
GetDsName(
IN TString &strDsName
)
{
TString strDomainName;
TStatusB bStatus;
bStatus DBGCHK = GetDomainName( strDomainName );
if (bStatus)
{
bStatus DBGCHK = strDsName.bUpdate( gszLeadingSlashes ) && strDsName.bCat( strDomainName );
}
return bStatus;
}
/*++
Name:
GetLDAPPrefix
Description:
Returns the correct LDAP prefix using fully qualified machine account
domain name (example "LDAP://ntdev.microsoft.com/"
Arguments:
strLDAPPrefix - where to return The LDAP prefix (domain relative or
fully qualified)
Return Value:
TRUE on success, FALSE othewise
Notes:
--*/
BOOL
TDirectoryService::
GetLDAPPrefix(
OUT TString &strLDAPPrefix
)
{
TStatusB bStatus;
bStatus DBGNOCHK = TRUE;
if( !_strLDAPPrefix.uLen( ) )
{
TString strRootDSE;
TString strConfig;
bStatus DBGCHK = strRootDSE.bCat( gszLdapPrefix ) &&
strRootDSE.bCat( gszRootDSE );
if( bStatus )
{
//
// We need to use fully qualified domain LDAP address
//
TString strDomainName;
bStatus DBGCHK = GetDomainName( strDomainName );
if( bStatus )
{
bStatus DBGCHK = _strLDAPPrefix.bUpdate( NULL ) &&
_strLDAPPrefix.bCat( gszLdapPrefix ) &&
_strLDAPPrefix.bCat( strDomainName ) &&
_strLDAPPrefix.bCat( gszSlash );
}
}
}
if( !_strLDAPPrefix.uLen( ) || !bStatus )
{
bStatus DBGCHK = _strLDAPPrefix.bUpdate( gszLdapPrefix );
}
if( bStatus )
{
bStatus DBGCHK = strLDAPPrefix.bUpdate( _strLDAPPrefix );
}
return bStatus;
}
/*++
Name:
GetLDAPPrefixPerUser
Description:
Returns the correct LDAP prefix using fully qualified machine account
domain name (example "LDAP://ntdev.microsoft.com/" if the user domain
(the domain in which the user is logged on) doesn't have a DS, if the
user domain has a DS then we are using domain relative prefix (i.e.
"LDAP://").
Arguments:
strLDAPPrefix - where to return The LDAP prefix (domain relative or
fully qualified)
Return Value:
TRUE on success, FALSE othewise
Notes:
--*/
BOOL
TDirectoryService::
GetLDAPPrefixPerUser(
OUT TString &strLDAPPrefix
)
{
TStatusB bStatus;
bStatus DBGNOCHK = TRUE;
if( !_strLDAPPrefixPerUser.uLen( ) )
{
TString strRootDSE;
TString strConfig;
bStatus DBGCHK = strRootDSE.bCat( gszLdapPrefix ) &&
strRootDSE.bCat( gszRootDSE );
if( bStatus )
{
bStatus DBGCHK = ReadStringProperty( strRootDSE, gszConfigurationNameingContext, strConfig );
if( bStatus )
{
//
// We can use domain relative LDAP address
//
bStatus DBGCHK = _strLDAPPrefixPerUser.bUpdate( gszLdapPrefix );
}
else
{
//
// We need to use fully qualified domain LDAP address
//
bStatus DBGCHK = GetLDAPPrefix (_strLDAPPrefixPerUser);
}
}
}
if( !_strLDAPPrefixPerUser.uLen( ) || !bStatus )
{
bStatus DBGCHK = _strLDAPPrefixPerUser.bUpdate( gszLdapPrefix );
}
if( bStatus )
{
bStatus DBGCHK = strLDAPPrefix.bUpdate( _strLDAPPrefixPerUser );
}
return bStatus;
}