784 lines
20 KiB
C++
784 lines
20 KiB
C++
|
// Interfaces.cpp : Implementation of TSUserExInterfaces class.
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
#if 1 //POST_BETA_3
|
||
|
#include <sspi.h>
|
||
|
#include <secext.h>
|
||
|
#include <dsgetdc.h>
|
||
|
#endif //POST_BETA_3
|
||
|
|
||
|
#include "tsuserex.h"
|
||
|
//#include "ConfigDlg.h" // for CTSUserProperties
|
||
|
#include "tsusrsht.h"
|
||
|
|
||
|
#include "Interfaces.h"
|
||
|
//#include "logmsg.h"
|
||
|
#include "limits.h" // USHRT_MAX
|
||
|
#ifdef _RTM_
|
||
|
#include <ntverp.h> // VER_PRODUCTVERSION_DW
|
||
|
#endif
|
||
|
#include <winsta.h>
|
||
|
//#include "ntdsapi.h" // enbable for "having some fun macro"
|
||
|
|
||
|
// clipboard format to retreive the machine name and account name associated
|
||
|
// with a data object created by local user manager
|
||
|
|
||
|
#define CCF_LOCAL_USER_MANAGER_MACHINE_NAME TEXT("Local User Manager Machine Focus Name")
|
||
|
|
||
|
|
||
|
#define ByteOffset(base, offset) (((LPBYTE)base)+offset)
|
||
|
|
||
|
|
||
|
BOOL g_bPagesHaveBeenInvoked = FALSE;
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// IExtendPropertySheet implementation
|
||
|
|
||
|
|
||
|
HRESULT GetMachineAndUserName(IDataObject *pDataObject, LPWSTR pMachineName, LPWSTR pUserName , PBOOL pbDSAType , PSID *ppUserSid )
|
||
|
{
|
||
|
ASSERT_(pUserName);
|
||
|
ASSERT_(pMachineName);
|
||
|
ASSERT_(pDataObject != NULL );
|
||
|
|
||
|
// register the display formats.
|
||
|
// first 2 formats supported by local user manager snapin
|
||
|
static UINT s_cfMachineName = RegisterClipboardFormat(CCF_LOCAL_USER_MANAGER_MACHINE_NAME);
|
||
|
static UINT s_cfDisplayName = RegisterClipboardFormat(CCF_DISPLAY_NAME);;
|
||
|
static UINT s_cfDsObjectNames = RegisterClipboardFormat(CFSTR_DSOBJECTNAMES); // this format is supported by dsadmin snapin.
|
||
|
|
||
|
ASSERT_(s_cfMachineName);
|
||
|
ASSERT_(s_cfDisplayName);
|
||
|
ASSERT_(s_cfDsObjectNames);
|
||
|
|
||
|
|
||
|
FORMATETC fmte = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
||
|
|
||
|
STGMEDIUM medium = { TYMED_HGLOBAL, NULL, NULL };
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
ASSERT_(USHRT_MAX > s_cfDsObjectNames);
|
||
|
|
||
|
// first we will try dsdataobject format. This means we are running in context of dsadmin
|
||
|
|
||
|
fmte.cfFormat = ( USHORT )s_cfDsObjectNames;
|
||
|
|
||
|
hr = pDataObject->GetData(&fmte, &medium);
|
||
|
|
||
|
if( SUCCEEDED( hr ) )
|
||
|
{
|
||
|
// CFSTR_DSOBJECTNAMES is supported.
|
||
|
// It means we are dealing with dsadmin
|
||
|
// lets get username, and domain name from the dsadmin.
|
||
|
|
||
|
LPDSOBJECTNAMES pDsObjectNames = (LPDSOBJECTNAMES)medium.hGlobal;
|
||
|
|
||
|
*pbDSAType = TRUE;
|
||
|
|
||
|
if( pDsObjectNames->cItems < 1 )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : @GetMachineAndUserName DS Object names < 1\n" );
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
LPWSTR pwszObjName = ( LPWSTR )ByteOffset( pDsObjectNames , pDsObjectNames->aObjects[0].offsetName );
|
||
|
|
||
|
KdPrint( ( "TSUSEREX : adspath is %ws\n" , pwszObjName ) );
|
||
|
|
||
|
// first stage get the server name from the adspath
|
||
|
// since IADsPathname does not live off a normal IADs Directory object
|
||
|
// so me must cocreate the object set the path and then retrieve the server name
|
||
|
// hey this saves us wire-tripping
|
||
|
|
||
|
// IADsPathname *pPathname = NULL;
|
||
|
|
||
|
IADsObjectOptions *pADsOptions = NULL;
|
||
|
|
||
|
IADs *pADs = NULL;
|
||
|
|
||
|
hr = ADsGetObject( pwszObjName, IID_IADs, (void**)&pADs );
|
||
|
|
||
|
if( FAILED( hr ) )
|
||
|
{
|
||
|
KdPrint( ( "TSUSEREX : no means of binding to adspath -- hresult = 0x%x\n" , hr ) );
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
VARIANT varServerName;
|
||
|
|
||
|
VariantInit(&varServerName);
|
||
|
|
||
|
hr = pADs->QueryInterface( IID_IADsObjectOptions , ( void ** )&pADsOptions );
|
||
|
|
||
|
KdPrint( ( "TSUSEREX : binded to adsobject queried for IID_IADsObjectOptions returned 0x%x\n" , hr ) );
|
||
|
|
||
|
if( SUCCEEDED( hr ) )
|
||
|
{
|
||
|
hr = pADsOptions->GetOption( ADS_OPTION_SERVERNAME, &varServerName);
|
||
|
|
||
|
pADsOptions->Release( );
|
||
|
|
||
|
KdPrint( ( "TSUSEREX: GetOption returned 0x%x\n" , hr ) ) ;
|
||
|
}
|
||
|
|
||
|
if( SUCCEEDED( hr ) )
|
||
|
{
|
||
|
lstrcpy( pMachineName , V_BSTR( &varServerName ) );
|
||
|
|
||
|
KdPrint( ( "TSUSEREX: Server name is %ws\n" , pMachineName ) ) ;
|
||
|
}
|
||
|
|
||
|
VariantClear( &varServerName );
|
||
|
|
||
|
|
||
|
if( FAILED( hr ) )
|
||
|
{
|
||
|
// ADS_FORMAT_SERVER is not supported this could mean we're dealing with an WinNT format
|
||
|
// or a DS Provider that is poorly implemented
|
||
|
|
||
|
KdPrint( ( "IADsPathname could not obtain server name 0x%x\n" , hr ) );
|
||
|
|
||
|
// let's go wire tapping to get the server name
|
||
|
|
||
|
VARIANT v;
|
||
|
|
||
|
LPTSTR szDName = NULL;
|
||
|
|
||
|
ULONG ulDName = 0;
|
||
|
|
||
|
VariantInit(&v);
|
||
|
|
||
|
hr = pADs->Get(L"distinguishedName", &v);
|
||
|
|
||
|
if( FAILED( hr ) )
|
||
|
{
|
||
|
KdPrint( ( "TSUSEREX : pADs->Get( DN ) returned 0x%x\n", hr ) );
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
ASSERT_( V_VT( &v ) == VT_BSTR );
|
||
|
|
||
|
if( !TranslateNameW( V_BSTR(&v), NameFullyQualifiedDN, NameCanonical, szDName, &ulDName) )
|
||
|
{
|
||
|
KdPrint( ( "TSUSEREX : TranslateNameW failed with 0x%x\n", GetLastError( ) ) );
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
szDName = ( LPTSTR )new TCHAR[ ulDName + 1 ];
|
||
|
|
||
|
if( szDName == NULL )
|
||
|
{
|
||
|
KdPrint( ( "TSUSEREX : could not allocate space for szDName\n" ) );
|
||
|
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
if( !TranslateNameW( V_BSTR(&v), NameFullyQualifiedDN, NameCanonical, szDName, &ulDName) )
|
||
|
{
|
||
|
KdPrint( ( "TSUSEREX : TranslateNameW failed 2nd pass with 0x%x\n", GetLastError( ) ) );
|
||
|
|
||
|
delete[] szDName;
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
|
||
|
// perform LEFT$( szDName , up to '/' )
|
||
|
|
||
|
KdPrint( ( "TSUSEREX : TranslateNameW cracked the name to %ws\n" , szDName ) );
|
||
|
|
||
|
LPTSTR pszTemp = szDName;
|
||
|
|
||
|
while( pszTemp != NULL )
|
||
|
{
|
||
|
if( *pszTemp == L'/' )
|
||
|
{
|
||
|
*pszTemp = 0;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pszTemp++;
|
||
|
}
|
||
|
|
||
|
|
||
|
KdPrint( ("TranslateName with my LEFT$ returned %ws\n",szDName ) );
|
||
|
|
||
|
// get the domaincontroller name of the remote machine
|
||
|
|
||
|
DOMAIN_CONTROLLER_INFO *pdinfo;
|
||
|
|
||
|
DWORD dwStatus = DsGetDcName( NULL , szDName , NULL , NULL , 0 , &pdinfo );
|
||
|
|
||
|
KdPrint( ( "TSUSEREX : DsGetDcName: %ws returned 0x%x\n", pdinfo->DomainControllerName , dwStatus ) );
|
||
|
|
||
|
if( dwStatus == NO_ERROR )
|
||
|
{
|
||
|
lstrcpy( pMachineName , pdinfo->DomainControllerName );
|
||
|
|
||
|
NetApiBufferFree( pdinfo );
|
||
|
}
|
||
|
|
||
|
if( szDName != NULL )
|
||
|
{
|
||
|
delete[] szDName;
|
||
|
}
|
||
|
|
||
|
VariantClear( &v );
|
||
|
|
||
|
} // END else
|
||
|
|
||
|
|
||
|
pADs->Release( );
|
||
|
|
||
|
|
||
|
IADsUser *pADsUser = NULL;
|
||
|
|
||
|
hr = ADsGetObject( pwszObjName, IID_IADsUser, (void**)&pADsUser);
|
||
|
|
||
|
if( FAILED( hr ) )
|
||
|
{
|
||
|
KdPrint( ( "TSUSEREX: ADsGetObject failed to get the user object 0x%x\n",hr ) );
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
VARIANT var;
|
||
|
VARIANT varSid;
|
||
|
|
||
|
VariantInit(&var);
|
||
|
VariantInit(&varSid);
|
||
|
|
||
|
hr = pADsUser->Get(L"ObjectSid", &varSid);
|
||
|
|
||
|
if( FAILED( hr ) )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : IADsUser::Get( ObjectSid ) failed \n" );
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
if( !( varSid.vt & VT_ARRAY) )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : Object SID is not a VT_ARRAY\n" );
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
PSID pSid = NULL;
|
||
|
|
||
|
PSID pUserSid = NULL;
|
||
|
|
||
|
SafeArrayAccessData( varSid.parray, &pSid );
|
||
|
|
||
|
if( !IsValidSid( pSid ) )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : pSid is invalid\n" );
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
DWORD dwSidSize = GetLengthSid( pSid );
|
||
|
|
||
|
pUserSid = new BYTE[ dwSidSize ];
|
||
|
|
||
|
if( pUserSid == NULL )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : failed to allocate pUserSid\n" );
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
CopySid( dwSidSize , pUserSid , pSid );
|
||
|
|
||
|
*ppUserSid = pUserSid;
|
||
|
|
||
|
SafeArrayUnaccessData( varSid.parray );
|
||
|
|
||
|
VariantClear( &varSid );
|
||
|
|
||
|
|
||
|
hr = pADsUser->Get( L"samAccountName" , &var );
|
||
|
|
||
|
pADsUser->Release();
|
||
|
|
||
|
if( FAILED( hr ) )
|
||
|
{
|
||
|
KdPrint( ( "TSUSEREX : ADsUser::Get( name ) failed 0x%x\n", hr ) );
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
ASSERT_( V_VT( &var ) == VT_BSTR );
|
||
|
|
||
|
lstrcpy( pUserName , V_BSTR( &var ) );
|
||
|
|
||
|
KdPrint( ( "TSUSEREX : Server name %ws user name is %ws\n" , pMachineName , pUserName ) );
|
||
|
|
||
|
VariantClear( &var );
|
||
|
|
||
|
ReleaseStgMedium(&medium);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// CFSTR_DSOBJECTNAMES is NOT supported.
|
||
|
// It means we are dealing with local user manager.
|
||
|
// we must be able to get
|
||
|
// Allocate medium for GetDataHere.
|
||
|
|
||
|
medium.hGlobal = GlobalAlloc(GMEM_SHARE, MAX_PATH * sizeof(WCHAR));
|
||
|
|
||
|
if( !medium.hGlobal )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : GlobalAlloc failed in GetMachineAndUserName\n" );
|
||
|
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
*pbDSAType = FALSE;
|
||
|
|
||
|
// since we are doing data conversion.
|
||
|
// check for possible data loss.
|
||
|
|
||
|
ASSERT_(USHRT_MAX > s_cfMachineName);
|
||
|
|
||
|
// request the machine name from the dataobject.
|
||
|
|
||
|
fmte.cfFormat = (USHORT)s_cfMachineName;
|
||
|
|
||
|
hr = pDataObject->GetDataHere(&fmte, &medium);
|
||
|
|
||
|
if( FAILED( hr ) )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : @GetMachineAndUserName GetDataHere for s_cfMachineName failed\n" );
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// copy the machine name into our buffer
|
||
|
|
||
|
if( ( LPWSTR )medium.hGlobal != NULL && pMachineName != NULL )
|
||
|
{
|
||
|
wcscpy(pMachineName, (LPWSTR)medium.hGlobal );
|
||
|
}
|
||
|
|
||
|
// administer local accounts only for Terminal Servers
|
||
|
|
||
|
SERVER_INFO_101 *psi101;
|
||
|
HANDLE hTServer = NULL;
|
||
|
|
||
|
DWORD dwNetStatus = NetServerGetInfo( pMachineName , 101 , ( LPBYTE * )&psi101 );
|
||
|
|
||
|
if( dwNetStatus != NERR_Success )
|
||
|
{
|
||
|
KdPrint( ( "TSUSEREX:GetMachineAndUserName -- NetServerGetInfo failed with 0x%x\n", dwNetStatus ) );
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
if( psi101 == NULL )
|
||
|
{
|
||
|
KdPrint( ( "TSUSEREX:GetMachineAndUserName -- NetServerGetInfo failed getting sinfo101 0x%x\n",dwNetStatus ) );
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
KdPrint( ("TSUSEREX:NetServerGetInfo server bits returnd 0x%x and nttype is 0x%x\n", psi101->sv101_type , SV_TYPE_SERVER_NT ) );
|
||
|
|
||
|
BOOL fServer = ( BOOL )( psi101->sv101_type & ( DWORD )SV_TYPE_SERVER_NT );
|
||
|
|
||
|
NetApiBufferFree( ( LPVOID )psi101 );
|
||
|
|
||
|
if( !fServer )
|
||
|
{
|
||
|
|
||
|
KdPrint( ( "TSUSEREX : viewing local account on non-TS ( exiting )\n" ) );
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
hTServer = WinStationOpenServer( pMachineName );
|
||
|
if( hTServer == NULL )
|
||
|
{
|
||
|
KdPrint( ( "TSUSEREX: This OS does not support terminal services\n" ) ) ;
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
WinStationCloseServer( hTServer );
|
||
|
|
||
|
// since we are doing data conversion.
|
||
|
// check for possible data loss.
|
||
|
|
||
|
ASSERT_(USHRT_MAX > s_cfDisplayName);
|
||
|
|
||
|
// request data about user name.
|
||
|
|
||
|
fmte.cfFormat = (USHORT)s_cfDisplayName;
|
||
|
|
||
|
hr = pDataObject->GetDataHere( &fmte , &medium );
|
||
|
|
||
|
if( FAILED( hr ) )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : @GetMachineAndUserName GetDataHere for s_cfDisplayName failed\n" );
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// copy the user name into our buffer and release the medium.
|
||
|
|
||
|
if( ( LPWSTR )medium.hGlobal != NULL && pUserName != NULL )
|
||
|
{
|
||
|
wcscpy( pUserName , ( LPWSTR )medium.hGlobal );
|
||
|
}
|
||
|
|
||
|
ReleaseStgMedium( &medium );
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
TSUserExInterfaces::TSUserExInterfaces()
|
||
|
{
|
||
|
// LOGMESSAGE0(_T("TSUserExInterfaces::TSUserExInterfaces()..."));
|
||
|
// m_pUserConfigPage = NULL;
|
||
|
m_pTSUserSheet = NULL;
|
||
|
|
||
|
m_pDsadataobj = NULL;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
TSUserExInterfaces::~TSUserExInterfaces()
|
||
|
{
|
||
|
ODS( L"Good bye\n" );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
HRESULT TSUserExInterfaces::CreatePropertyPages(
|
||
|
LPPROPERTYSHEETCALLBACK lpProvider, // pointer to the callback interface
|
||
|
LONG_PTR , // handle for routing notification
|
||
|
LPDATAOBJECT lpIDataObject) // pointer to the data object);
|
||
|
{
|
||
|
//
|
||
|
// Test for valid parameters
|
||
|
//
|
||
|
|
||
|
if( lpIDataObject == NULL || IsBadReadPtr( lpIDataObject , sizeof( LPDATAOBJECT ) ) )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : @ CreatePropertyPages IDataObject is invalid\n " );
|
||
|
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
if( lpProvider == NULL )
|
||
|
{
|
||
|
ODS( L"TSUSEREX @ CreatePropertyPages LPPROPERTYSHEETCALLBACK is invalid\n" );
|
||
|
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
WCHAR wUserName[ MAX_PATH ];
|
||
|
|
||
|
WCHAR wMachineName[ MAX_PATH ];
|
||
|
|
||
|
BOOL bDSAType;
|
||
|
|
||
|
|
||
|
|
||
|
if( g_bPagesHaveBeenInvoked )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : TSUserExInterfaces::CreatePropertyPages pages have been invoked\n" );
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
|
||
|
PSID pUserSid = NULL;
|
||
|
|
||
|
|
||
|
if( FAILED( GetMachineAndUserName( lpIDataObject , wMachineName , wUserName , &bDSAType , &pUserSid ) ) )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : GetMachineAndUserName failed @CreatePropertyPages \n" );
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Test to see if we are being called twice
|
||
|
//
|
||
|
|
||
|
if( m_pTSUserSheet != NULL )
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// MMC likes to release IEXtendPropertySheet ( this object )
|
||
|
// so we cannot free CTSUserSheet in TSUserExInterfaces::dtor
|
||
|
// CTSUserSheet must release itself!!!
|
||
|
//
|
||
|
|
||
|
m_pTSUserSheet = new CTSUserSheet( );
|
||
|
|
||
|
if( m_pTSUserSheet != NULL )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : CreatePropertyPages mem allocation succeeded\n" );
|
||
|
|
||
|
m_pTSUserSheet->SetDSAType( bDSAType );
|
||
|
|
||
|
VERIFY_S( TRUE , m_pTSUserSheet->SetServerAndUser( &wMachineName[0] , &wUserName[0] ) );
|
||
|
|
||
|
m_pTSUserSheet->CopyUserSid( pUserSid );
|
||
|
|
||
|
VERIFY_S( S_OK , m_pTSUserSheet->AddPagesToPropSheet( lpProvider ) );
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
HRESULT TSUserExInterfaces::QueryPagesFor( LPDATAOBJECT /* lpDataObject */ )
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
// this has not been checked in yet!!!
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
STDMETHODIMP TSUserExInterfaces::GetHelpTopic( LPOLESTR *ppszHelp )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : GetHelpTopic\n" );
|
||
|
|
||
|
if( ppszHelp == NULL )
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
TCHAR tchHelpFile[ 80 ];
|
||
|
|
||
|
VERIFY_E( 0 , LoadString( _Module.GetResourceInstance( ) , IDS_TSUSERHELP , tchHelpFile , sizeof( tchHelpFile ) / sizeof( TCHAR ) ) );
|
||
|
|
||
|
// mmc will call CoTaskMemFree
|
||
|
|
||
|
*ppszHelp = ( LPOLESTR )CoTaskMemAlloc( sizeof( TCHAR ) * MAX_PATH );
|
||
|
|
||
|
if( *ppszHelp != NULL )
|
||
|
{
|
||
|
if( GetSystemWindowsDirectory( *ppszHelp , MAX_PATH ) != 0 )
|
||
|
{
|
||
|
lstrcat( *ppszHelp , tchHelpFile );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lstrcpy( *ppszHelp , tchHelpFile );
|
||
|
}
|
||
|
|
||
|
ODS( *ppszHelp );
|
||
|
|
||
|
ODS( L"\n" );
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
// IShellExtInit
|
||
|
|
||
|
STDMETHODIMP TSUserExInterfaces::Initialize(
|
||
|
LPCITEMIDLIST ,
|
||
|
LPDATAOBJECT lpdobj,
|
||
|
HKEY
|
||
|
)
|
||
|
{
|
||
|
m_pDsadataobj = lpdobj;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
// IShellPropSheetExt - this interface is used only for dsadmin based tools
|
||
|
// for this reason the DSAType flag is set to true.
|
||
|
|
||
|
STDMETHODIMP TSUserExInterfaces::AddPages(
|
||
|
LPFNADDPROPSHEETPAGE lpfnAddPage,
|
||
|
LPARAM lParam
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// Test for valid parameters
|
||
|
//
|
||
|
|
||
|
if( m_pDsadataobj == NULL )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : @ AddPages IDataObject is invalid\n " );
|
||
|
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
if( lpfnAddPage == NULL )
|
||
|
{
|
||
|
ODS( L"TSUSEREX @ AddPages LPFNADDPROPSHEETPAGE is invalid\n" );
|
||
|
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
WCHAR wUserName[ MAX_PATH ];
|
||
|
|
||
|
WCHAR wMachineName[ MAX_PATH ];
|
||
|
|
||
|
BOOL bDSAType;
|
||
|
|
||
|
PSID pUserSid = NULL;
|
||
|
|
||
|
|
||
|
if( FAILED( GetMachineAndUserName( m_pDsadataobj , wMachineName , wUserName , &bDSAType , &pUserSid ) ) )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : GetMachineAndUserName @AddPages failed \n" );
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
ODS( L"TSUSEREX : DSATYPE in AddPages\n" );
|
||
|
|
||
|
g_bPagesHaveBeenInvoked = TRUE;
|
||
|
|
||
|
//
|
||
|
// Test to see if we are being called twice
|
||
|
//
|
||
|
|
||
|
if( m_pTSUserSheet != NULL )
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// MMC likes to release IEXtendPropertySheet ( this object )
|
||
|
// so we cannot free CTSUserSheet in TSUserExInterfaces::dtor
|
||
|
// CTSUserSheet must release itself!!!
|
||
|
//
|
||
|
|
||
|
m_pTSUserSheet = new CTSUserSheet( );
|
||
|
|
||
|
if( m_pTSUserSheet != NULL )
|
||
|
{
|
||
|
ODS( L"TSUSEREX : AddPages mem allocation succeeded\n" );
|
||
|
|
||
|
m_pTSUserSheet->SetDSAType( bDSAType );
|
||
|
|
||
|
m_pTSUserSheet->CopyUserSid( pUserSid );
|
||
|
|
||
|
VERIFY_S( TRUE , m_pTSUserSheet->SetServerAndUser( &wMachineName[0] , &wUserName[0] ) );
|
||
|
|
||
|
VERIFY_S( S_OK , m_pTSUserSheet->AddPagesToDSAPropSheet( lpfnAddPage , lParam ) );
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
|
||
|
STDMETHODIMP TSUserExInterfaces::ReplacePage(
|
||
|
UINT ,
|
||
|
LPFNADDPROPSHEETPAGE ,
|
||
|
LPARAM
|
||
|
)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef _RTM_ // add ISnapinAbout
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
STDMETHODIMP TSUserExInterfaces::GetSnapinDescription(
|
||
|
LPOLESTR *ppOlestr )
|
||
|
{
|
||
|
TCHAR tchMessage[] = TEXT("This extension allows the administrator to configure Terminal Services user properties. This extension is only enabled on Terminal Servers.");
|
||
|
|
||
|
ODS( L"TSUSEREX: GetSnapinDescription called\n" );
|
||
|
|
||
|
*ppOlestr = ( LPOLESTR )CoTaskMemAlloc( ( lstrlen( tchMessage ) + 1 ) * sizeof( TCHAR ) );
|
||
|
|
||
|
if( *ppOlestr != NULL )
|
||
|
{
|
||
|
lstrcpy( *ppOlestr , tchMessage );
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
STDMETHODIMP TSUserExInterfaces::GetProvider(
|
||
|
LPOLESTR *ppOlestr )
|
||
|
{
|
||
|
TCHAR tchMessage[] = TEXT("Microsoft Corporation");
|
||
|
|
||
|
ODS( L"TSUSEREX: GetProvider called\n" );
|
||
|
|
||
|
*ppOlestr = ( LPOLESTR )CoTaskMemAlloc( ( lstrlen( tchMessage ) + 1 ) * sizeof( TCHAR ) );
|
||
|
|
||
|
if( *ppOlestr != NULL )
|
||
|
{
|
||
|
lstrcpy( *ppOlestr , tchMessage );
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
STDMETHODIMP TSUserExInterfaces::GetSnapinVersion(
|
||
|
LPOLESTR *ppOlestr )
|
||
|
{
|
||
|
char chMessage[ 32 ] = VER_PRODUCTVERSION_STR;
|
||
|
|
||
|
TCHAR tchMessage[32];
|
||
|
|
||
|
ODS( L"TSUSEREX: GetSnapinVersion called\n" );
|
||
|
|
||
|
int iCharCount = MultiByteToWideChar( CP_ACP , 0 , chMessage , sizeof( chMessage ) , tchMessage , sizeof( tchMessage ) / sizeof( TCHAR ) );
|
||
|
|
||
|
//wsprintf( tchMessage , TEXT( "%d" ) , VER_PRODUCTVERSION_DW );
|
||
|
|
||
|
*ppOlestr = ( LPOLESTR )CoTaskMemAlloc( ( iCharCount + 1 ) * sizeof( TCHAR ) );
|
||
|
|
||
|
if( *ppOlestr != NULL )
|
||
|
{
|
||
|
lstrcpy( *ppOlestr , tchMessage );
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
STDMETHODIMP TSUserExInterfaces::GetSnapinImage(
|
||
|
HICON * )
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
STDMETHODIMP TSUserExInterfaces::GetStaticFolderImage(
|
||
|
/* [out] */ HBITMAP *,
|
||
|
/* [out] */ HBITMAP *,
|
||
|
/* [out] */ HBITMAP *,
|
||
|
/* [out] */ COLORREF *)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
#endif //_RTM_
|
||
|
|
||
|
|