// // Copyright 1997 - Microsoft // // // CCOMPUTR.CPP - Handles the computer object property pages. // #include "pch.h" #include "client.h" #include "server.h" #include "ccomputr.h" #include "varconv.h" // // Begin Class Definitions // DEFINE_MODULE("IMADMUI") DEFINE_THISCLASS("CComputer") #define THISCLASS CComputer #define LPTHISCLASS LPCComputer // ************************************************************************ // // Constructor / Destructor // // ************************************************************************ // // CreateInstance() // LPVOID CComputer_CreateInstance( void ) { TraceFunc( "CComputer_CreateInstance()\n" ); LPTHISCLASS lpcc = new THISCLASS( ); if (!lpcc) RETURN(lpcc); HRESULT hr = THR( lpcc->Init( ) ); if ( hr ) { delete lpcc; RETURN(NULL); } RETURN((LPVOID) lpcc); } // // CreateCComputer( ) // LPVOID CreateIntelliMirrorClientComputer( IADs * pads) { TraceFunc( "CreateCComputer(" ); TraceMsg( TF_FUNC, "pads = 0x%08x )\n", pads ); HRESULT hr; LPTHISCLASS lpcc = NULL; if ( !pads ) { hr = THR( E_POINTER ); goto Error; } lpcc = new THISCLASS( ); if ( !lpcc ) { hr = THR( E_OUTOFMEMORY ); goto Error; } hr = THR( lpcc->Init( ) ); if ( hr ) goto Error; hr = lpcc->Init2( pads ); if (hr != S_FALSE) { hr = THR(E_FAIL); // account exists? goto Error; } Cleanup: RETURN((LPVOID) lpcc); Error: if (lpcc) { delete lpcc; lpcc = NULL; } switch (hr) { case S_OK: break; default: MessageBoxFromHResult( NULL, IDC_ERROR_CREATINGACCOUNT_TITLE, hr ); break; } goto Cleanup; } // // Init2( ) // STDMETHODIMP THISCLASS::Init2( IADs * pads ) { TraceClsFunc( "Init2( ... )\n" ); HRESULT hr; _pads = pads; _pads->AddRef( ); hr = _pads->Get( NETBOOTGUID, &_vGUID ); if (FAILED( hr ) && hr != E_ADS_PROPERTY_NOT_FOUND ) goto Cleanup; hr = _pads->Get( NETBOOTSAP, &_vSCP ); if (FAILED( hr ) && hr != E_ADS_PROPERTY_NOT_FOUND ) goto Cleanup; hr = _pads->Get( NETBOOTMACHINEFILEPATH, &_vMachineFilepath ); if (FAILED( hr ) && hr != E_ADS_PROPERTY_NOT_FOUND ) goto Cleanup; hr = _pads->Get( NETBOOTINITIALIZATION, &_vInitialization ); if (FAILED( hr ) && hr != E_ADS_PROPERTY_NOT_FOUND ) goto Cleanup; if ( _vSCP.vt == VT_EMPTY || _vGUID.vt == VT_EMPTY || _vInitialization.vt == VT_EMPTY || _vMachineFilepath.vt == VT_EMPTY ) { // // These must be blank since we are setting the attributes // of a newly created MAO. // hr = S_FALSE; goto Cleanup; } hr = S_OK; Cleanup: HRETURN(hr); } // // Constructor // THISCLASS::THISCLASS( ) { TraceClsFunc( "CComputer()\n" ); InterlockIncrement( g_cObjects ); TraceFuncExit(); } // // Init() // STDMETHODIMP THISCLASS::Init( ) { HRESULT hr = S_OK; TraceClsFunc( "Init()\n" ); // IUnknown stuff BEGIN_QITABLE_IMP( CComputer, IShellExtInit ); QITABLE_IMP( IShellExtInit ); QITABLE_IMP( IShellPropSheetExt ); QITABLE_IMP( IMAO ); END_QITABLE_IMP( CComputer ); Assert( _cRef == 0); AddRef( ); hr = CheckClipboardFormats( ); // Private Members Assert( !_pads ); Assert( !_pDataObj ); VariantInit( &_vGUID ); VariantInit( &_vMachineFilepath ); VariantInit( &_vInitialization ); VariantInit( &_vSCP ); // _InitParams should already be zero'ed. _InitParams.dwSize = sizeof(_InitParams); _uMode = MODE_SHELL; // default HRETURN(hr); } // // Destructor // THISCLASS::~THISCLASS( ) { TraceClsFunc( "~CComputer()\n" ); // Members if ( _pads ) { // // note: we shouldn't commit anything in the destructor -- we can't // catch failures here. We'll just have to make sure that we // explicitly commit changes when necessary // #if 0 // Commit any changes before we release THR( _pads->SetInfo( ) ); #endif _pads->Release( ); } if ( _pDataObj ) _pDataObj->Release( ); if ( _pszObjectName ) TraceFree( _pszObjectName ); VariantClear( &_vGUID ); VariantClear( &_vMachineFilepath ); VariantClear( &_vInitialization ); VariantClear( &_vSCP ); #if 0 // EricB might be adding an AddRef( ) to this. Until then, don't release. if ( _InitParams.pDsObj ) _InitParams.pDsObj->Release( ); #endif InterlockDecrement( g_cObjects ); TraceFuncExit(); }; // ************************************************************************ // // IUnknown // // ************************************************************************ // // QueryInterface() // STDMETHODIMP THISCLASS::QueryInterface( REFIID riid, LPVOID *ppv ) { TraceClsFunc( "" ); HRESULT hr = ::QueryInterface( this, _QITable, riid, ppv ); // Ugly ugly ulgy... but it works if ( hr == E_NOINTERFACE && _pDataObj ) { hr = _pDataObj->QueryInterface( riid, ppv ); } QIRETURN( hr, riid ); } // // AddRef() // STDMETHODIMP_(ULONG) THISCLASS::AddRef( void ) { TraceClsFunc( "[IUnknown] AddRef( )\n" ); InterlockIncrement( _cRef ); RETURN(_cRef); } // // Release() // STDMETHODIMP_(ULONG) THISCLASS::Release( void ) { TraceClsFunc( "[IUnknown] Release( )\n" ); InterlockDecrement( _cRef ); if ( _cRef ) RETURN(_cRef); TraceDo( delete this ); RETURN(0); } // ************************************************************************ // // IShellExtInit // // ************************************************************************ // // Initialize() // STDMETHODIMP THISCLASS::Initialize( LPCITEMIDLIST pidlFolder, LPDATAOBJECT lpdobj, HKEY hkeyProgID ) { TraceClsFunc( "[IShellExtInit] Initialize( " ); TraceMsg( TF_FUNC, " pidlFolder = 0x%08x, lpdobj = 0x%08x, hkeyProgID = 0x%08x )\n", pidlFolder, lpdobj, hkeyProgID ); if ( !lpdobj ) RETURN(E_INVALIDARG); HRESULT hr = S_OK; FORMATETC fmte; STGMEDIUM stg = { 0 }; STGMEDIUM stgOptions = { 0 }; LPWSTR pszObjectName; LPWSTR pszClassName; LPWSTR pszAttribPrefix; LPDSOBJECT pDsObject; LPDSOBJECTNAMES pDsObjectNames; LPDSDISPLAYSPECOPTIONS pDsDisplayOptions; BOOL b; // Hang onto it _pDataObj = lpdobj; _pDataObj->AddRef( ); // // Retrieve the Object Names // fmte.cfFormat = (CLIPFORMAT)g_cfDsObjectNames; fmte.tymed = TYMED_HGLOBAL; fmte.dwAspect = DVASPECT_CONTENT; fmte.lindex = -1; fmte.ptd = 0; hr = THR( lpdobj->GetData( &fmte, &stg) ); if ( hr ) goto Cleanup; pDsObjectNames = (LPDSOBJECTNAMES) stg.hGlobal; Assert( stg.tymed == TYMED_HGLOBAL ); TraceMsg( TF_ALWAYS, "Object's Namespace CLSID: " ); TraceMsgGUID( TF_ALWAYS, pDsObjectNames->clsidNamespace ); TraceMsg( TF_ALWAYS, "\tNumber of Objects: %u \n", pDsObjectNames->cItems ); Assert( pDsObjectNames->cItems == 1 ); pDsObject = (LPDSOBJECT) pDsObjectNames->aObjects; pszObjectName = (LPWSTR) PtrToByteOffset( pDsObjectNames, pDsObject->offsetName ); pszClassName = (LPWSTR) PtrToByteOffset( pDsObjectNames, pDsObject->offsetClass ); TraceMsg( TF_ALWAYS, "Object Name (Class): %s (%s)\n", pszObjectName, pszClassName ); // // This must be a "Computer" class // if ( StrCmp( pszClassName, DSCOMPUTERCLASSNAME ) ) { hr = S_FALSE; goto Error; } // // Retrieve the Display Spec Options // fmte.cfFormat = (CLIPFORMAT)g_cfDsDisplaySpecOptions; fmte.tymed = TYMED_HGLOBAL; fmte.dwAspect = DVASPECT_CONTENT; fmte.lindex = -1; fmte.ptd = 0; hr = THR( lpdobj->GetData( &fmte, &stgOptions ) ); if ( hr ) goto Cleanup; pDsDisplayOptions = (LPDSDISPLAYSPECOPTIONS) stgOptions.hGlobal; Assert( stgOptions.tymed == TYMED_HGLOBAL ); Assert( pDsDisplayOptions->dwSize >= sizeof(DSDISPLAYSPECOPTIONS) ); pszAttribPrefix = (LPWSTR) PtrToByteOffset( pDsDisplayOptions, pDsDisplayOptions->offsetAttribPrefix ); // TraceMsg( TF_ALWAYS, TEXT("Attribute Prefix: %s\n"), pszAttribPrefix ); if ( StrCmpW( pszAttribPrefix, STRING_ADMIN ) == 0 ) { _uMode = MODE_ADMIN; } // else default from Init() TraceMsg( TF_ALWAYS, TEXT("Mode: %s\n"), _uMode ? TEXT("Admin") : TEXT("Shell") ); ReleaseStgMedium( &stgOptions ); _pszObjectName = TraceStrDup( pszObjectName ); if ( !_pszObjectName ) goto OutOfMemory; // create the DS notify object hr = THR( ADsPropCreateNotifyObj( _pDataObj, _pszObjectName, &_hwndNotify ) ); if (FAILED( hr )) goto Error; b = ADsPropGetInitInfo( _hwndNotify, &_InitParams ); if ( !b ) { hr = E_FAIL; goto Error; } hr = THR( _InitParams.hr ); if (FAILED( hr )) goto Error; hr = THR( _InitParams.pDsObj->QueryInterface( IID_IADs, (void**) &_pads ) ); if (FAILED( hr )) goto Error; // // Retrieve the attributes // hr = _pads->Get( NETBOOTGUID, &_vGUID ); if (FAILED( hr ) && hr != E_ADS_PROPERTY_NOT_FOUND ) goto Error; hr = _pads->Get( NETBOOTSAP, &_vSCP ); if (FAILED( hr ) && hr != E_ADS_PROPERTY_NOT_FOUND ) goto Error; // // Check to see if this is an MAO that we need to add // ourselves to. // if ( _vSCP.vt == VT_EMPTY && _vGUID.vt == VT_EMPTY ) { // // This MAO is not a IntelliMirror client or server. // hr = S_FALSE; goto Error; } hr = _pads->Get( NETBOOTMACHINEFILEPATH, &_vMachineFilepath ); if (FAILED( hr ) && hr != E_ADS_PROPERTY_NOT_FOUND ) goto Error; hr = _pads->Get( NETBOOTINITIALIZATION, &_vInitialization ); if (FAILED( hr ) && hr != E_ADS_PROPERTY_NOT_FOUND ) goto Error; // // Fix HR // if ( hr == E_ADS_PROPERTY_NOT_FOUND ) { hr = S_OK; } Cleanup: ReleaseStgMedium( &stg ); HRETURN(hr); OutOfMemory: hr = E_OUTOFMEMORY; // fall thru Error: switch (hr) { case S_OK: break; case S_FALSE: hr = E_FAIL; // don't show page break; default: MessageBoxFromHResult( NULL, IDS_ERROR_READINGCOMPUTERACCOUNT, hr ); break; } goto Cleanup; } // ************************************************************************ // // IShellPropSheetExt // // ************************************************************************ // // AddPages() // STDMETHODIMP THISCLASS::AddPages( LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam) { TraceClsFunc( "[IShellPropSheetExt] AddPages( )\n" ); if ( !lpfnAddPage ) HRETURN(E_POINTER); HRESULT hr = S_OK; BOOL fServer; hr = THR( IsServer( &fServer ) ); if (FAILED( hr )) goto Error; if ( fServer ) { // // Add the "IntelliMirror" tab for servers // hr = THR( ::AddPagesEx( NULL, CServerTab_CreateInstance, lpfnAddPage, lParam, (LPUNKNOWN) (IShellExtInit*) this ) ); if (FAILED( hr )) goto Error; } else { // // Add the "IntelliMirror" tab for clients // hr = THR( ::AddPagesEx( NULL, CClientTab_CreateInstance, lpfnAddPage, lParam, (LPUNKNOWN) (IShellExtInit*) this ) ); if (FAILED( hr )) goto Error; } // Release our count on it. // _pDataObj->Release( ); // _pDataObj = NULL; Error: HRETURN(hr); } // // ReplacePage() // STDMETHODIMP THISCLASS::ReplacePage( UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam ) { TraceClsFunc( "[IShellPropSheetExt] ReplacePage( ) *** NOT_IMPLEMENTED ***\n" ); RETURN(E_NOTIMPL); } // ************************************************************************ // // IMAO (Private) // // ************************************************************************ // // CommitChanges( ) // STDMETHODIMP THISCLASS::CommitChanges( void ) { TraceClsFunc("[IMAO] CommitChanges( )\n" ); HRESULT hr = THR( _pads->SetInfo( ) ); HRETURN(hr); } // // IsAdmin( ) // STDMETHODIMP THISCLASS::IsAdmin( BOOL * fAdmin ) { TraceClsFunc( "[IMAO] IsAdmin( )\n" ); if ( !fAdmin ) HRETURN( E_INVALIDARG ); HRESULT hr = S_OK; *fAdmin = (_uMode == MODE_ADMIN); HRETURN(hr); } // // IsServer( ) // STDMETHODIMP THISCLASS::IsServer( BOOL * fServer ) { TraceClsFunc( "[IMAO] IsServer( )\n" ); if ( !fServer ) HRETURN( E_INVALIDARG ); HRESULT hr = S_OK; *fServer = (_vSCP.vt != VT_EMPTY); HRETURN(hr); } // // IsClient( ) // STDMETHODIMP THISCLASS::IsClient( BOOL * fClient ) { TraceClsFunc( "[IMAO] IsClient( )\n" ); if ( !fClient) HRETURN( E_INVALIDARG ); HRESULT hr = S_OK; *fClient = (_vGUID.vt != VT_EMPTY ) | (_vMachineFilepath.vt != VT_EMPTY ) | (_vInitialization.vt != VT_EMPTY ); HRETURN(hr); } // // SetServerName( ) // STDMETHODIMP THISCLASS::SetServerName( LPWSTR pszName ) { TraceClsFunc( "[IMAO] SetServerName( " ); TraceMsg( TF_FUNC, "pszName = %s )\n", pszName ); HRESULT hr = S_OK; LPWSTR pszFilepath = NULL; VARIANT var; if ( V_VT( &_vMachineFilepath ) == VT_BSTR ) { pszFilepath = StrChr( _vMachineFilepath.bstrVal, L'\\' ); } // // Create variant with new Server\Filepath string // VariantInit( &var ); if ( !pszName || pszName[0] == L'\0' ) { hr = THR( _pads->PutEx( ADS_PROPERTY_CLEAR, NETBOOTMACHINEFILEPATH, var ) ); DebugMsg( "Cleared MachineFilepath\n" ); } else { if ( pszFilepath ) { WCHAR szBuf[ DNS_MAX_NAME_LENGTH + 1 + 128 /* DHCP BOOTP PATH */ + 1 ]; wsprintf( szBuf, L"%s\\%s", pszName, pszFilepath ); PackStringToVariant( &var, szBuf); DebugMsg( "Set MachineFilepath to %s\n", szBuf ); } else { hr = PackStringToVariant( &var, pszName ); if ( FAILED( hr ) ) goto Cleanup; DebugMsg( "Set MachineFilepath to %s\n", pszName ); } // // Set the property // hr = THR( _pads->Put( NETBOOTMACHINEFILEPATH, var ) ); } if (FAILED( hr )) goto Cleanup; // // Release the old variant and shallow copy the new one to the // MachineFilepath variant. No need to release the "var". // VariantClear( &_vMachineFilepath ); _vMachineFilepath = var; VariantInit( &var ); // don't free Cleanup: VariantClear( &var ); HRETURN(hr); } // // GetServerName( ) // STDMETHODIMP THISCLASS::GetServerName( LPWSTR * ppszName ) { TraceClsFunc( "[IMAO] GetServerName( " ); TraceMsg( TF_FUNC, "*ppszName = 0x%08x )\n", *ppszName ); HRESULT hr = S_OK; LPWSTR psz = _vMachineFilepath.bstrVal; if ( !ppszName ) HRETURN( E_INVALIDARG ); *ppszName = NULL; if ( _vMachineFilepath.vt != VT_BSTR || _vMachineFilepath.bstrVal == NULL ) HRETURN( E_ADS_PROPERTY_NOT_FOUND ); if ( *psz == L'\0' ) { hr = S_FALSE; } else { // Find the Filepath while ( *psz && *psz != L'\\' ) psz++; *psz = L'\0'; *ppszName = (LPWSTR) TraceStrDup( _vMachineFilepath.bstrVal ); if ( !*ppszName ) hr = E_OUTOFMEMORY; } HRETURN(hr); } // // SetGUID( ) // STDMETHODIMP THISCLASS::SetGUID( LPWSTR pszGUID ) { TraceClsFunc("[IMAO] SetGUID( )\n" ); HRESULT hr = E_FAIL; BYTE uGUID[16]; VARIANT var; VariantInit( &var ); if ( !pszGUID ) { hr = THR( _pads->PutEx( ADS_PROPERTY_CLEAR, NETBOOTGUID, var ) ); if (FAILED( hr )) goto Cleanup; VariantClear( &_vGUID ); } else { if ( ValidateGuid(pszGUID,uGUID,NULL) == S_OK ) { // // Put it into a variant // PackBytesToVariant( &var, uGUID, 16 ); VariantClear( &_vGUID ); _vGUID = var; hr = THR( _pads->Put( NETBOOTGUID, _vGUID ) ); if (FAILED( hr )) goto Cleanup; } else // I don't know what it is. { Assert( FALSE ); VariantClear( &var ); hr = E_INVALIDARG; goto Cleanup; } } Cleanup: HRETURN(hr); } // // GetGUID( ) // STDMETHODIMP THISCLASS::GetGUID( IN LPWSTR * ppszGUID OPTIONAL, IN LPBYTE uGUID OPTIONAL ) { TraceClsFunc("[IMAO] GetGUID( )\n" ); HRESULT hr = S_OK; LPBYTE ptr = NULL; VARIANT var = _vGUID; LONG Length; if ( ppszGUID != NULL ) { *ppszGUID = NULL; } if ( var.vt == VT_EMPTY ) HRETURN( HRESULT_FROM_WIN32(ERROR_INVALID_DATA)); if ( SafeArrayGetDim( var.parray ) != 1 ) HRETURN( HRESULT_FROM_WIN32(ERROR_INVALID_DATA)); hr = THR( SafeArrayGetUBound( var.parray, 1, &Length ) ); if (FAILED( hr )) goto Cleanup; Assert( Length == 15 ); if ( Length != 15 ) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); goto Cleanup; } hr = THR( SafeArrayAccessData( var.parray, (LPVOID*)&ptr ) ); if (FAILED( hr )) goto Cleanup; if ( uGUID != NULL ) { memcpy( uGUID, ptr, 16 * sizeof(BYTE) ); } if ( ppszGUID != NULL ) { *ppszGUID = PrettyPrintGuid( ptr ); if ( !*ppszGUID ) { hr = E_OUTOFMEMORY; goto Cleanup; } } hr = S_OK; Cleanup: if ( ptr ) SafeArrayUnaccessData( var.parray ); HRETURN(hr); } // // GetSAP( ) // STDMETHODIMP THISCLASS::GetSAP( LPVOID *punk ) { TraceClsFunc( "[IMAO] GetSAP( punk )\n" ); HRESULT hr = S_OK; LPWSTR pszDN = NULL; *punk = NULL; if ( _vSCP.vt != VT_BSTR ) { hr = E_ADS_PROPERTY_NOT_FOUND; goto Cleanup; } Assert( _vSCP.vt == VT_BSTR ); Assert( _vSCP.bstrVal ); // pre-pend the "LDAP://server/" from our DN hr = _FixObjectPath( V_BSTR( &_vSCP ), &pszDN ); if (FAILED( hr )) goto Cleanup; // Bind to the MAO in the DS hr = THR( ADsGetObject( pszDN, IID_IADs, punk ) ); if (FAILED( hr )) goto Cleanup; Cleanup: if ( pszDN ) TraceFree( pszDN ); HRETURN(hr); } // // _FixObjectPath( ) // HRESULT THISCLASS::_FixObjectPath( LPWSTR pszOldObjectPath, LPWSTR *ppszNewObjectPath ) { TraceClsFunc( "_FixObjectPath()\n" ); if ( !ppszNewObjectPath ) HRETURN(E_POINTER); HRESULT hr; LPWSTR psz = NULL; *ppszNewObjectPath = NULL; // Try to parse the string to connect to the same server as the DSADMIN if ( _pszObjectName && StrCmpNI( _pszObjectName, L"LDAP://", 7 ) == 0 ) { psz = _pszObjectName + 7; } else if ( _pszObjectName && StrCmpNI( _pszObjectName, L"GC://", 5 ) == 0 ) { psz = _pszObjectName + 5; } if ( psz ) { psz = StrChr( psz, L'/' ); psz++; INT_PTR uLen = psz - _pszObjectName; // get a chunk of memory, pre-zero'ed psz = TraceAllocString( LPTR, (size_t) uLen + wcslen( pszOldObjectPath ) + 1 ); if ( !psz ) goto OutOfMemory; MoveMemory( psz, _pszObjectName, uLen * sizeof(WCHAR) ); wcscat( psz, pszOldObjectPath); *ppszNewObjectPath = psz; } else { // find another server hr = THR( LDAPPrefix( pszOldObjectPath, ppszNewObjectPath ) ); } Assert( ppszNewObjectPath || hr != S_OK ); HRETURN(hr); OutOfMemory: HRETURN(E_OUTOFMEMORY); } // // GetDataObject( ) // STDMETHODIMP THISCLASS::GetDataObject( LPDATAOBJECT * pDataObj ) { TraceClsFunc( "GetDataObject( ... )\n "); if ( !pDataObj ) HRETURN(E_POINTER); *pDataObj = _pDataObj; _pDataObj->AddRef( ); HRETURN(S_OK); } // // // STDMETHODIMP THISCLASS::GetNotifyWindow( HWND *phNotifyObj ) { TraceClsFunc( "GetNotifyWindow( ... )\n" ); if ( !phNotifyObj ) HRETURN(E_POINTER); *phNotifyObj = _hwndNotify; HRETURN(S_OK); }