/*++ Copyright (c) 1997 Microsoft Corporation Module Name: iroot.cpp Abstract: Internal implementation for the root subfolder. Environment: WIN32 User Mode Author: Darwin Ouyang (t-darouy) 30-Sept-1997 --*/ #include "StdAfx.h" #include "inode.h" // base class #include "iroot.h" // root folder #include "idevices.h" // devices folder #include "ilogging.h" // logging folder #include "faxsnapin.h" // snapin #include "faxdataobj.h" // dataobject #include "faxhelper.h" // ole helper functions #include "faxstrt.h" // string table #include "faxsecinfo.h" // fax security info #include "dgenprop.h" // general property sheet #include "droutpri.h" // routing priority property sheet #include // acl editor property sheet #pragma hdrstop // context menu command #define RECONNECT_SERVER 101 extern CStringTable * GlobalStringTable; // Generated with uuidgen. Each node must have a GUID associated with it. // This one is for the main root node. const GUID GUID_RootNode = /* 8f39b047-3071-11d1-9067-00a0c90ab504 */ { 0x8f39b047, 0x3071, 0x11d1, {0x90, 0x67, 0x00, 0xa0, 0xc9, 0x0a, 0xb5, 0x04} }; //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // // // Constructor and destructor // // CInternalRoot::CInternalRoot( IN CInternalNode * pParent, IN CFaxComponentData * pCompData ) : CInternalNode( this, pCompData ) /*++ Routine Description: Constructor Arguments: pParent - pointer to parent node, in this case unused pCompData - pointer to IComponentData implementation for snapin global data Return Value: None. --*/ { iDevices = NULL; iLogging = NULL; targetFaxServName = NULL; m_pCompData->m_FaxHandle = NULL; localNodeName = NULL; pMyPropSheet = NULL; pMyPropSheet2 = NULL; m_myPropPage = NULL; } CInternalRoot::~CInternalRoot() /*++ Routine Description: Destructor Arguments: None. Return Value: None. --*/ { if(iDevices != NULL ) { delete iDevices; } if(iLogging != NULL ) { delete iLogging; } if(m_pCompData->m_FaxHandle != NULL ) { FaxClose( m_pCompData->m_FaxHandle ); // close the connection m_pCompData->m_FaxHandle = NULL; } if(targetFaxServName != NULL ) { delete targetFaxServName; } } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // // // Mandatory CInternalNode implementations. // // const GUID * CInternalRoot::GetNodeGUID() /*++ Routine Description: Returns the node's associated GUID. Arguments: None. Return Value: A const pointer to a binary GUID. --*/ { // DebugPrint(( TEXT("Trace: CInternalRoot::GetNodeGUID") )); return &GUID_RootNode; } const LPTSTR CInternalRoot::GetNodeDisplayName() /*++ Routine Description: Returns a const TSTR pointer to the node's display name. Arguments: None. Return Value: A const pointer to a TSTR. --*/ { // DebugPrint(( TEXT("Trace: CInternalRoot::GetNodeDisplayName") )); if( localNodeName == NULL ) { if( targetFaxServName != NULL ) { // remote machine localNodeName = new TCHAR[ StringSize( (::GlobalStringTable->GetString(IDS_ROOTNODENAME)) ) + StringSize( targetFaxServName ) + 1 ]; assert( localNodeName != NULL ); if (!localNodeName) { return NULL; } _tcscpy( localNodeName, ::GlobalStringTable->GetString(IDS_ROOTNODENAME) ); _tcscat( localNodeName, targetFaxServName ); } else { // local machine localNodeName = new TCHAR[ StringSize( (::GlobalStringTable->GetString(IDS_ROOTNODENAME)) ) + StringSize( ::GlobalStringTable->GetString(IDS_LOCALMACHINE) ) + 1 ]; assert( localNodeName != NULL ); if (!localNodeName) { return NULL; } _tcscpy( localNodeName, ::GlobalStringTable->GetString(IDS_ROOTNODENAME) ); _tcscat( localNodeName, ::GlobalStringTable->GetString(IDS_LOCALMACHINE) ); } } return localNodeName; } const LONG_PTR CInternalRoot::GetCookie() /*++ Routine Description: Returns the cookie for this node. Arguments: None. Return Value: A const long containing the cookie for the pointer, in this case, a NULL, since the root node has no cookie. --*/ { DebugPrint(( TEXT("Root Node Cookie: NULL") )); return NULL; // root node has no cookie. } void CInternalRoot::SetMachine( IN LPTSTR theName ) /*++ Routine Description: Sets the machine name for the root node. This is used by all other nodes to determine the target machine name. Arguments: A LPTSTR pointing to the machine name. It will be string copied to an internal store. Return Value: None. --*/ { if(theName != NULL ) { targetFaxServName = new TCHAR[ MAX_COMPUTERNAME_LENGTH + 1 ]; if (!targetFaxServName) { return; } ZeroMemory( (PVOID) targetFaxServName, (MAX_COMPUTERNAME_LENGTH + 1) * sizeof( TCHAR ) ); _tcsncpy( targetFaxServName, theName, MAX_COMPUTERNAME_LENGTH ); targetFaxServName[MAX_COMPUTERNAME_LENGTH] = 0; } else { targetFaxServName = NULL; } } const LPTSTR CInternalRoot::GetMachine() /*++ Routine Description: Returns the machine name for the root node. This is used by all other nodes to determine the target machine name. Arguments: None. Return Value: A const LPTSTR pointing to the machine name. Do not free this string, it is an internal buffer. --*/ { return targetFaxServName; } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // // // Internal Event Handlers // // HRESULT CInternalRoot::ScopeOnExpand( IN CFaxComponentData * pCompData, IN CFaxDataObject * pdo, IN LPARAM arg, IN LPARAM param ) /*++ Routine Description: Event handler for the MMCN_EXPAND message for the root node. Arguments: pCompData - a pointer to the instance of IComponentData which this root node is associated with. pdo - a pointer to the data object associated with this node arg, param - the arguements of the message Return Value: HRESULT which indicates SUCCEEDED() or FAILED() --*/ { DebugPrint(( TEXT("Trace: CInternalRoot::ScopeOnExpand") )); INT iResult; HRESULT hr = S_OK; LPCONSOLE console = pCompData->m_pConsole; HANDLE targetFaxServHandle = NULL; DWORD descCount = 0; assert(console != NULL); // make sure we QI'ed for the interface if(arg == TRUE) { // folder needs to be expanded DebugPrint(( TEXT("Trace: CInternalRoot::ScopeOnExpand - Expand folder") )); if(!pdo) { hr = console->MessageBox(::GlobalStringTable->GetString( IDS_CORRUPT_DATAOBJECT ), ::GlobalStringTable->GetString( IDS_ERR_TITLE ), MB_OK, &iResult); hr = E_INVALIDARG; return hr; } // Make sure that what we are placing ourselves under is the root node! if(pdo->GetCookie() != NULL) return S_FALSE; assert(pdo->GetContext() == CCT_SCOPE); // // Open the fax server connection. // try { if( FaxConnectFaxServer( targetFaxServName, &targetFaxServHandle ) == FALSE ) { m_pCompData->NotifyRpcError( TRUE ); hr = console->MessageBox(::GlobalStringTable->GetString( IDS_FAX_CONNECT_SERVER_FAIL ), ::GlobalStringTable->GetString( IDS_ERR_TITLE ), MB_OK, &iResult); DebugPrint(( TEXT("Trace: CInternalRoot::ScopeOnExpand - open connection fail") )); hr = E_UNEXPECTED; } else { // sucessful connect! m_pCompData->NotifyRpcError( FALSE ); } } catch( ... ) { m_pCompData->NotifyRpcError( TRUE ); console->MessageBox(::GlobalStringTable->GetString( IDS_FAX_CONNECT_SERVER_FAIL ), ::GlobalStringTable->GetString( IDS_ERR_TITLE ), MB_OK, &iResult); hr = E_UNEXPECTED; DebugPrint(( TEXT("Trace: CInternalRoot::ScopeOnExpand - open connection fail") )); } // // short circuit if we failed to connect to faxsvc // if (FAILED(hr)) { return(hr); } m_pCompData->m_FaxHandle = targetFaxServHandle; // // Place our folder into the scope pane // // create a new internal representation of the devices folder. iDevices = new CInternalDevices( this, m_pCompData ); assert( iDevices != NULL ); if (!iDevices) { return(E_OUTOFMEMORY); } // insert devices folder hr = InsertItem( iDevices, param ); // create a new internal representation of the logging folder. iLogging = new CInternalLogging( this, m_pCompData ); assert( iLogging != NULL ); if (!iLogging) { return(E_OUTOFMEMORY); } // insert logging folder hr = InsertItem( iLogging, param ); } else if(arg == FALSE ) { DebugPrint(( TEXT("Trace: CInternalRoot::ScopeOnExpand - Contract folder") )); } return hr; } HRESULT CInternalRoot::ResultOnShow( IN CFaxComponent* pComp, IN CFaxDataObject * lpDataObject, IN LPARAM arg, IN LPARAM param) /*++ Routine Description: Event handler for the MMCN_SHOW message for the root node. Arguments: pCompData - a pointer to the instance of IComponentData which this root node is associated with. lpDataObject - a pointer to the data object containing context information for this node. pdo - a pointer to the data object associated with this node arg, param - the arguements of the message Return Value: HRESULT which indicates SUCCEEDED() or FAILED() --*/ { LPHEADERCTRL pIHeaderCtrl = pComp->m_pHeaderCtrl; HRESULT hr = S_OK; DebugPrint(( TEXT("Trace: CInternalRoot::ResultOnShow") )); assert( pIHeaderCtrl != NULL ); if( arg == TRUE ) { do { // insert the icons into the image list hr = pComp->InsertIconsIntoImageList(); assert( SUCCEEDED( hr ) ); if( FAILED( hr ) ) { break; } hr = pIHeaderCtrl->InsertColumn( 0, ::GlobalStringTable->GetString( IDS_ROOT_NAME ), LVCFMT_LEFT, MMCLV_AUTO ); if( FAILED( hr ) ) { break; } hr = pIHeaderCtrl->InsertColumn( 1, ::GlobalStringTable->GetString( IDS_ROOT_DESC ), LVCFMT_LEFT, MMCLV_AUTO ); if( FAILED( hr ) ) { break; } } while( 0 ); } return hr; } HRESULT CInternalRoot::ResultOnSelect( IN CFaxComponent* pComp, IN CFaxDataObject * lpDataObject, IN LPARAM arg, IN LPARAM param) /*++ Routine Description: Event handler for the MMCN_SELECT message for the root node. Arguments: pCompData - a pointer to the instance of IComponentData which this root node is associated with. pdo - a pointer to the data object associated with this node arg, param - the arguements of the message Return Value: HRESULT which indicates SUCCEEDED() or FAILED() --*/ { DebugPrint(( TEXT("Trace: CInternalRoot::ResultOnSelect") )); if( m_pCompData->QueryRpcError() == FALSE ) { pComp->m_pConsoleVerb->SetVerbState( MMC_VERB_PROPERTIES, ENABLED, TRUE ); pComp->m_pConsoleVerb->SetDefaultVerb( MMC_VERB_OPEN ); } else { pComp->m_pConsoleVerb->SetVerbState( MMC_VERB_PROPERTIES, ENABLED, FALSE ); pComp->m_pConsoleVerb->SetDefaultVerb( MMC_VERB_NONE ); } return S_OK; } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // // // IExtendPropertySheet implementation // // HRESULT STDMETHODCALLTYPE CInternalRoot::ComponentDataPropertySheetCreatePropertyPages( IN CFaxComponentData * pCompData, IN LPPROPERTYSHEETCALLBACK lpProvider, IN LONG_PTR handle, IN CFaxDataObject * lpIDataObject) /*++ Routine Description: Event handler for the MMCN_EXPAND message for the root node. Arguments: pCompData - a pointer to the instance of IComponentData which this root node is associated with. pdo - a pointer to the data object associated with this node arg, param - the arguements of the message Return Value: HRESULT which indicates SUCCEEDED() or FAILED() --*/ { DebugPrint(( TEXT("Trace: CInternalDevice::ComponentPropertySheetCreatePropertyPages") )); assert( lpIDataObject != NULL ); assert( lpProvider != NULL ); HRESULT hr; BOOL bResult = FALSE; PFAX_SECURITY_DESCRIPTOR pSecurityDescriptor = NULL; CFaxSecurityInformation * psi = NULL; DWORD descCount = 0; PFAX_GLOBAL_ROUTING_INFO pRoutingMethod; DWORD iRoutingMethodCount; DWORD i; WCHAR DllName[MAX_PATH]; BOOL bUnknownMethod = FALSE; if( m_pCompData->QueryRpcError() == TRUE ) { assert( FALSE ); return E_UNEXPECTED; } if( lpIDataObject == NULL || lpProvider == NULL ) { assert(FALSE); return E_POINTER; } pMyPropSheet = new CFaxGeneralSettingsPropSheet( ::GlobalStringTable->GetInstance(), handle, this ); if (!pMyPropSheet) { hr = E_OUTOFMEMORY; goto e0; } hr = lpProvider->AddPage( pMyPropSheet->GetHandle() ); if (FAILED(hr)) { goto e1; } try { // // do routing priority page // // // Check if we have non "default" extensions // if( !FaxEnumGlobalRoutingInfo( m_pCompData->m_FaxHandle, &pRoutingMethod, &iRoutingMethodCount ) ) { if (GetLastError() != ERROR_ACCESS_DENIED) { m_pCompData->NotifyRpcError( TRUE ); assert(FALSE); } ::GlobalStringTable->SystemErrorMsg( GetLastError() ); hr = E_UNEXPECTED; goto e1; } else { // go through the routing methods ensuring that // we know of all of them DWORD retval; retval = ExpandEnvironmentStrings(MSFAX_EXTENSION,DllName,MAX_PATH); if (retval == 0 || retval > MAX_PATH) { hr = E_OUTOFMEMORY; goto e1; } for( i=0; iGetInstance(), handle, this, NULL ); if (!pMyPropSheet2) { hr = E_OUTOFMEMORY; goto e1; } hr = lpProvider->AddPage( pMyPropSheet2->GetHandle() ); if (FAILED(hr)) { goto e2; } } } if( FaxGetSecurityDescriptorCount( m_pCompData->m_FaxHandle, &descCount ) ) { // if there is only one descriptor we might as well just stick it in // the root node if( descCount == 1 ) { psi = new CComObject; if (!psi) { hr = E_OUTOFMEMORY; goto e2; } psi->SetOwner( this ); if( SUCCEEDED( psi->SetSecurityDescriptor( 0 ) ) ) { m_myPropPage = CreateSecurityPage( psi ); hr = lpProvider->AddPage( m_myPropPage ); } else { goto e3; } FaxFreeBuffer( (PVOID)pSecurityDescriptor ); } } } catch ( ... ) { assert( FALSE ); DebugPrint(( TEXT("Trace: CInternalRoot::ComponentDataPropertySheetCreatePropertyPages - RPC connection fail") )); m_pCompData->NotifyRpcError( TRUE ); hr = E_UNEXPECTED; } return hr; e3: if (psi) delete(psi); e2: if (pMyPropSheet2) delete(pMyPropSheet2); e1: if (pMyPropSheet) delete(pMyPropSheet); e0: return(hr); } HRESULT STDMETHODCALLTYPE CInternalRoot::ComponentDataPropertySheetQueryPagesFor( IN CFaxComponentData * pCompData, IN CFaxDataObject * lpDataObject) /*++ Routine Description: Returns S_OK to indicated there are property pages for this node. Arguments: pCompData - a pointer to the instance of IComponentData which this root node is associated with. lpDataObject - a pointer to the data object associated with this node Return Value: HRESULT which indicates SUCCEEDED() or FAILED() --*/ { DebugPrint(( TEXT("Trace: CInternalDevice::ComponentPropertySheetQueryPagesFor") )); return S_OK; } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // // IExtendContextMenu implementation // // HRESULT STDMETHODCALLTYPE CInternalRoot::ComponentDataContextMenuAddMenuItems( IN CFaxComponentData * pCompData, IN CFaxDataObject * piDataObject, IN LPCONTEXTMENUCALLBACK piCallback, IN OUT long __RPC_FAR *pInsertionAllowed) /*++ Routine Description: Adds the context menu items to the root node. Arguments: pCompData - a pointer to the instance of IComponentData which this root node is associated with. piDataObject - a pointer to the data object associated with this node piCallback - a pointer the the IContextMenuCallback supplied by the MMC pInsertionAllowed - a set of flags to indicate whether context menu insertion is allows Return Value: HRESULT which indicates SUCCEEDED() or FAILED() --*/ { DebugPrint(( TEXT("Trace: CInternalDevice::ComponentContextMenuAddMenuItems") )); CONTEXTMENUITEM menuItem; HRESULT hr = S_OK; if( !( *pInsertionAllowed | CCM_INSERTIONALLOWED_TOP ) ) { assert( FALSE ); return E_UNEXPECTED; } if( m_pCompData->QueryRpcError() == TRUE ) { // build the submenu items ZeroMemory( ( void* )&menuItem, sizeof( menuItem ) ); menuItem.strName = ::GlobalStringTable->GetString( IDS_RECONNECT ); menuItem.strStatusBarText = ::GlobalStringTable->GetString( IDS_RECONNECT_DESC ); menuItem.lCommandID = RECONNECT_SERVER; menuItem.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TOP; menuItem.fFlags = MF_ENABLED; menuItem.fSpecialFlags = CCM_SPECIAL_DEFAULT_ITEM; hr = piCallback->AddItem( &menuItem ); if( FAILED(hr) ) { assert(FALSE); return hr; } } return hr; } HRESULT STDMETHODCALLTYPE CInternalRoot::ComponentDataContextMenuCommand( IN CFaxComponentData * pCompData, IN long lCommandID, IN CFaxDataObject * piDataObject) /*++ Routine Description: Handles the context menu events. Arguments: pCompData - a pointer to the instance of IComponentData which this root node is associated with. lCommandID - the command ID. piDataObject - a pointer to the data object associated with this node Return Value: HRESULT which indicates SUCCEEDED() or FAILED() --*/ { DebugPrint(( TEXT("Trace: CInternalRoot::ComponentDataContextMenuCommand") )); HRESULT hr = S_OK; HANDLE targetFaxServHandle = NULL; int iResult; do { switch( lCommandID ) { case RECONNECT_SERVER: // // Re-open the fax server connection. // try { if( FaxConnectFaxServer( targetFaxServName, &targetFaxServHandle ) == FALSE ) { m_pCompData->NotifyRpcError( TRUE ); hr = m_pCompData->m_pConsole->MessageBox(::GlobalStringTable->GetString( IDS_FAX_CONNECT_SERVER_FAIL ), ::GlobalStringTable->GetString( IDS_ERR_TITLE ), MB_OK, &iResult); DebugPrint(( TEXT("Trace: CInternalRoot::ComponentDataContextMenuCommand - RE-OPEN connection fail") )); } else { // sucessful connect! m_pCompData->NotifyRpcError( FALSE ); } } catch( ... ) { m_pCompData->NotifyRpcError( TRUE ); m_pCompData->m_pConsole->MessageBox(::GlobalStringTable->GetString( IDS_FAX_CONNECT_SERVER_FAIL ), ::GlobalStringTable->GetString( IDS_ERR_TITLE ), MB_OK, &iResult); DebugPrint(( TEXT("Trace: CInternalRoot::ComponentDataContextMenuCommand - RE-OPEN connection fail") )); hr = E_UNEXPECTED; break; } m_pCompData->m_FaxHandle = targetFaxServHandle; break; default: assert(FALSE); hr = E_UNEXPECTED; break; } } while( 0 ); return hr; } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // // // Utility Function // // HRESULT CInternalRoot::InsertItem( IN CInternalNode * iCookie, IN LPARAM param ) /*++ Routine Description: Wrapper that inserts an item into a scope view pane given a cookie. Arguments: iCookie - the cookie of the node that needs to be inserted into the view param - the HRESULTITEM of the parent to the node being inserted Return Value: HRESULT which indicates SUCCEEDED() or FAILED() --*/ { SCOPEDATAITEM sdi; LPCONSOLENAMESPACE consoleNameSpace = m_pCompData->m_pConsoleNameSpace; assert(consoleNameSpace != NULL); // make sure we QI'ed for the interface ZeroMemory(&sdi, sizeof sdi); sdi.mask = SDI_STR | // displayname is valid SDI_PARAM | // lParam is valid SDI_IMAGE | // nImage is valid SDI_OPENIMAGE | // nOpenImage is valid SDI_CHILDREN | // cChildren is valid SDI_PARENT; sdi.relativeID = (HSCOPEITEM) param; sdi.nImage = iCookie->GetNodeDisplayImage(); sdi.nOpenImage = iCookie->GetNodeDisplayOpenImage(); sdi.displayname = MMC_CALLBACK; sdi.cChildren = 0; sdi.lParam = (LPARAM) iCookie; // The cookie return consoleNameSpace->InsertItem(&sdi); }