/*++ Copyright (c) 1997 Microsoft Corporation Module Name: faxcompd.cpp Abstract: This file contains my implementation of IComponentData. Environment: WIN32 User Mode Author: Darwin Ouyang (t-darouy) 30-Sept-1997 --*/ // faxcompdata.cpp : Implementation of CFaxComponentData #include "stdafx.h" #include "faxadmin.h" #include "faxcomp.h" #include "faxcompd.h" #include "faxdataobj.h" #include "faxhelper.h" #include "faxstrt.h" #include "iroot.h" #include "idevice.h" #pragma hdrstop //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // // // Constructor and destructor // // CFaxComponentData::CFaxComponentData() /*++ Routine Description: Constructor. Arguments: None. Return Value: None. --*/ { m_pUnknown = NULL; // IUnknown m_pConsoleNameSpace = NULL; // IConsoleNameSpace m_pConsole = NULL; // IConsole m_pImageList = NULL; // IImageList m_pControlbar = NULL; // IControlbar m_FaxHandle = NULL; // Fax connection handle; m_bRpcErrorHasHappened = TRUE; // Fax server is down until we connect. m_dwPropSheetCount = 0; DebugPrint(( TEXT( "FaxComponentData Created" ) )); globalRoot = new CInternalRoot( NULL, this ); assert( globalRoot != NULL ); // Initialize the critical section. InitializeCriticalSection( &GlobalCriticalSection ); InitializeCriticalSection( &CInternalDevice::csDeviceLock ); } CFaxComponentData::~CFaxComponentData() /*++ Routine Description: Destructor. Arguments: None. Return Value: None. --*/ { assert( globalRoot != NULL ); if( globalRoot != NULL ) { delete globalRoot; } DebugPrint(( TEXT( "FaxComponentData Destroyed" ) )); } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // // // CFaxComponentData implementation // // HRESULT STDMETHODCALLTYPE CFaxComponentData::Initialize( IN LPUNKNOWN pUnknown) /*++ Routine Description: This routine initializes IComponentData by querying for needed interfaces. Arguments: pUnknown - the console's IUnknown interface. Return Value: HRESULT indicating SUCCEEDED() or FAILED() --*/ { HRESULT hr; DebugPrint(( TEXT("Trace: CFaxComponentData::Initialize") )); do { assert(globalRoot != NULL ); if(globalRoot == NULL ) { hr = E_UNEXPECTED; break; } assert(pUnknown != NULL); if( pUnknown == NULL ) { hr = E_POINTER; break; } // MMC should only call ::Initialize once! assert(m_pUnknown == NULL); if( m_pUnknown != NULL ) { hr = E_UNEXPECTED; break; } m_pUnknown = pUnknown; m_pUnknown->AddRef(); // retrieve and store away all the interface pointers I might want // // Get pointer to IConsole // hr = pUnknown->QueryInterface(IID_IConsole, (VOID**)(&m_pConsole)); assert( SUCCEEDED(hr) ); if( FAILED( hr ) ) { break; } // // Get pointer to IConsoleNameSpace // hr = pUnknown->QueryInterface(IID_IConsoleNameSpace, (VOID**)(&m_pConsoleNameSpace)); assert( SUCCEEDED(hr) ); if( FAILED( hr ) ) { break; } // // Get pointer to IImageList for scope pane // //hr = pUnknown->QueryInterface(IID_IImageList, (VOID**)(&m_pImageList)); hr = m_pConsole->QueryScopeImageList( &m_pImageList ); assert( SUCCEEDED(hr) ); if( FAILED( hr ) ) { break; } // setup my images in the imagelist hr = InsertIconsIntoImageList( m_pImageList ); assert( SUCCEEDED(hr) ); if( FAILED( hr ) ) { break; } } while( 0 ); // damage control if( FAILED( hr ) ) { if( m_pUnknown != NULL ) { m_pUnknown->Release(); m_pUnknown = NULL; } if( m_pConsole != NULL ) { m_pConsole->Release(); m_pConsole = NULL; } if( m_pConsoleNameSpace != NULL ) { m_pConsoleNameSpace->Release(); m_pConsoleNameSpace = NULL; } if( m_pImageList != NULL ) { m_pImageList->Release(); m_pImageList = NULL; } } return hr; } HRESULT STDMETHODCALLTYPE CFaxComponentData::CreateComponent( OUT LPCOMPONENT __RPC_FAR *ppComponent) /*++ Routine Description: This routine creates and returns an IComponent interface. Arguments: ppComponent - the new IComponent is returned here. Return Value: HRESULT indicating SUCCEEDED() or FAILED() --*/ { HRESULT hr = S_OK; CFaxComponent * temp = NULL; DebugPrint(( TEXT("Trace: CFaxComponentData::CreateComponent") )); // // MMC asks us for a pointer to the IComponent interface // if( ppComponent != NULL ) { temp = new CComObject; if( temp == NULL ) { return E_OUTOFMEMORY; } temp->SetOwner( this ); *ppComponent = temp; (*ppComponent)->AddRef(); } else { hr = E_POINTER; } return hr; } HRESULT STDMETHODCALLTYPE CFaxComponentData::Notify( IN LPDATAOBJECT lpDataObject, IN MMC_NOTIFY_TYPE event, IN LPARAM arg, IN LPARAM param) /*++ Routine Description: This routine dispatches events sent to the IComponentData interface using the cookie extracted from the DataObject. The cookie stored is a pointer to the class that implements behavior for that subfolder. So we delegate all the messages by taking the cookie casting it to a pointer to a folder, and invoking the notify method. Arguments: lpDataobject - the data object event - the event type arg, param - event arguments Return Value: HRESULT indicating SUCCEEDED() or FAILED() --*/ { HRESULT hr = S_OK; CFaxDataObject * dataObject = NULL; LONG_PTR cookie; // DebugPrint(( TEXT("Trace: CFaxComponentData::Notify") )); if( lpDataObject != NULL) { dataObject = ExtractOwnDataObject( lpDataObject ); if( dataObject == NULL ) { return E_UNEXPECTED; } cookie = dataObject->GetCookie(); if( cookie == NULL) { // my static node hr = globalRoot->ScopeNotify( this, dataObject, event, arg, param ); } else { // cast the cookie to a pointer try { hr = ((CInternalNode *)cookie)->ScopeNotify( this, dataObject, event, arg, param ); } catch ( ... ) { DebugPrint(( TEXT("Invalid Cookie: 0x%08x"), cookie )); assert( FALSE ); // got passed an INVALID COOKIE!?!?!?!? hr = E_UNEXPECTED; } } } else { // some events do not pass a lpDataObject // if we want to handle these event, we // have to do it here if( event == MMCN_PROPERTY_CHANGE ) { if( param != NULL ) { try { hr = ((CInternalNode *)param)->ScopeNotify( this, NULL, event, arg, param ); } catch ( ... ) { DebugPrint(( TEXT("Invalid Cookie") )); assert( FALSE ); // got passed an INVALID COOKIE!?!?!?!? hr = E_UNEXPECTED; } } } } return hr; } HRESULT STDMETHODCALLTYPE CFaxComponentData::Destroy( void ) /*++ Routine Description: This method releases all the aquired console interface in preperation for the snapin being destroyed. Arguments: None. Return Value: HRESULT indicating SUCCEEDED() or FAILED() --*/ { DebugPrint(( TEXT("Trace: CFaxComponentData::Destroy") )); // the prop sheet count should never be negative assert( QueryPropSheetCount() >= 0 ); // check to see if any property sheets are up while( QueryPropSheetCount() > 0 ) { DebugPrint(( TEXT("Trace: QueryPropSheetCount() %d "), QueryPropSheetCount() )); // don't allow deletion GlobalStringTable->PopUpMsg( NULL, IDS_PROP_SHEET_STILL_UP, TRUE, NULL ); } // Free interfaces if( m_pUnknown != NULL ) { m_pUnknown->Release(); m_pUnknown = NULL; } if( m_pConsole != NULL ) { m_pConsole->Release(); m_pConsole = NULL; } if( m_pConsoleNameSpace != NULL ) { m_pConsoleNameSpace->Release(); m_pConsoleNameSpace = NULL; } if( m_pImageList != NULL ) { m_pImageList->Release(); m_pImageList = NULL; } if( m_pControlbar != NULL ) { m_pControlbar->Release(); m_pControlbar = NULL; } return S_OK; } HRESULT STDMETHODCALLTYPE CFaxComponentData::QueryDataObject( IN MMC_COOKIE cookie, IN DATA_OBJECT_TYPES type, OUT LPDATAOBJECT __RPC_FAR *ppDataObject) /*++ Routine Description: This method dispatches DataObjects requests to the appropriate nodes using the cookie. Arguments: cookie - the cookie for the associated node type - the type of the cookie ppDataobject - a pointer to the new data object is stored here Return Value: HRESULT indicating SUCCEEDED() or FAILED() --*/ { // DebugPrint(( TEXT("Trace: CFaxComponentData::QueryDataObject") )); HRESULT hr = S_OK; if( cookie == NULL ) { hr = globalRoot->ScopeQueryDataObject( this, cookie, type, ppDataObject ); } else { try { hr = ((CInternalNode *)cookie)->ScopeQueryDataObject( this, cookie, type, ppDataObject ); } catch ( ... ) { DebugPrint(( TEXT("Invalid Cookie: 0x%08x"), cookie )); assert( FALSE ); // got passed an INVALID COOKIE!?!?!?!? hr = E_UNEXPECTED; } } return hr; } HRESULT STDMETHODCALLTYPE CFaxComponentData::GetDisplayInfo( IN OUT SCOPEDATAITEM __RPC_FAR *pScopeDataItem) /*++ Routine Description: This method dispatches DisplayInfo requests to the appropriate nodes using the cookie in pScopeDataItem. Arguments: pScopeDataItem - struct containing information about the scope item. Return Value: HRESULT indicating SUCCEEDED() or FAILED() --*/ { // DebugPrint(( TEXT("Trace: CFaxComponentData::GetDisplayInfo") )); LONG_PTR cookie; HRESULT hr = S_OK; assert(pScopeDataItem != NULL); if( pScopeDataItem == NULL ) { return E_POINTER; } cookie = pScopeDataItem->lParam; if( cookie == NULL ) { // our top node hr = globalRoot->ScopeGetDisplayInfo( this, pScopeDataItem); } else { // another node try { hr = ((CInternalNode *)cookie)->ScopeGetDisplayInfo( this, pScopeDataItem); } catch ( ... ) { DebugPrint(( TEXT("Invalid Cookie: 0x%08x"), cookie )); assert( FALSE ); // got passed an INVALID COOKIE!?!?!?!? hr = E_UNEXPECTED; } } return hr; } ///////////////////////////////////////////////////////////////////////////// // CompareObjects // // Compares two objects. HRESULT STDMETHODCALLTYPE CFaxComponentData::CompareObjects( IN LPDATAOBJECT lpDataObjectA, IN LPDATAOBJECT lpDataObjectB) /*++ Routine Description: This method compares two data object to see if they correspond to the same object by comparing the cookies. Arguments: lpDataObjectA - object A lpDataObjectB - object B Return Value: HRESULT indicating S_OK or S_FALSE. E_UNEXPECTED for an error. --*/ { DebugPrint(( TEXT("Trace: CFaxComponentData::CompareObjects") )); CFaxDataObject * aOBJ = ExtractOwnDataObject( lpDataObjectA ); CFaxDataObject * bOBJ = ExtractOwnDataObject( lpDataObjectB ); if( aOBJ == NULL || bOBJ == NULL ) { return E_UNEXPECTED; } if( aOBJ->GetCookie() == bOBJ->GetCookie() ) { return S_OK; } else { return S_FALSE; } } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // // // Internal Methods // // HRESULT CFaxComponentData::InsertIconsIntoImageList( IN LPIMAGELIST pImageList ) /*++ Routine Description: Takes an image list and inserts the standard set of icons into it Add any new node images you want here and also don't forget to assign them new ids. Arguments: pImageList - the image list into which icons are to be inserted. Return Value: HRESULT indicating SUCCEEDED() or FAILED() --*/ { HICON hIcon = NULL; HRESULT hr = S_OK; WORD resID = IDI_NODEICON; do { // set generic node icon // the defined values are stored in resource.h hr = InsertSingleIconIntoImageList( IDI_NODEICON, IDI_NODEICON, pImageList ); if( FAILED( hr ) ) { break; } // set more icons here // // for( resID = IDI_COVERPG; resID < LAST_ICON; resID++ ) { hr = InsertSingleIconIntoImageList( resID, resID, pImageList ); if( FAILED( hr ) ) { break; } } if( FAILED( hr ) ) { break; } } while( 0 ); return hr; } HRESULT CFaxComponentData::InsertSingleIconIntoImageList( IN WORD resID, IN long assignedIndex, IN LPIMAGELIST pImageList ) /*++ Routine Description: Takes an image list and inserts a single icon into it using the resource ID and index specified. Arguments: resID - the resource ID assignedIndex - the index assigned to the icon pImageList - the image list into which icons are to be inserted. Return Value: HRESULT indicating SUCCEEDED() or FAILED() --*/ { HICON hIcon = NULL; HRESULT hr = S_OK; do { hIcon = LoadIcon( ::GlobalStringTable->GetInstance(), MAKEINTRESOURCE( resID ) ); assert( hIcon != NULL ); if( hIcon == NULL ) { hr = E_UNEXPECTED; break; } hr = pImageList->ImageListSetIcon( (LONG_PTR *)hIcon, assignedIndex ); assert( SUCCEEDED( hr ) ); if( FAILED( hr ) ) { break; } } while( 0 ); return hr; } BOOL CFaxComponentData::QueryRpcError() /*++ Routine Description: Queries the state of the RPC connection. The critical section is probably needed because this function can be called from the property sheets which run in a different thread. Arguments: None. Return Value: BOOL indicating TRUE if the RPC connection has encountered an error. --*/ { BOOL temp; EnterCriticalSection(&GlobalCriticalSection); temp = m_bRpcErrorHasHappened; // other stuff might go in here someday LeaveCriticalSection(&GlobalCriticalSection); return temp; } void CFaxComponentData::NotifyRpcError( IN BOOL bRpcErrorHasHappened ) /*++ Routine Description: Informs all the members of the snapin that the RPC connection is dead and the server state is indeterminate The critical section is probably needed because this function can be called from the property sheets which run in a different thread. Arguments: BOOL indicating TRUE if the RPC connection has encountered an error. Return Value: None. --*/ { EnterCriticalSection(&GlobalCriticalSection); // handle server down events here // other stuff might go in here someday m_bRpcErrorHasHappened = bRpcErrorHasHappened; LeaveCriticalSection(&GlobalCriticalSection); }