|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: compbas_.cpp
//
//--------------------------------------------------------------------------
// initialize to the thread ID of the thread that loads the snapin
// that is the main thread
extern DWORD _MainThreadId = ::GetCurrentThreadId();
const TCHAR NODE_TYPES_KEY[] = TEXT("Software\\Microsoft\\MMC\\NodeTypes"); const TCHAR SNAPINS_KEY[] = TEXT("Software\\Microsoft\\MMC\\SnapIns"); const TCHAR g_szNodeType[] = TEXT("NodeType"); const TCHAR g_szNameString[] = TEXT("NameString"); const TCHAR g_szNameStringIndirect[] = TEXT("NameStringIndirect"); const TCHAR g_szStandaloneSnap[] = TEXT("Standalone"); const TCHAR g_szExtensionSnap[] = TEXT("Extension"); const TCHAR g_szNodeTypes[] = TEXT("NodeTypes"); const TCHAR g_szExtensions[] = TEXT("Extensions"); const TCHAR g_szDynamicExtensions[] = TEXT("Dynamic Extensions"); const TCHAR g_szVersion[] = TEXT("Version"); const TCHAR g_szProvider[] = _T("Provider"); const TCHAR g_szAbout[] = _T("About");
HRESULT RegisterSnapin(const GUID* pSnapinCLSID, const GUID* pStaticNodeGUID, const GUID* pAboutGUID, LPCTSTR lpszNameString, LPCTSTR lpszVersion, LPCTSTR lpszProvider, BOOL bExtension, _NODE_TYPE_INFO_ENTRY* pNodeTypeInfoEntryArray, UINT nSnapinNameID) { OLECHAR szSnapinClassID[128] = {0}, szStaticNodeGuid[128] = {0}, szAboutGuid[128] = {0}; ::StringFromGUID2(*pSnapinCLSID,szSnapinClassID,128); ::StringFromGUID2(*pStaticNodeGUID,szStaticNodeGuid,128); ::StringFromGUID2(*pAboutGUID,szAboutGuid,128);
CRegKey regkeySnapins; LONG lRes = regkeySnapins.Open(HKEY_LOCAL_MACHINE, SNAPINS_KEY); ASSERT(lRes == ERROR_SUCCESS); if (lRes != ERROR_SUCCESS) return HRESULT_FROM_WIN32(lRes); // failed to open
CRegKey regkeyThisSnapin; lRes = regkeyThisSnapin.Create(regkeySnapins, szSnapinClassID); ASSERT(lRes == ERROR_SUCCESS); if (lRes != ERROR_SUCCESS) return HRESULT_FROM_WIN32(lRes); // failed to create
lRes = regkeyThisSnapin.SetValue(lpszNameString, g_szNameString); if (lRes != ERROR_SUCCESS) return HRESULT_FROM_WIN32(lRes);
// JeffJon 6/12/00 100624: MUI: MMC: Shared Folders snap-in
// stores its display information in the registry
if (nSnapinNameID != 0) { CString str; WCHAR szModule[_MAX_PATH]; ::GetModuleFileName(AfxGetInstanceHandle(), szModule, _MAX_PATH); str.Format( _T("@%s,-%d"), szModule, nSnapinNameID ); lRes = regkeyThisSnapin.SetValue(str, g_szNameStringIndirect); if (lRes != ERROR_SUCCESS) return HRESULT_FROM_WIN32(lRes); }
lRes = regkeyThisSnapin.SetValue(szAboutGuid, g_szAbout); if (lRes != ERROR_SUCCESS) return HRESULT_FROM_WIN32(lRes); lRes = regkeyThisSnapin.SetValue(szStaticNodeGuid, g_szNodeType); if (lRes != ERROR_SUCCESS) return HRESULT_FROM_WIN32(lRes); lRes = regkeyThisSnapin.SetValue(lpszProvider, g_szProvider); if (lRes != ERROR_SUCCESS) return HRESULT_FROM_WIN32(lRes); lRes = regkeyThisSnapin.SetValue(lpszVersion, g_szVersion); if (lRes != ERROR_SUCCESS) return HRESULT_FROM_WIN32(lRes);
CRegKey regKeyStandaloneorExtension; lRes = regKeyStandaloneorExtension.Create(regkeyThisSnapin, bExtension ? g_szExtensionSnap : g_szStandaloneSnap); if (lRes != ERROR_SUCCESS) return HRESULT_FROM_WIN32(lRes);
CRegKey regKeyNodeTypes; lRes = regKeyNodeTypes.Create(regkeyThisSnapin, g_szNodeTypes); if (lRes != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(lRes); }
OLECHAR szNodeGUID[128]; for (_NODE_TYPE_INFO_ENTRY* pCurrEntry = pNodeTypeInfoEntryArray; pCurrEntry->m_pNodeGUID != NULL; pCurrEntry++) { ::StringFromGUID2(*(pCurrEntry->m_pNodeGUID),szNodeGUID,128); CRegKey regKeyNode; lRes = regKeyNode.Create(regKeyNodeTypes, szNodeGUID); if (lRes != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(lRes); } }
return HRESULT_FROM_WIN32(lRes); }
HRESULT UnregisterSnapin(const GUID* pSnapinCLSID) { OLECHAR szSnapinClassID[128]; ::StringFromGUID2(*pSnapinCLSID,szSnapinClassID,128);
CRegKey regkeySnapins; LONG lRes = regkeySnapins.Open(HKEY_LOCAL_MACHINE, SNAPINS_KEY); ASSERT(lRes == ERROR_SUCCESS); if (lRes != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(lRes); // failed to open
} lRes = regkeySnapins.RecurseDeleteKey(szSnapinClassID); ASSERT(lRes == ERROR_SUCCESS); return HRESULT_FROM_WIN32(lRes); }
HRESULT RegisterNodeType(const GUID* pGuid, LPCTSTR lpszNodeDescription) { OLECHAR szNodeGuid[128]; ::StringFromGUID2(*pGuid,szNodeGuid,128);
CRegKey regkeyNodeTypes; LONG lRes = regkeyNodeTypes.Open(HKEY_LOCAL_MACHINE, NODE_TYPES_KEY); ASSERT(lRes == ERROR_SUCCESS); if (lRes != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(lRes); // failed to open
}
CRegKey regkeyThisNodeType; lRes = regkeyThisNodeType.Create(regkeyNodeTypes, szNodeGuid); ASSERT(lRes == ERROR_SUCCESS); if (lRes != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(lRes); // failed to create
}
lRes = regkeyThisNodeType.SetValue(lpszNodeDescription); ASSERT(lRes == ERROR_SUCCESS); return HRESULT_FROM_WIN32(lRes); }
HRESULT UnregisterNodeType(const GUID* pGuid) { OLECHAR szNodeGuid[128]; ::StringFromGUID2(*pGuid,szNodeGuid,128);
CRegKey regkeyNodeTypes; LONG lRes = regkeyNodeTypes.Open(HKEY_LOCAL_MACHINE, NODE_TYPES_KEY); ASSERT(lRes == ERROR_SUCCESS); if (lRes != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(lRes); // failed to open
}
lRes = regkeyNodeTypes.RecurseDeleteKey(szNodeGuid); ASSERT(lRes == ERROR_SUCCESS); return HRESULT_FROM_WIN32(lRes); }
HRESULT RegisterNodeExtension(const GUID* pNodeGuid, LPCTSTR lpszExtensionType, const GUID* pExtensionSnapinCLSID, LPCTSTR lpszDescription, BOOL bDynamic) { OLECHAR szNodeGuid[128], szExtensionSnapinCLSID[128]; ::StringFromGUID2(*pNodeGuid, szNodeGuid,128); ::StringFromGUID2(*pExtensionSnapinCLSID, szExtensionSnapinCLSID,128);
// compose full path of key up to the node GUID
WCHAR szKeyPath[2048]; wsprintf(szKeyPath, L"%s\\%s", NODE_TYPES_KEY, szNodeGuid); CRegKey regkeyNodeTypesNode; LONG lRes = regkeyNodeTypesNode.Open(HKEY_LOCAL_MACHINE, szKeyPath); ASSERT(lRes == ERROR_SUCCESS); if (lRes != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(lRes); // failed to open
}
CRegKey regkeyExtensions; lRes = regkeyExtensions.Create(regkeyNodeTypesNode, g_szExtensions); ASSERT(lRes == ERROR_SUCCESS); if (lRes != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(lRes); // failed to create
}
CRegKey regkeyExtensionType; lRes = regkeyExtensionType.Create(regkeyExtensions, lpszExtensionType); ASSERT(lRes == ERROR_SUCCESS); if (lRes != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(lRes); // failed to create
}
lRes = regkeyExtensionType.SetValue(lpszDescription, szExtensionSnapinCLSID); ASSERT(lRes == ERROR_SUCCESS); if (lRes != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(lRes); // failed to set value
}
if (bDynamic) { // create a subkey under the node GUID
CRegKey regkeyDynamicExtensions; lRes = regkeyDynamicExtensions.Create(regkeyNodeTypesNode, g_szDynamicExtensions); ASSERT(lRes == ERROR_SUCCESS); if (lRes != ERROR_SUCCESS) return HRESULT_FROM_WIN32(lRes); // failed to create
// set value (same value as the extension type above)
lRes = regkeyDynamicExtensions.SetValue(lpszDescription, szExtensionSnapinCLSID); ASSERT(lRes == ERROR_SUCCESS); if (lRes != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(lRes); // failed to set value
} } return HRESULT_FROM_WIN32(lRes); }
HRESULT UnregisterNodeExtension(const GUID* pNodeGuid, LPCTSTR lpszExtensionType, const GUID* pExtensionSnapinCLSID, BOOL bDynamic) { OLECHAR szNodeGuid[128], szExtensionSnapinCLSID[128]; ::StringFromGUID2(*pNodeGuid, szNodeGuid,128); ::StringFromGUID2(*pExtensionSnapinCLSID, szExtensionSnapinCLSID,128);
// compose full path of key up to the node GUID
WCHAR szKeyPath[2048]; wsprintf(szKeyPath, L"%s\\%s", NODE_TYPES_KEY, szNodeGuid); CRegKey regkeyNodeTypesNode; LONG lRes = regkeyNodeTypesNode.Open(HKEY_LOCAL_MACHINE, szKeyPath); ASSERT(lRes == ERROR_SUCCESS); if (lRes != ERROR_SUCCESS) return HRESULT_FROM_WIN32(lRes); // failed to open
lRes = ERROR_SUCCESS;
// open the key for the Dynamic extensions
if (bDynamic) { CRegKey regkeyDynamicExtensions; lRes = regkeyDynamicExtensions.Open(regkeyNodeTypesNode, g_szDynamicExtensions); if (lRes == ERROR_SUCCESS) { lRes = regkeyDynamicExtensions.DeleteValue(szExtensionSnapinCLSID); } } else { //
// Open the extensions key
//
CRegKey regkeyExtensions; lRes = regkeyExtensions.Open(regkeyNodeTypesNode, g_szExtensions); if (lRes == ERROR_SUCCESS) { CRegKey regkeyExtensionType; lRes = regkeyExtensionType.Open(regkeyExtensions, lpszExtensionType); if (lRes == ERROR_SUCCESS) { lRes = regkeyExtensionType.DeleteValue(szExtensionSnapinCLSID); } } } lRes = ERROR_SUCCESS; return HRESULT_FROM_WIN32(lRes); }
/////////////////////////////////////////////////////////////////////////////
// CTimerThread
BOOL CTimerThread::Start(HWND hWnd) { ASSERT(m_hWnd == NULL); ASSERT(::IsWindow(hWnd)); m_hWnd = hWnd; return CreateThread(); }
BOOL CTimerThread::PostMessageToWnd(WPARAM wParam, LPARAM lParam) { ASSERT(::IsWindow(m_hWnd)); return ::PostMessage(m_hWnd, CHiddenWnd::s_TimerThreadMessage, wParam, lParam); }
/////////////////////////////////////////////////////////////////////////////
// CWorkerThread
CWorkerThread::CWorkerThread() { m_bAutoDelete = FALSE; m_bAbandoned = FALSE; m_hEventHandle = NULL; ExceptionPropagatingInitializeCriticalSection(&m_cs); m_hWnd = NULL; }
CWorkerThread::~CWorkerThread() { ::DeleteCriticalSection(&m_cs); if (m_hEventHandle != NULL) { VERIFY(::CloseHandle(m_hEventHandle)); m_hEventHandle = NULL; } }
BOOL CWorkerThread::Start(HWND hWnd) { ASSERT(m_hWnd == NULL); ASSERT(::IsWindow(hWnd)); m_hWnd = hWnd;
ASSERT(m_hEventHandle == NULL); // cannot call start twice or reuse the same C++ object
m_hEventHandle = ::CreateEvent(NULL,TRUE /*bManualReset*/,FALSE /*signalled*/, NULL); if (m_hEventHandle == NULL) { return FALSE; }
return CreateThread(); }
void CWorkerThread::Abandon() { Lock(); OnAbandon(); m_bAutoDelete = TRUE; m_bAbandoned = TRUE; Unlock(); }
BOOL CWorkerThread::IsAbandoned() { Lock(); BOOL b = m_bAbandoned; Unlock(); return b; }
BOOL CWorkerThread::PostMessageToWnd(UINT Msg, WPARAM wParam, LPARAM lParam) { BOOL b = IsAbandoned(); if (b) { return TRUE; // no need to post
}
ASSERT(::IsWindow(m_hWnd)); return ::PostMessage(m_hWnd, Msg, wParam, lParam); }
void CWorkerThread::WaitForExitAcknowledge() { BOOL b = IsAbandoned(); if (b) { return; }
VERIFY(WAIT_OBJECT_0 == ::WaitForSingleObject(m_hEventHandle,INFINITE)); }
/////////////////////////////////////////////////////////////////////////////
// CHiddenWnd
const UINT CHiddenWnd::s_NodeThreadHaveDataNotificationMessage = WM_USER + 1; const UINT CHiddenWnd::s_NodeThreadErrorNotificationMessage = WM_USER + 2; const UINT CHiddenWnd::s_NodeThreadExitingNotificationMessage = WM_USER + 3;
const UINT CHiddenWnd::s_NodePropertySheetCreateMessage = WM_USER + 4; const UINT CHiddenWnd::s_NodePropertySheetDeleteMessage = WM_USER + 5;
const UINT CHiddenWnd::s_ExecCommandMessage = WM_USER + 6; const UINT CHiddenWnd::s_ForceEnumerationMessage = WM_USER + 7; const UINT CHiddenWnd::s_TimerThreadMessage = WM_USER + 8;
CHiddenWnd::CHiddenWnd(CComponentDataObject* pComponentDataObject) { m_pComponentDataObject = pComponentDataObject; m_nTimerID = 0; }
LRESULT CHiddenWnd::OnNodeThreadHaveDataNotification(UINT, WPARAM wParam, LPARAM, BOOL&) { //TRACE(_T("CHiddenWnd::OnNodeThreadHaveDataNotification()\n"));
ASSERT(m_pComponentDataObject != NULL);
// call into the CTreeNode code
CMTContainerNode* pNode = reinterpret_cast<CMTContainerNode*>(wParam); ASSERT(pNode); ASSERT(pNode->IsContainer()); pNode->OnThreadHaveDataNotification(m_pComponentDataObject); return 1; }
LRESULT CHiddenWnd::OnNodeThreadExitingNotification(UINT, WPARAM wParam, LPARAM lParam, BOOL&) { //TRACE(_T("CHiddenWnd::OnNodeThreadExitingNotification()\n"));
ASSERT(m_pComponentDataObject != NULL);
// call into the CTreeNode code
CMTContainerNode* pNode = reinterpret_cast<CMTContainerNode*>(wParam); ASSERT(pNode); ASSERT(pNode->IsContainer()); pNode->OnThreadExitingNotification(m_pComponentDataObject);
// notify anybody interested in this event
m_pComponentDataObject->GetNotificationSinkTable()->Notify( CHiddenWnd::s_NodeThreadExitingNotificationMessage ,wParam,lParam); return 1; }
LRESULT CHiddenWnd::OnNodeThreadErrorNotification(UINT, WPARAM wParam, LPARAM lParam, BOOL&) { ASSERT(m_pComponentDataObject != NULL);
// call into the CTreeNode code
CMTContainerNode* pNode = reinterpret_cast<CMTContainerNode*>(wParam); DWORD dwErr = static_cast<DWORD>(lParam); ASSERT(pNode); ASSERT(pNode->IsContainer()); pNode->OnThreadErrorNotification(dwErr, m_pComponentDataObject); return 1; }
LRESULT CHiddenWnd::OnNodePropertySheetCreate(UINT, WPARAM wParam, LPARAM lParam, BOOL&) { //TRACE(_T("CHiddenWnd::OnNodePropertySheetCreate()\n"));
ASSERT(m_pComponentDataObject != NULL);
CPropertyPageHolderBase* pPPHolder = reinterpret_cast<CPropertyPageHolderBase*>(wParam); ASSERT(pPPHolder != NULL); HWND hWnd = reinterpret_cast<HWND>(lParam); ASSERT(::IsWindow(hWnd));
m_pComponentDataObject->GetPropertyPageHolderTable()->AddWindow(pPPHolder, hWnd);
return 1; }
LRESULT CHiddenWnd::OnNodePropertySheetDelete(UINT, WPARAM wParam, LPARAM lParam, BOOL&) { //TRACE(_T("CHiddenWnd::OnNodePropertySheetDestroy()\n"));
ASSERT(m_pComponentDataObject != NULL);
CPropertyPageHolderBase* pPPHolder = reinterpret_cast<CPropertyPageHolderBase*>(wParam); ASSERT(pPPHolder != NULL); CTreeNode* pNode = reinterpret_cast<CTreeNode*>(lParam); ASSERT(pNode != NULL);
m_pComponentDataObject->GetPropertyPageHolderTable()->Remove(pPPHolder); pNode->OnDeleteSheet();
return 1; }
LRESULT CHiddenWnd::OnExecCommand(UINT, WPARAM wParam, LPARAM lParam, BOOL&) { //TRACE(_T("CHiddenWnd::OnExecCommand()\n"));
ASSERT(m_pComponentDataObject != NULL);
CExecContext* pExec = reinterpret_cast<CExecContext*>(wParam); ASSERT(pExec != NULL);
pExec->Execute((long)lParam); // execute code
TRACE(_T("CHiddenWnd::BeforeDone()\n")); pExec->Done(); // let the secondary thread proceed
return 1; }
LRESULT CHiddenWnd::OnForceEnumeration(UINT, WPARAM wParam, LPARAM, BOOL&) { TRACE(_T("CHiddenWnd::OnForceEnumeration()\n")); ASSERT(m_pComponentDataObject != NULL); // call into the CTreeNode code
CMTContainerNode* pNode = reinterpret_cast<CMTContainerNode*>(wParam); ASSERT(pNode); ASSERT(pNode->GetContainer() != NULL); // not the root!!!
ASSERT(pNode->IsContainer()); pNode->ForceEnumeration(m_pComponentDataObject); return 1; }
LRESULT CHiddenWnd::OnTimerThread(UINT, WPARAM wParam, LPARAM lParam, BOOL&) { //TRACE(_T("CHiddenWnd::OnTimerThread()\n"));
ASSERT(m_pComponentDataObject != NULL);
// NULL arguments means that the thread acknowledge it is running properly
// only to be called once
if ((wParam == 0) && (lParam == 0)) { ASSERT(!m_pComponentDataObject->m_bTimerThreadStarted); m_pComponentDataObject->m_bTimerThreadStarted = TRUE; } else { // got some object specific message
m_pComponentDataObject->OnTimerThread(wParam, lParam); } return 1; }
LRESULT CHiddenWnd::OnTimer(UINT, WPARAM, LPARAM, BOOL&) { ASSERT(m_pComponentDataObject != NULL); m_pComponentDataObject->OnTimer(); return 1; }
////////////////////////////////////////////////////////////////////////////////////
// CRunningThreadTable
#define RUNNING_THREAD_ARRAY_DEF_SIZE (4)
CRunningThreadTable::CRunningThreadTable(CComponentDataObject* pComponentData) { m_pComponentData = pComponentData; m_pEntries = (CMTContainerNode**)malloc(sizeof(CMTContainerNode*) * RUNNING_THREAD_ARRAY_DEF_SIZE);
if (m_pEntries != NULL) { memset(m_pEntries,NULL, sizeof(CMTContainerNode*) * RUNNING_THREAD_ARRAY_DEF_SIZE); } m_nSize = RUNNING_THREAD_ARRAY_DEF_SIZE; }
CRunningThreadTable::~CRunningThreadTable() { #ifdef _DEBUG
for (int k=0; k < m_nSize; k++) { ASSERT(m_pEntries[k] == NULL); } #endif
free(m_pEntries); }
void CRunningThreadTable::Add(CMTContainerNode* pNode) { ASSERT(pNode != NULL); for (int k=0; k < m_nSize; k++) { if (m_pEntries[k] == NULL) // get the first empty spot
{ pNode->IncrementThreadLockCount(); m_pEntries[k] = pNode; return; } }
// all full, need to grow the array
int nAlloc = m_nSize*2; m_pEntries = (CMTContainerNode**)realloc(m_pEntries, sizeof(CMTContainerNode*)*nAlloc); memset(&m_pEntries[m_nSize], NULL, sizeof(CMTContainerNode*)*m_nSize); pNode->IncrementThreadLockCount(); m_pEntries[m_nSize] = pNode; m_nSize = nAlloc; }
BOOL CRunningThreadTable::IsPresent(CMTContainerNode* pNode) { ASSERT(pNode != NULL); for (int k=0; k < m_nSize; k++) { if (m_pEntries[k] == pNode) { return TRUE; } } return FALSE; }
void CRunningThreadTable::Remove(CMTContainerNode* pNode) { ASSERT(pNode != NULL); for (int k=0; k < m_nSize; k++) { if (m_pEntries[k] == pNode) { m_pEntries[k] = NULL; pNode->DecrementThreadLockCount(); return; // assume no more that one holder entry
} } }
void CRunningThreadTable::RemoveAll() { for (int k=0; k < m_nSize; k++) { if (m_pEntries[k] != NULL) { m_pEntries[k]->AbandonThread(m_pComponentData); m_pEntries[k] = NULL; } } }
////////////////////////////////////////////////////////////////////////////////////
// CExecContext
CExecContext::CExecContext() { m_hEventHandle = ::CreateEvent(NULL,TRUE /*bManualReset*/,FALSE /*signalled*/, NULL); ASSERT(m_hEventHandle != NULL); }
CExecContext::~CExecContext() { ASSERT(m_hEventHandle != NULL); VERIFY(::CloseHandle(m_hEventHandle)); }
void CExecContext::Done() { VERIFY(0 != ::SetEvent(m_hEventHandle)); }
void CExecContext::Wait() { ASSERT(m_hEventHandle != NULL); VERIFY(WAIT_OBJECT_0 == ::WaitForSingleObject(m_hEventHandle,INFINITE)); } ////////////////////////////////////////////////////////////////////////////////////
// CNotificationSinkEvent
CNotificationSinkEvent::CNotificationSinkEvent() { m_hEventHandle = ::CreateEvent(NULL,TRUE /*bManualReset*/,FALSE /*signalled*/, NULL); ASSERT(m_hEventHandle != NULL); }
CNotificationSinkEvent::~CNotificationSinkEvent() { ASSERT(m_hEventHandle != NULL); VERIFY(::CloseHandle(m_hEventHandle)); }
void CNotificationSinkEvent::OnNotify(DWORD, WPARAM, LPARAM) { TRACE(_T("CNotificationSinkEvent::OnNotify()\n")); VERIFY(0 != ::SetEvent(m_hEventHandle)); }
void CNotificationSinkEvent::Wait() { TRACE(_T("CNotificationSinkEvent::Wait()\n")); ASSERT(m_hEventHandle != NULL); VERIFY(WAIT_OBJECT_0 == ::WaitForSingleObject(m_hEventHandle,INFINITE)); }
////////////////////////////////////////////////////////////////////////////////////
// CNotificationSinkTable
#define NOTIFICATION_SINK_ARRAY_DEF_SIZE (4)
CNotificationSinkTable::CNotificationSinkTable() { ExceptionPropagatingInitializeCriticalSection(&m_cs); m_pEntries = (CNotificationSinkBase**)malloc(sizeof(CNotificationSinkBase*) * NOTIFICATION_SINK_ARRAY_DEF_SIZE);
if (m_pEntries != NULL) { memset(m_pEntries,NULL, sizeof(CNotificationSinkBase*) * NOTIFICATION_SINK_ARRAY_DEF_SIZE); } m_nSize = NOTIFICATION_SINK_ARRAY_DEF_SIZE;
}
CNotificationSinkTable::~CNotificationSinkTable() { free(m_pEntries); ::DeleteCriticalSection(&m_cs); } void CNotificationSinkTable::Advise(CNotificationSinkBase* p) { Lock(); ASSERT(p != NULL); for (int k=0; k < m_nSize; k++) { if (m_pEntries[k] == NULL) // get the first empty spot
{ m_pEntries[k] = p; Unlock(); return; } } // all full, need to grow the array
int nAlloc = m_nSize*2; m_pEntries = (CNotificationSinkBase**)realloc(m_pEntries, sizeof(CNotificationSinkBase*)*nAlloc); memset(&m_pEntries[m_nSize], NULL, sizeof(CNotificationSinkBase*)*m_nSize); m_pEntries[m_nSize] = p; m_nSize = nAlloc; Unlock(); }
void CNotificationSinkTable::Unadvise(CNotificationSinkBase* p) { Lock(); ASSERT(p != NULL); for (int k=0; k < m_nSize; k++) { if (m_pEntries[k] == p) { m_pEntries[k] = NULL; Unlock(); return; // assume no more that one holder entry
} } Unlock(); }
void CNotificationSinkTable::Notify(DWORD dwEvent, WPARAM dwArg1, LPARAM dwArg2) { Lock(); for (int k=0; k < m_nSize; k++) { if (m_pEntries[k] != NULL) { m_pEntries[k]->OnNotify(dwEvent, dwArg1, dwArg2); } } Unlock(); }
///////////////////////////////////////////////////////////////////////////////
// CWatermarkInfoState (private class)
class CWatermarkInfoState { public: CWatermarkInfoState() { m_pWatermarkInfo = NULL; m_hBanner = m_hWatermark = NULL; }
~CWatermarkInfoState() { DeleteBitmaps(); if (m_pWatermarkInfo != NULL) { delete m_pWatermarkInfo; } } void DeleteBitmaps() { if (m_hBanner != NULL) { ::DeleteObject(m_hBanner); m_hBanner = NULL; } if (m_hWatermark != NULL) { ::DeleteObject(m_hWatermark); m_hWatermark = NULL; } } void LoadBitmaps() { ASSERT(m_pWatermarkInfo != NULL); if (m_hBanner == NULL) { m_hBanner = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(m_pWatermarkInfo->m_nIDBanner)); } if (m_hWatermark == NULL) { m_hWatermark = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(m_pWatermarkInfo->m_nIDWatermark)); } }
CWatermarkInfo* m_pWatermarkInfo; HBITMAP m_hBanner; HBITMAP m_hWatermark; };
///////////////////////////////////////////////////////////////////////////////
// CComponentDataObject implementation: helpers
#ifdef _DEBUG_REFCOUNT
unsigned int CComponentDataObject::m_nOustandingObjects = 0; #endif // _DEBUG_REFCOUNT
CComponentDataObject::CComponentDataObject() : m_hiddenWnd((CComponentDataObject*)this), // initialize backpointer
m_pTimerThreadObj(NULL), m_PPHTable(this), m_RTTable(this), m_pConsole(NULL), m_pConsoleNameSpace(NULL), m_pRootData(NULL), m_hWnd(NULL), m_nTimerThreadID(0x0), m_bTimerThreadStarted(FALSE), m_dwTimerInterval(1), m_dwTimerTime(0), m_pWatermarkInfoState(NULL), m_bExtensionSnapin(FALSE) { ExceptionPropagatingInitializeCriticalSection(&m_cs); #ifdef _DEBUG_REFCOUNT
dbg_cRef = 0; ++m_nOustandingObjects; TRACE(_T("CComponentDataObject(), count = %d\n"),m_nOustandingObjects); #endif // _DEBUG_REFCOUNT
}
CComponentDataObject::~CComponentDataObject() { ::DeleteCriticalSection(&m_cs); #ifdef _DEBUG_REFCOUNT
--m_nOustandingObjects; TRACE(_T("~CComponentDataObject(), count = %d\n"),m_nOustandingObjects); #endif // _DEBUG_REFCOUNT
ASSERT(m_pConsole == NULL); ASSERT(m_pConsoleNameSpace == NULL); ASSERT(m_pRootData == NULL); }
HRESULT CComponentDataObject::FinalConstruct() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (!m_hiddenWnd.Create()) { TRACE(_T("Failed to create hidden window\n")); return E_FAIL; }
m_hWnd = m_hiddenWnd.m_hWnd; m_pRootData = OnCreateRootData(); ASSERT(m_pRootData != NULL);
return S_OK; }
void CComponentDataObject::FinalRelease() { if (m_hiddenWnd.m_hWnd != NULL) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); VERIFY(m_hiddenWnd.DestroyWindow()); } // delete data
if(m_pRootData != NULL) { delete m_pRootData; m_pRootData = NULL; }
if (m_pWatermarkInfoState != NULL) { delete m_pWatermarkInfoState; }
m_ColList.RemoveAndDeleteAllColumnSets();
if (log_instance != NULL) { log_instance->KillInstance(); } }
///////////////////////////////////////////////////////////////////////////////
// CComponentDataObject::IComponentData members
STDMETHODIMP CComponentDataObject::Initialize(LPUNKNOWN pUnknown) { ASSERT(m_pRootData != NULL); ASSERT(pUnknown != NULL); HRESULT hr = E_FAIL; AFX_MANAGE_STATE(AfxGetStaticModuleState());
// MMC should only call ::Initialize once!
ASSERT(m_pConsole == NULL); ASSERT(m_pConsoleNameSpace == NULL);
// get the pointers we need to hold on to
hr = pUnknown->QueryInterface(IID_IConsoleNameSpace2, reinterpret_cast<void**>(&m_pConsoleNameSpace)); ASSERT(hr == S_OK); ASSERT(m_pConsoleNameSpace != NULL); hr = pUnknown->QueryInterface(IID_IConsole2, reinterpret_cast<void**>(&m_pConsole)); ASSERT(hr == S_OK); ASSERT(m_pConsole != NULL);
// add the images for the scope tree
LPIMAGELIST lpScopeImage;
hr = m_pConsole->QueryScopeImageList(&lpScopeImage); ASSERT(hr == S_OK);
// Set the images
hr = OnSetImages(lpScopeImage); // Load the bitmaps from the dll
ASSERT(hr == S_OK);
lpScopeImage->Release();
OnInitialize();
return S_OK; }
STDMETHODIMP CComponentDataObject::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param) { ASSERT(m_pConsoleNameSpace != NULL); HRESULT hr = S_OK;
// Since it's my folder it has an internal format.
// Design Note: for extension. I can use the fact, that the data object doesn't have
// my internal format and I should look at the node type and see how to extend it.
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (event == MMCN_PROPERTY_CHANGE) { ASSERT(lpDataObject == NULL); hr = OnPropertyChange(param, static_cast<long>(arg)); } else { CInternalFormatCracker ifc; ifc.Extract(lpDataObject);
if (ifc.GetCookieCount() == 0) { if ((event == MMCN_EXPAND) && (arg == TRUE) && IsExtensionSnapin()) { return OnExtensionExpand(lpDataObject, param); // this is a namespace extension, need to add
// the root of the snapin
CContainerNode* pContNode = GetRootData(); HSCOPEITEM pParent = param; pContNode->SetScopeID(pParent); pContNode->MarkExpanded(); return AddContainerNode(pContNode, pParent);
} else if ((event == MMCN_REMOVE_CHILDREN) && IsExtensionSnapin()) { hr = OnRemoveChildren(lpDataObject, arg); }
return S_OK; // Extensions not supported
}
switch(event) { case MMCN_PASTE: break;
case MMCN_DELETE: hr = OnDeleteVerbHandler(ifc, NULL); break;
case MMCN_REFRESH: hr = OnRefreshVerbHandler(ifc); break;
case MMCN_RENAME: hr = OnRename(ifc, arg, param); break;
case MMCN_EXPAND: hr = OnExpand(ifc, arg, param); break;
case MMCN_EXPANDSYNC: hr = OnExpand(ifc, arg, param, FALSE); break;
case MMCN_BTN_CLICK: break;
case MMCN_SELECT: hr = OnSelect(ifc, arg, param); break;
default: break; } // switch
} // if
return hr; }
STDMETHODIMP CComponentDataObject::Destroy() { InternalAddRef(); TRACE(_T("CComponentDataObject::Destroy()\n")); OnDestroy(); SAFE_RELEASE(m_pConsoleNameSpace); SAFE_RELEASE(m_pConsole); AFX_MANAGE_STATE(AfxGetStaticModuleState()); VERIFY(m_hiddenWnd.DestroyWindow()); InternalRelease(); return S_OK; }
BOOL CComponentDataObject::PostExecMessage(CExecContext* pExec, LPARAM arg) { ASSERT(pExec != NULL); ASSERT(::IsWindow(m_hWnd)); return ::PostMessage(m_hWnd, CHiddenWnd::s_ExecCommandMessage, (WPARAM)pExec, (LPARAM)arg); }
BOOL CComponentDataObject::PostForceEnumeration(CMTContainerNode* pContainerNode) { ASSERT(::IsWindow(m_hWnd)); return ::PostMessage(m_hWnd, CHiddenWnd::s_ForceEnumerationMessage, (WPARAM)pContainerNode, (LPARAM)0); }
BOOL CComponentDataObject::OnCreateSheet(CPropertyPageHolderBase* pPPHolder, HWND hWnd) { ASSERT(pPPHolder != NULL); ASSERT(::IsWindow(hWnd)); ASSERT(::IsWindow(m_hWnd)); TRACE(_T("\nCComponentDataObject::OnCreateSheet()\n")); return ::PostMessage(m_hWnd, CHiddenWnd::s_NodePropertySheetCreateMessage, (WPARAM)pPPHolder, (LPARAM)hWnd); }
BOOL CComponentDataObject::OnDeleteSheet(CPropertyPageHolderBase* pPPHolder, CTreeNode* pNode) { ASSERT(pPPHolder != NULL); ASSERT(pNode != NULL); ASSERT(::IsWindow(m_hWnd)); TRACE(_T("\nCComponentDataObject::OnDeleteSheet()\n")); return ::PostMessage(m_hWnd, CHiddenWnd::s_NodePropertySheetDeleteMessage, (WPARAM)pPPHolder, (LPARAM)pNode); }
void CComponentDataObject::OnInitialize() { VERIFY(StartTimerThread()); }
void CComponentDataObject::OnDestroy() { // stop timer and worker thread
ShutDownTimerThread(); // detach all the threads that might be still running
GetRunningThreadTable()->RemoveAll(); // tell all the open property sheets to shut down
// shut down property sheets, if any
GetPropertyPageHolderTable()->WaitForAllToShutDown(); }
STDMETHODIMP CComponentDataObject::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject) { ASSERT(ppDataObject != NULL);
CComObject<CDataObject>* pObject;
CComObject<CDataObject>::CreateInstance(&pObject); ASSERT(pObject != NULL);
// Save cookie and type for delayed rendering
pObject->SetType(type);
CTreeNode* pNode;
//
// -1 is an uninitialized data object, just ignore
//
if (cookie != -1) { if (cookie == NULL) { pNode = GetRootData(); } else { pNode = reinterpret_cast<CTreeNode*>(cookie); } ASSERT(pNode != NULL); pObject->AddCookie(pNode); }
// save a pointer to "this"
IUnknown* pUnkComponentData = GetUnknown(); // no addref
ASSERT(pUnkComponentData != NULL);
pObject->SetComponentData(pUnkComponentData); // will addref it
return pObject->QueryInterface(IID_IDataObject, reinterpret_cast<void**>(ppDataObject)); }
STDMETHODIMP CComponentDataObject::GetDisplayInfo(SCOPEDATAITEM* pScopeDataItem) { ASSERT(pScopeDataItem != NULL); CTreeNode* pNode = reinterpret_cast<CTreeNode*>(pScopeDataItem->lParam); ASSERT(pNode != NULL); ASSERT(pNode->IsContainer());
ASSERT(pScopeDataItem->mask & SDI_STR); pScopeDataItem->displayname = const_cast<LPWSTR>(pNode->GetDisplayName());
ASSERT(pScopeDataItem->displayname != NULL); return S_OK; }
STDMETHODIMP CComponentDataObject::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB) { ASSERT(lpDataObjectA != NULL); ASSERT(lpDataObjectB != NULL);
CInternalFormatCracker ifcA, ifcB; VERIFY(SUCCEEDED(ifcA.Extract(lpDataObjectA))); VERIFY(SUCCEEDED(ifcB.Extract(lpDataObjectB)));
CTreeNode* pNodeA = ifcA.GetCookieAt(0); CTreeNode* pNodeB = ifcB.GetCookieAt(0);
ASSERT(pNodeA != NULL); ASSERT(pNodeB != NULL);
if ( (pNodeA == NULL) || (pNodeB == NULL) ) { return E_FAIL; }
return (pNodeA == pNodeB) ? S_OK : S_FALSE; }
///////////////////////////////////////////////////////////////////////////////
// Message handlers for CComponentDataObject::IComponentData::Notify()
HRESULT CComponentDataObject::OnAdd(CTreeNode*, LPARAM, LPARAM) { return E_UNEXPECTED; }
HRESULT CComponentDataObject::OnRemoveChildren(LPDATAOBJECT lpDataObject, LPARAM) { CInternalFormatCracker ifc; HRESULT hr = S_OK; hr = ifc.Extract(lpDataObject); if (SUCCEEDED(hr)) { if (ifc.GetCookieCount() == 1) { CTreeNode* pNode = ifc.GetCookieAt(0); if (pNode != NULL) { if (pNode->IsContainer()) { CContainerNode* pContainerNode = dynamic_cast<CContainerNode*>(pNode); if (pContainerNode != NULL) { pContainerNode->RemoveAllChildrenFromList(); } } } } else { ASSERT(FALSE); } } return hr; }
HRESULT CComponentDataObject::OnRename(CInternalFormatCracker& ifc, LPARAM, LPARAM param) { HRESULT hr = S_FALSE;
CTreeNode* pNode = ifc.GetCookieAt(0); ASSERT(pNode != NULL); hr = pNode->OnRename(this, (LPOLESTR)param); if (hr == S_OK) { UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNode), CHANGE_RESULT_ITEM); } return hr; }
HRESULT CComponentDataObject::OnExpand(CInternalFormatCracker& ifc, LPARAM arg, LPARAM param, BOOL bAsync) { if (arg == TRUE) { // Did Initialize get called?
ASSERT(m_pConsoleNameSpace != NULL);
//
// I shouldn't have to deal with multiple select here...
//
ASSERT(ifc.GetCookieCount() == 1); CTreeNode* pNode = ifc.GetCookieAt(0); if (pNode == NULL) { ASSERT(pNode != NULL); return S_FALSE; }
EnumerateScopePane(pNode, param, bAsync); } else if (!bAsync) { ASSERT(m_pConsoleNameSpace != NULL);
//
// I shouldn't have to deal with multiple select here...
//
ASSERT(ifc.GetCookieCount() == 1); CTreeNode* pNode = ifc.GetCookieAt(0); ASSERT(pNode != NULL);
if (pNode && pNode->CanExpandSync()) { MMC_EXPANDSYNC_STRUCT* pExpandStruct = reinterpret_cast<MMC_EXPANDSYNC_STRUCT*>(param); if (pExpandStruct && pExpandStruct->bExpanding) { EnumerateScopePane(pNode, pExpandStruct->hItem, bAsync); pExpandStruct->bHandled = TRUE; } } else { return S_FALSE; } }
return S_OK; }
HRESULT CComponentDataObject::OnSelect(CInternalFormatCracker&, LPARAM, LPARAM) { return E_UNEXPECTED; }
HRESULT CComponentDataObject::OnContextMenu(CTreeNode*, LPARAM, LPARAM) { return S_OK; }
HRESULT CComponentDataObject::OnPropertyChange(LPARAM param, long fScopePane) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); TRACE(_T("CComponentDataObject::OnPropertyChange()\n")); ASSERT(param != NULL); CPropertyPageHolderBase* pPPHolder = reinterpret_cast<CPropertyPageHolderBase*>(param); ASSERT(pPPHolder != NULL); CTreeNode* pNode = pPPHolder->GetTreeNode(); ASSERT(pNode != NULL);
// allow both types in the result pane, but only scope items in the scope pane
ASSERT(!fScopePane || (fScopePane && pNode->IsContainer()) );
long changeMask = CHANGE_RESULT_ITEM; // default, the holder can change it
BOOL bUpdate = pPPHolder->OnPropertyChange(fScopePane, &changeMask); // fire event to let the property page thread proceed
pPPHolder->AcknowledgeNotify();
if (bUpdate) { pNode->OnPropertyChange(this, fScopePane, changeMask); } return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// CComponentDataObject::IExtendPropertySheet2 memebers
STDMETHODIMP CComponentDataObject::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider, LONG_PTR handle, LPDATAOBJECT lpIDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
CInternalFormatCracker ifc; HRESULT hr = ifc.Extract(lpIDataObject); if (FAILED(hr)) { return hr; } //
// this was an object created by the modal wizard, do nothing
//
if (ifc.GetCookieType() == CCT_UNINITIALIZED) { return hr; }
if (ifc.GetCookieType() == CCT_SNAPIN_MANAGER) { return SnapinManagerCreatePropertyPages(lpProvider,handle); }
CTreeNode* pNode = ifc.GetCookieAt(0); ASSERT(ifc.GetCookieType() == CCT_SCOPE || ifc.GetCookieType() == CCT_RESULT);
CNodeList nodeList; ifc.GetCookieList(nodeList);
if (nodeList.GetCount() > 1) // multiple selection
{ //
// Delegate to the container
//
ASSERT(pNode->GetContainer() != NULL); hr = pNode->GetContainer()->CreatePropertyPages(lpProvider, handle, &nodeList); } else if (nodeList.GetCount() == 1) // single selection
{ //
// Delegate to the node
//
ASSERT(pNode != NULL); hr = pNode->CreatePropertyPages(lpProvider, handle, &nodeList); } else { hr = E_FAIL; } return hr; }
STDMETHODIMP CComponentDataObject::QueryPagesFor(LPDATAOBJECT lpDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CTreeNode* pNode; DATA_OBJECT_TYPES type;
CInternalFormatCracker ifc; HRESULT hr = ifc.Extract(lpDataObject); if (FAILED(hr)) { return hr; }
type = ifc.GetCookieType(); pNode = ifc.GetCookieAt(0);
//
// Retrieve node list and count
//
CNodeList nodeList; ifc.GetCookieList(nodeList);
//
// this was an object created by the modal wizard, do nothing
//
if (type == CCT_UNINITIALIZED) { return hr; }
if (type == CCT_SNAPIN_MANAGER) { return HasPropertyPages(type) ? S_OK : S_FALSE; }
//
// we have a node, so delegate to it
//
ASSERT(pNode != NULL); BOOL bDummy;
if (nodeList.GetCount() == 1) // single selection
{ ASSERT((type == CCT_SCOPE) || (type == CCT_RESULT)); if (pNode->GetSheetCount() > 0) { pNode->ShowPageForNode(this); return S_FALSE; } else if (pNode->DelegatesPPToContainer() && pNode->GetContainer()->GetSheetCount() > 0) { //
// Find the page and bring it to foreground
//
pNode->ShowPageForNode(this); return S_FALSE; } if (pNode->HasPropertyPages(type, &bDummy, &nodeList)) { hr = S_OK; } else { hr = S_FALSE; } } else if (nodeList.GetCount() > 1) // multiple selection
{ ASSERT(pNode->GetContainer() != NULL); if (pNode->GetContainer()->HasPropertyPages(type, &bDummy, &nodeList)) { hr = S_OK; } else { hr = S_FALSE; } } return hr; }
HRESULT CComponentDataObject::CreatePropertySheet(CTreeNode* pNode, HWND hWndParent, LPCWSTR lpszTitle) { HRESULT hr = S_OK; HWND hWnd = hWndParent; if (hWnd == NULL) { hr = m_pConsole->GetMainWindow(&hWnd); if (FAILED(hr)) { ASSERT(FALSE); return hr; } }
//
// get an interface to a sheet provider
//
CComPtr<IPropertySheetProvider> spSheetProvider; hr = m_pConsole->QueryInterface(IID_IPropertySheetProvider,(void**)&spSheetProvider); ASSERT(SUCCEEDED(hr)); ASSERT(spSheetProvider != NULL);
//
// get an interface to a sheet callback
//
CComPtr<IPropertySheetCallback> spSheetCallback; hr = m_pConsole->QueryInterface(IID_IPropertySheetCallback,(void**)&spSheetCallback); ASSERT(SUCCEEDED(hr)); ASSERT(spSheetCallback != NULL);
//
// get a sheet
//
MMC_COOKIE cookie = reinterpret_cast<MMC_COOKIE>(pNode); DATA_OBJECT_TYPES type = (pNode->IsContainer()) ? CCT_SCOPE : CCT_RESULT;
CComPtr<IDataObject> spDataObject; hr = QueryDataObject(cookie, type, &spDataObject); ASSERT(SUCCEEDED(hr)); ASSERT(spDataObject != NULL);
hr = spSheetProvider->CreatePropertySheet(lpszTitle, TRUE, cookie, spDataObject, 0x0 /*dwOptions*/); ASSERT(SUCCEEDED(hr));
hr = spSheetProvider->AddPrimaryPages(GetUnknown(), TRUE /*bCreateHandle*/, hWnd, pNode->IsContainer() /* bScopePane*/);
hr = spSheetProvider->AddExtensionPages();
ASSERT(SUCCEEDED(hr));
hr = spSheetProvider->Show(reinterpret_cast<LONG_PTR>(hWnd), 0); ASSERT(SUCCEEDED(hr));
return hr; }
CWatermarkInfo* CComponentDataObject::SetWatermarkInfo(CWatermarkInfo* pWatermarkInfo) { if (m_pWatermarkInfoState == NULL) { m_pWatermarkInfoState = new CWatermarkInfoState; }
CWatermarkInfo* pOldWatermarkInfo = m_pWatermarkInfoState->m_pWatermarkInfo; m_pWatermarkInfoState->m_pWatermarkInfo = pWatermarkInfo;
// we changed info, so dump the old bitmap handles
m_pWatermarkInfoState->DeleteBitmaps();
return pOldWatermarkInfo; }
STDMETHODIMP CComponentDataObject::GetWatermarks(LPDATAOBJECT, HBITMAP* lphWatermark, HBITMAP* lphHeader, HPALETTE* lphPalette, BOOL* pbStretch) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
*lphHeader = NULL; *lphWatermark = NULL; *lphPalette = NULL; *pbStretch = TRUE;
if ((m_pWatermarkInfoState == NULL) || (m_pWatermarkInfoState->m_pWatermarkInfo == NULL)) { return E_FAIL; }
*pbStretch = m_pWatermarkInfoState->m_pWatermarkInfo->m_bStretch; *lphPalette = m_pWatermarkInfoState->m_pWatermarkInfo->m_hPalette;
// load bitmaps if not loaded yet
m_pWatermarkInfoState->LoadBitmaps();
*lphHeader = m_pWatermarkInfoState->m_hBanner; if (*lphHeader == NULL) { return E_FAIL; }
*lphWatermark = m_pWatermarkInfoState->m_hWatermark; if (*lphWatermark == NULL) { return E_FAIL; }
return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// CComponentDataObject::IExtendContextMenu memebers
STDMETHODIMP CComponentDataObject::AddMenuItems(LPDATAOBJECT pDataObject, LPCONTEXTMENUCALLBACK pContextMenuCallback, long *pInsertionAllowed) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr = S_OK; CTreeNode* pNode; DATA_OBJECT_TYPES type;
CInternalFormatCracker ifc; hr = ifc.Extract(pDataObject); if (FAILED(hr)) { return hr; }
type = ifc.GetCookieType();
pNode = ifc.GetCookieAt(0); ASSERT(pNode != NULL); if (pNode == NULL) { return hr; }
CComPtr<IContextMenuCallback2> spContextMenuCallback2; hr = pContextMenuCallback->QueryInterface(IID_IContextMenuCallback2, (PVOID*)&spContextMenuCallback2); if (FAILED(hr)) { return hr; }
CNodeList nodeList; ifc.GetCookieList(nodeList);
if (nodeList.GetCount() > 1) // multiple selection
{ ASSERT(pNode->GetContainer() != NULL); hr = pNode->GetContainer()->OnAddMenuItems(spContextMenuCallback2, type, pInsertionAllowed, &nodeList); } else if (nodeList.GetCount() == 1) // single selection
{ hr = pNode->OnAddMenuItems(spContextMenuCallback2, type, pInsertionAllowed, &nodeList); } else { hr = E_FAIL; } return hr; }
STDMETHODIMP CComponentDataObject::Command(long nCommandID, LPDATAOBJECT pDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
CInternalFormatCracker ifc; HRESULT hr = ifc.Extract(pDataObject); if (FAILED(hr)) { return hr; }
CTreeNode* pNode = ifc.GetCookieAt(0); ASSERT(pNode != NULL); //
// Retrieve node list and count
//
CNodeList nodeList; ifc.GetCookieList(nodeList);
if (nodeList.GetCount() > 1) // multiple selection
{ //
// Delegate the command to the container
//
ASSERT(pNode->GetContainer() != NULL);
hr = pNode->GetContainer()->OnCommand(nCommandID, ifc.GetCookieType(), this, &nodeList); } else if (nodeList.GetCount() == 1) // single selection
{ //
// Let the node take care of it
//
hr = pNode->OnCommand(nCommandID, ifc.GetCookieType(), this, &nodeList); } else { hr = E_FAIL; } return hr; }
/////////////////////////////////////////////////////////////////////////////
// CComponentDataObject::IPersistStream members
STDMETHODIMP CComponentDataObject::IsDirty() { // forward to the root of the tree
CRootData* pRootData = GetRootData(); ASSERT(pRootData != NULL); return pRootData->IsDirty(); }
STDMETHODIMP CComponentDataObject::Load(IStream __RPC_FAR *pStm) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
// forward to the root of the tree
CRootData* pRootData = GetRootData(); ASSERT(pRootData != NULL); return pRootData->Load(pStm); }
STDMETHODIMP CComponentDataObject::Save(IStream __RPC_FAR *pStm, BOOL fClearDirty) { // forward to the root of the tree
CRootData* pRootData = GetRootData(); ASSERT(pRootData != NULL); return pRootData->Save(pStm,fClearDirty); }
/////////////////////////////////////////////////////////////////////////////
// CComponentDataObject::ISnapinHelp2 memebers
STDMETHODIMP CComponentDataObject::GetHelpTopic(LPOLESTR* lpCompiledHelpFile) { if (lpCompiledHelpFile == NULL) { return E_INVALIDARG; }
LPCWSTR lpszHelpFileName = GetHTMLHelpFileName(); if (lpszHelpFileName == NULL) { *lpCompiledHelpFile = NULL; return E_NOTIMPL; }
CString szHelpFilePath; LPTSTR lpszBuffer = szHelpFilePath.GetBuffer(2*MAX_PATH); UINT nLen = ::GetSystemWindowsDirectory(lpszBuffer, 2*MAX_PATH); if (nLen == 0) { return E_FAIL; }
wcscpy(&lpszBuffer[nLen], lpszHelpFileName); szHelpFilePath.ReleaseBuffer();
UINT nBytes = (szHelpFilePath.GetLength()+1) * sizeof(WCHAR); *lpCompiledHelpFile = (LPOLESTR)::CoTaskMemAlloc(nBytes);
if (*lpCompiledHelpFile != NULL) { memcpy(*lpCompiledHelpFile, (LPCWSTR)szHelpFilePath, nBytes); } else { return E_OUTOFMEMORY; }
return S_OK; }
HRESULT CComponentDataObject::GetLinkedTopics(LPOLESTR*) { return S_FALSE; }
///////////////////////////////////////////////////////////////////////////////
// CComponentDataObject Helpers
HRESULT CComponentDataObject::UpdateAllViewsHelper(LPARAM data, LONG_PTR hint) { ASSERT(m_pConsole != NULL);
CComObject<CDummyDataObject>* pObject; CComObject<CDummyDataObject>::CreateInstance(&pObject); ASSERT(pObject != NULL);
IDataObject* pDataObject; HRESULT hr = pObject->QueryInterface(IID_IDataObject, reinterpret_cast<void**>(&pDataObject)); ASSERT(SUCCEEDED(hr)); ASSERT(pDataObject != NULL);
hr = m_pConsole->UpdateAllViews(pDataObject,data, hint); pDataObject->Release(); return hr; }
void CComponentDataObject::HandleStandardVerbsHelper(CComponentObject* pComponentObj, LPCONSOLEVERB pConsoleVerb, BOOL bScope, BOOL bSelect, LPDATAOBJECT lpDataObject) { // You should crack the data object and enable/disable/hide standard
// commands appropriately. The standard commands are reset everytime you get
// called. So you must reset them back.
ASSERT(pConsoleVerb != NULL); ASSERT(pComponentObj != NULL); ASSERT(lpDataObject != NULL);
// reset the selection
pComponentObj->SetSelectedNode(NULL, CCT_UNINITIALIZED);
CInternalFormatCracker ifc; VERIFY(SUCCEEDED(ifc.Extract(lpDataObject)));
CTreeNode* pNode = ifc.GetCookieAt(0); if (pNode == NULL) { return; }
//
// Retrieve node list and count
//
CNodeList nodeList; ifc.GetCookieList(nodeList);
if (nodeList.GetCount() > 1) // multiple selection
{ //
// Delegate to the container
//
ASSERT(pNode->GetContainer() != NULL);
pNode->GetContainer()->OnSetVerbState(pConsoleVerb, ifc.GetCookieType(), &nodeList); } else if (nodeList.GetCount() == 1) // single selection
{ //
// set selection, if any
//
if (bSelect) { pComponentObj->SetSelectedNode(pNode, ifc.GetCookieType()); }
ASSERT((ifc.GetCookieType() == CCT_SCOPE) || (ifc.GetCookieType() == CCT_RESULT)); TRACE(_T("HandleStandardVerbsHelper: Node <%s> bScope = %d bSelect = %d, type = %s\n"), pNode->GetDisplayName(), bScope, bSelect, (ifc.GetCookieType() == CCT_SCOPE) ? _T("CCT_SCOPE") : _T("CCT_RESULT"));
pConsoleVerb->SetDefaultVerb(pNode->GetDefaultVerb(ifc.GetCookieType(), &nodeList)); pNode->OnSetVerbState(pConsoleVerb, ifc.GetCookieType(), &nodeList); } }
void CComponentDataObject::EnumerateScopePane(CTreeNode* cookie, HSCOPEITEM pParent, BOOL bAsync) { ASSERT(m_pConsoleNameSpace != NULL); // make sure we QI'ed for the interface
// find the node corresponding to the cookie
ASSERT(cookie != NULL); ASSERT(cookie->IsContainer()); CContainerNode* pContNode = (CContainerNode*)cookie; pContNode->MarkExpanded();
if (pContNode == GetRootData()) { pContNode->SetScopeID(pParent); }
// allow the node to enumerate its children, if not enumerated yet
if (!pContNode->IsEnumerated()) { BOOL bAddChildrenNow = pContNode->OnEnumerate(this, bAsync); pContNode->MarkEnumerated(); if (!bAddChildrenNow) { return; } }
// scan the list of children, looking for containers and add them
ASSERT(pParent != NULL); CNodeList* pChildList = pContNode->GetContainerChildList(); ASSERT(pChildList != NULL);
POSITION pos; for( pos = pChildList->GetHeadPosition(); pos != NULL; ) { CContainerNode* pCurrChildNode = (CContainerNode*)pChildList->GetNext(pos); ASSERT(pCurrChildNode != NULL); if (pCurrChildNode->IsVisible()) { AddContainerNode(pCurrChildNode, pParent); } } }
HRESULT CComponentDataObject::OnDeleteVerbHandler(CInternalFormatCracker& ifc, CComponentObject*) { HRESULT hr = S_OK; CTreeNode* pNode = ifc.GetCookieAt(0); ASSERT(pNode != NULL);
//
// Retrieve the cookie list and count
//
CNodeList nodeList; ifc.GetCookieList(nodeList);
if (nodeList.GetCount() > 1) // multiple selection
{ ASSERT(pNode->GetContainer() != NULL); pNode->GetContainer()->OnDelete(this, &nodeList); } else if (nodeList.GetCount() == 1) // single selection
{ pNode->OnDelete(this, &nodeList); } else { hr = E_FAIL; } return hr; }
HRESULT CComponentDataObject::OnRefreshVerbHandler(CInternalFormatCracker& ifc) { HRESULT hr = S_OK; CTreeNode* pNode = ifc.GetCookieAt(0); ASSERT(pNode != NULL);
//
// Retrieve the node list and the count
//
CNodeList nodeList; ifc.GetCookieList(nodeList);
if (nodeList.GetCount() > 1) // multiple selection
{ ASSERT(pNode->GetContainer() != NULL);
pNode->GetContainer()->OnRefresh(this, &nodeList); } else if (nodeList.GetCount() == 1) // single selection
{ pNode->OnRefresh(this, &nodeList); } else { hr = E_FAIL; } return hr; }
HRESULT CComponentDataObject::OnHelpHandler(CInternalFormatCracker& ifc, CComponentObject* pComponentObject) { //
// responding to MMCN_CONTEXTHELP
//
ASSERT(pComponentObject != NULL);
HRESULT hr = S_OK; CTreeNode* pNode = ifc.GetCookieAt(0); ASSERT(pNode != NULL);
//
// Retrieve the node list and count
//
CNodeList nodeList; ifc.GetCookieList(nodeList);
if (nodeList.GetCount() > 1) // Multiple selection
{ ASSERT(pNode->GetContainer() != NULL);
OnNodeContextHelp(&nodeList); } else if (nodeList.GetCount() == 1) // Single selection
{ OnNodeContextHelp(&nodeList); } else { hr = E_FAIL; } return hr; }
BOOL CComponentDataObject::WinHelp(LPCTSTR lpszHelpFileName, // file, no path
UINT uCommand, // type of Help
DWORD dwData // additional data
) { HWND hWnd; GetConsole()->GetMainWindow(&hWnd); CString szHelpFilePath; LPTSTR lpszBuffer = szHelpFilePath.GetBuffer(2*MAX_PATH); UINT nLen = ::GetSystemWindowsDirectory(lpszBuffer, 2*MAX_PATH); if (nLen == 0) { return FALSE; }
wcscpy(&lpszBuffer[nLen], lpszHelpFileName); szHelpFilePath.ReleaseBuffer(); return ::WinHelp(hWnd, szHelpFilePath, uCommand, dwData); }
HRESULT CComponentDataObject::AddNode(CTreeNode* pNodeToAdd) { ASSERT(pNodeToAdd != NULL); // if the node is hidden, just ignore
if (!pNodeToAdd->IsVisible()) return S_OK;
if (pNodeToAdd->IsContainer()) { ASSERT(pNodeToAdd->GetContainer() != NULL); HSCOPEITEM pParentScopeItem = pNodeToAdd->GetContainer()->GetScopeID(); ASSERT(pParentScopeItem != NULL); return AddContainerNode((CContainerNode*)pNodeToAdd, pParentScopeItem); } return AddLeafNode((CLeafNode*)pNodeToAdd); }
HRESULT CComponentDataObject::AddNodeSorted(CTreeNode* pNodeToAdd) { ASSERT(pNodeToAdd != NULL); // if the node is hidden, just ignore
if (!pNodeToAdd->IsVisible()) { return S_OK; }
if (pNodeToAdd->IsContainer()) { ASSERT(pNodeToAdd->GetContainer() != NULL); HSCOPEITEM pParentScopeItem = pNodeToAdd->GetContainer()->GetScopeID(); ASSERT(pParentScopeItem != NULL); return AddContainerNodeSorted((CContainerNode*)pNodeToAdd, pParentScopeItem); } return AddLeafNode((CLeafNode*)pNodeToAdd); }
HRESULT CComponentDataObject::DeleteNode(CTreeNode* pNodeToDelete) { if (pNodeToDelete->IsContainer()) { return DeleteContainerNode((CContainerNode*)pNodeToDelete); } return DeleteLeafNode((CLeafNode*)pNodeToDelete); }
HRESULT CComponentDataObject::DeleteMultipleNodes(CNodeList* pNodeList) { HRESULT hr = S_OK;
POSITION pos = pNodeList->GetHeadPosition(); while (pos != NULL) { CTreeNode* pNode = pNodeList->GetNext(pos); if (pNode->IsContainer()) { DeleteContainerNode((CContainerNode*)pNode); } } hr = UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNodeList), DELETE_MULTIPLE_RESULT_ITEMS); return hr; }
HRESULT CComponentDataObject::ChangeNode(CTreeNode* pNodeToChange, long changeMask) { if (!pNodeToChange->IsVisible()) { return S_OK; }
if (pNodeToChange->IsContainer()) { CContainerNode* pContNode = (CContainerNode*)pNodeToChange; //if (!pContNode->IsExpanded())
// return S_OK;
return ChangeContainerNode(pContNode, changeMask); } return ChangeLeafNode((CLeafNode*)pNodeToChange, changeMask); }
HRESULT CComponentDataObject::RemoveAllChildren(CContainerNode* pNode) { // if the node is hidden or not expanded yet, just ignore
if (!pNode->IsVisible() || !pNode->IsExpanded()) { return S_OK; }
ASSERT(pNode != NULL); HSCOPEITEM nID = pNode->GetScopeID(); ASSERT(nID != 0);
// remove the container itself
HRESULT hr = m_pConsoleNameSpace->DeleteItem(nID, /*fDeleteThis*/ FALSE); ASSERT(SUCCEEDED(hr)); DeleteAllResultPaneItems(pNode); // remove the result items from all the views (will do only if container selected)
ASSERT(SUCCEEDED(hr)); return hr; }
HRESULT CComponentDataObject::RepaintSelectedFolderInResultPane() { return UpdateAllViewsHelper((long)NULL, REPAINT_RESULT_PANE); }
HRESULT CComponentDataObject::RepaintResultPane(CContainerNode* pNode) { ASSERT(pNode != NULL); return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNode), REPAINT_RESULT_PANE); }
HRESULT CComponentDataObject::DeleteAllResultPaneItems(CContainerNode* pNode) { ASSERT(pNode != NULL); return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNode), DELETE_ALL_RESULT_ITEMS); }
HRESULT CComponentDataObject::AddContainerNode(CContainerNode* pNodeToInsert, HSCOPEITEM pParentScopeItem) { ASSERT(pNodeToInsert != NULL);
if ((pNodeToInsert != GetRootData()) && (!pNodeToInsert->GetContainer()->IsExpanded())) { return S_OK; }
//ASSERT(pNodeToInsert->GetScopeID() == 0);
SCOPEDATAITEM scopeDataItem; InitializeScopeDataItem(&scopeDataItem, pParentScopeItem, reinterpret_cast<LPARAM>(pNodeToInsert), // lParam, use the node pointer as cookie
pNodeToInsert->GetImageIndex(FALSE), // close image
pNodeToInsert->GetImageIndex(TRUE), // open image
pNodeToInsert->HasChildren());
HRESULT hr = m_pConsoleNameSpace->InsertItem(&scopeDataItem); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) { return hr; }
// Note - On return, the ID member of 'scopeDataItem'
// contains the handle to the newly inserted item, so we have to save
ASSERT(scopeDataItem.ID != NULL); pNodeToInsert->SetScopeID(scopeDataItem.ID); return hr; }
//
// Note : This should combined with the function above adding a third parameter that is a compare function,
// which is NULL by default. If it is NULL then we just skip the GetChildItem() and the while loop.
//
HRESULT CComponentDataObject::AddContainerNodeSorted(CContainerNode* pNodeToInsert, HSCOPEITEM pParentScopeItem) { ASSERT(pNodeToInsert != NULL);
if ((pNodeToInsert != GetRootData()) && (!pNodeToInsert->GetContainer()->IsExpanded())) { return S_OK; }
SCOPEDATAITEM scopeDataItem; InitializeScopeDataItem(&scopeDataItem, pParentScopeItem, reinterpret_cast<LPARAM>(pNodeToInsert), // lParam, use the node pointer as cookie
pNodeToInsert->GetImageIndex(FALSE), // close image
pNodeToInsert->GetImageIndex(TRUE), // open image
pNodeToInsert->HasChildren());
HSCOPEITEM pChildScopeItem; CTreeNode* pChildNode = NULL;
// Enumerate through the scope node items and insert the new node in sorted order
HRESULT hr = m_pConsoleNameSpace->GetChildItem(pParentScopeItem, &pChildScopeItem, (MMC_COOKIE*)&pChildNode); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) { return hr; }
while (pChildNode != NULL) { // REVIEW_JEFFJON : we should probably have a compare function as a parameter and use that here.
if (_wcsicoll(pNodeToInsert->GetDisplayName(), pChildNode->GetDisplayName()) < 0) { // Insert the node before the node pointed to by pChildScopeItem
scopeDataItem.relativeID = pChildScopeItem; scopeDataItem.mask |= SDI_NEXT; break; } pChildNode = NULL; hr = m_pConsoleNameSpace->GetNextItem(pChildScopeItem, &pChildScopeItem, (MMC_COOKIE*)&pChildNode); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) { return hr; } } hr = m_pConsoleNameSpace->InsertItem(&scopeDataItem); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) { return hr; }
// Note - On return, the ID member of 'scopeDataItem'
// contains the handle to the newly inserted item, so we have to save
ASSERT(scopeDataItem.ID != NULL); pNodeToInsert->SetScopeID(scopeDataItem.ID); return hr; }
HRESULT CComponentDataObject::DeleteContainerNode(CContainerNode* pNodeToDelete) { ASSERT(pNodeToDelete != NULL); ASSERT(pNodeToDelete->GetContainer() != NULL); HSCOPEITEM nID = pNodeToDelete->GetScopeID(); ASSERT(nID != 0); HRESULT hr = m_pConsoleNameSpace->DeleteItem(nID, /*fDeleteThis*/ TRUE); pNodeToDelete->SetScopeID(0); return hr; }
HRESULT CComponentDataObject::ChangeContainerNode(CContainerNode* pNodeToChange, long changeMask) { ASSERT(pNodeToChange != NULL); ASSERT(changeMask & CHANGE_RESULT_ITEM); ASSERT(m_pConsoleNameSpace != NULL);
if (!pNodeToChange->AddedToScopePane()) { return S_OK; }
SCOPEDATAITEM scopeDataItem; memset(&scopeDataItem, 0, sizeof(SCOPEDATAITEM)); scopeDataItem.ID = pNodeToChange->GetScopeID(); ASSERT(scopeDataItem.ID != 0);
if (changeMask & CHANGE_RESULT_ITEM_DATA) { scopeDataItem.mask |= SDI_STR; scopeDataItem.displayname = MMC_CALLBACK; } if (changeMask & CHANGE_RESULT_ITEM_ICON) { scopeDataItem.mask |= SDI_IMAGE; scopeDataItem.nImage = pNodeToChange->GetImageIndex(FALSE); scopeDataItem.mask |= SDI_OPENIMAGE; scopeDataItem.nOpenImage = pNodeToChange->GetImageIndex(TRUE); } return m_pConsoleNameSpace->SetItem(&scopeDataItem); }
HRESULT CComponentDataObject::AddLeafNode(CLeafNode* pNodeToAdd) { // will have to broadcast to all views
ASSERT(pNodeToAdd != NULL); return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNodeToAdd), ADD_RESULT_ITEM); }
HRESULT CComponentDataObject::DeleteLeafNode(CLeafNode* pNodeToDelete) { // will have to broadcast to all views
ASSERT(pNodeToDelete != NULL); return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNodeToDelete), DELETE_RESULT_ITEM); }
HRESULT CComponentDataObject::ChangeLeafNode(CLeafNode* pNodeToChange, long changeMask) { // will have to broadcast to all views
ASSERT(pNodeToChange != NULL); return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNodeToChange), changeMask); }
HRESULT CComponentDataObject::UpdateVerbState(CTreeNode* pNodeToChange) { // will have to broadcast to all views
ASSERT(pNodeToChange != NULL); return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pNodeToChange), UPDATE_VERB_STATE); }
HRESULT CComponentDataObject::SetDescriptionBarText(CTreeNode* pTreeNode) { ASSERT(pTreeNode != NULL); return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pTreeNode), UPDATE_DESCRIPTION_BAR); }
HRESULT CComponentDataObject::SortResultPane(CContainerNode* pContainerNode) { ASSERT(pContainerNode != NULL); return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pContainerNode), SORT_RESULT_PANE); }
HRESULT CComponentDataObject::UpdateResultPaneView(CContainerNode* pContainerNode) { ASSERT(pContainerNode != NULL); return UpdateAllViewsHelper(reinterpret_cast<LONG_PTR>(pContainerNode), UPDATE_RESULT_PANE_VIEW); }
void CComponentDataObject::InitializeScopeDataItem(LPSCOPEDATAITEM pScopeDataItem, HSCOPEITEM pParentScopeItem, LPARAM lParam, int nImage, int nOpenImage, BOOL bHasChildren) { ASSERT(pScopeDataItem != NULL); memset(pScopeDataItem, 0, sizeof(SCOPEDATAITEM));
// set parent scope item
pScopeDataItem->mask |= SDI_PARENT; pScopeDataItem->relativeID = pParentScopeItem;
// Add node name, we implement callback
pScopeDataItem->mask |= SDI_STR; pScopeDataItem->displayname = MMC_CALLBACK;
// Add the lParam
pScopeDataItem->mask |= SDI_PARAM; pScopeDataItem->lParam = lParam; // Add close image
if (nImage != -1) { pScopeDataItem->mask |= SDI_IMAGE; pScopeDataItem->nImage = nImage; } // Add open image
if (nOpenImage != -1) { pScopeDataItem->mask |= SDI_OPENIMAGE; pScopeDataItem->nOpenImage = nOpenImage; } // Add button to node if the folder has children
if (bHasChildren == TRUE) { pScopeDataItem->mask |= SDI_CHILDREN; pScopeDataItem->cChildren = 1; } }
///////////////////////////////////////////////////////////////////////////////
// Timer and Background Thread
BOOL CComponentDataObject::StartTimerThread() { ASSERT(::IsWindow(m_hWnd)); m_pTimerThreadObj = OnCreateTimerThread();
if (m_pTimerThreadObj == NULL) { return TRUE; }
// start the the thread
if (!m_pTimerThreadObj->Start(m_hWnd)) { return FALSE; }
ASSERT(m_pTimerThreadObj->m_nThreadID != 0); m_nTimerThreadID = m_pTimerThreadObj->m_nThreadID;
WaitForTimerThreadStartAck(); return SetTimer(); }
void CComponentDataObject::ShutDownTimerThread() { KillTimer(); PostMessageToTimerThread(WM_QUIT, 0,0);
//
// Wait for the thread to die or else we could AV since there may be more
// messages in the queue than just the WM_QUIT
//
if (m_pTimerThreadObj != NULL) { DWORD dwRetState = ::WaitForSingleObject(m_pTimerThreadObj->m_hThread,INFINITE); ASSERT(dwRetState != WAIT_FAILED); }
//
// Threads now gone, delete the thread object
//
delete m_pTimerThreadObj; m_pTimerThreadObj = NULL; }
BOOL CComponentDataObject::PostMessageToTimerThread(UINT Msg, WPARAM wParam, LPARAM lParam) { if (m_nTimerThreadID != 0) { return ::PostThreadMessage(m_nTimerThreadID, Msg, wParam, lParam); } return TRUE; }
BOOL CComponentDataObject::SetTimer() { ASSERT(::IsWindow(m_hWnd)); ASSERT(m_hiddenWnd.m_nTimerID == 0); m_dwTimerTime = 0; DWORD dwTimerIntervalMillisec = m_dwTimerInterval*1000; m_hiddenWnd.m_nTimerID = m_hiddenWnd.SetTimer(1, dwTimerIntervalMillisec); return (m_hiddenWnd.m_nTimerID != 0); }
void CComponentDataObject::KillTimer() { ASSERT(::IsWindow(m_hWnd)); if (m_hiddenWnd.m_nTimerID != 0) { VERIFY(m_hiddenWnd.KillTimer(static_cast<UINT>(m_hiddenWnd.m_nTimerID))); m_hiddenWnd.m_nTimerID = 0; } }
void CComponentDataObject::WaitForTimerThreadStartAck() { MSG tempMSG; ASSERT(!m_bTimerThreadStarted); while(!m_bTimerThreadStarted) { if (::PeekMessage(&tempMSG,m_hWnd,CHiddenWnd::s_TimerThreadMessage, CHiddenWnd::s_TimerThreadMessage, PM_REMOVE)) { DispatchMessage(&tempMSG); } } }
void CComponentDataObject::WaitForThreadExitMessage(CMTContainerNode* pNode) { MSG tempMSG; while(GetRunningThreadTable()->IsPresent(pNode)) { if (::PeekMessage(&tempMSG, m_hiddenWnd.m_hWnd, CHiddenWnd::s_NodeThreadHaveDataNotificationMessage, CHiddenWnd::s_NodeThreadExitingNotificationMessage, PM_REMOVE)) { DispatchMessage(&tempMSG); } } // while
}
///////////////////////////////////////////////////////////////////////////////
// CComponentObject implementation
///////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG_REFCOUNT
unsigned int CComponentObject::m_nOustandingObjects = 0; #endif // _DEBUG_REFCOUNT
CComponentObject::CComponentObject() { #ifdef _DEBUG_REFCOUNT
dbg_cRef = 0; ++m_nOustandingObjects; TRACE(_T("CComponentObject(), count = %d\n"),m_nOustandingObjects); #endif // _DEBUG_REFCOUNT
Construct(); }
CComponentObject::~CComponentObject() { #ifdef _DEBUG_REFCOUNT
--m_nOustandingObjects; TRACE(_T("~CComponentObject(), count = %d\n"),m_nOustandingObjects); #endif // _DEBUG_REFCOUNT
// Make sure the interfaces have been released
ASSERT(m_pConsole == NULL); ASSERT(m_pHeader == NULL);
//SAFE_RELEASE(m_pComponentData); // QI'ed in IComponentDataImpl::CreateComponent
if (m_pComponentData != NULL) { m_pComponentData->Release(); m_pComponentData = NULL; TRACE(_T("~CComponentObject() released m_pCompomentData\n")); } Construct(); }
void CComponentObject::Construct() { m_pConsole = NULL; m_pHeader = NULL;
m_pResult = NULL; m_pImageResult = NULL; m_pComponentData = NULL; m_pToolbar = NULL; m_pControlbar = NULL; m_pConsoleVerb = NULL;
m_pSelectedContainerNode = NULL; m_pSelectedNode = NULL; m_selectedType = CCT_UNINITIALIZED; }
///////////////////////////////////////////////////////////////////////////////
// CComponentObject::IComponent members
STDMETHODIMP CComponentObject::Initialize(LPCONSOLE lpConsole) { ASSERT(lpConsole != NULL);
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// Save the IConsole pointer
m_pConsole = lpConsole; m_pConsole->AddRef();
// QI for a IHeaderCtrl
HRESULT hr = m_pConsole->QueryInterface(IID_IHeaderCtrl, reinterpret_cast<void**>(&m_pHeader));
// Give the console the header control interface pointer
if (SUCCEEDED(hr)) { m_pConsole->SetHeader(m_pHeader); }
m_pConsole->QueryInterface(IID_IResultData, reinterpret_cast<void**>(&m_pResult));
hr = m_pConsole->QueryResultImageList(&m_pImageResult); ASSERT(hr == S_OK);
hr = m_pConsole->QueryConsoleVerb(&m_pConsoleVerb); ASSERT(hr == S_OK);
return S_OK; }
STDMETHODIMP CComponentObject::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param) { HRESULT hr = S_OK;
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (event == MMCN_PROPERTY_CHANGE) { ASSERT(lpDataObject == NULL); hr = OnPropertyChange(param, static_cast<ULONG>(arg)); } else if (event == MMCN_VIEW_CHANGE) { hr = OnUpdateView(lpDataObject,arg,param); } else if (event == MMCN_DESELECT_ALL) { TRACE(_T("CComponentObject::Notify -> MMCN_DESELECT_ALL \n")); } else if (event == MMCN_COLUMN_CLICK) { OnColumnSortChanged(arg, param); } else if (event == MMCN_CUTORMOVE) { hr = S_FALSE; } else if (lpDataObject != NULL) { CInternalFormatCracker ifc; ifc.Extract(lpDataObject);
if (ifc.GetCookieCount() < 1) { CComponentDataObject* pComponentDataObject = (CComponentDataObject*)m_pComponentData; if ( (event == MMCN_ADD_IMAGES) && pComponentDataObject->IsExtensionSnapin() ) { CTreeNode* pTreeNode = pComponentDataObject->GetRootData(); return InitializeBitmaps(pTreeNode); // cookie for the root
} return S_OK; }
switch(event) { case MMCN_ACTIVATE: break;
case MMCN_CLICK: OnResultItemClk(ifc, FALSE); break;
case MMCN_DBLCLICK: hr = S_FALSE; break;
case MMCN_ADD_IMAGES: OnAddImages(ifc, arg, param); break;
case MMCN_SHOW: hr = OnShow(ifc, arg, param); break;
case MMCN_COLUMNS_CHANGED: hr = OnColumnsChanged(ifc, arg, param); break;
case MMCN_MINIMIZED: hr = OnMinimize(ifc, arg, param); break;
case MMCN_SELECT: HandleStandardVerbs( (BOOL) LOWORD(arg)/*bScope*/, (BOOL) HIWORD(arg)/*bSelect*/,lpDataObject); break;
case MMCN_QUERY_PASTE: hr = S_FALSE; break;
case MMCN_PASTE: AfxMessageBox(_T("CComponentObject::MMCN_PASTE")); break;
case MMCN_DELETE: // just delegate to the component data object
hr = ((CComponentDataObject*)m_pComponentData)->OnDeleteVerbHandler( ifc, this); break; case MMCN_REFRESH: // just delegate to the component data object
hr = ((CComponentDataObject*)m_pComponentData)->OnRefreshVerbHandler( ifc);
//
// Once the refresh has begun, update the verbs associated with the
// object being refreshed.
//
HandleStandardVerbs( (BOOL) LOWORD(arg)/*bScope*/, (BOOL) HIWORD(arg)/*bSelect*/,lpDataObject);
break;
case MMCN_RENAME: // just delegate to the component data object
hr = ((CComponentDataObject*)m_pComponentData)->OnRename(ifc, arg, param); break;
case MMCN_CONTEXTHELP: // just delegate to the component data object
hr = ((CComponentDataObject*)m_pComponentData)->OnHelpHandler(ifc, this); break; default: hr = E_UNEXPECTED; break; }
}
return hr; }
STDMETHODIMP CComponentObject::Destroy(MMC_COOKIE) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
//
// Release the interfaces that we QI'ed
//
if (m_pConsole != NULL) { //
// Tell the console to release the header control interface
//
m_pConsole->SetHeader(NULL); SAFE_RELEASE(m_pHeader); SAFE_RELEASE(m_pToolbar); SAFE_RELEASE(m_pControlbar);
SAFE_RELEASE(m_pResult); SAFE_RELEASE(m_pImageResult); SAFE_RELEASE(m_pConsoleVerb);
// Release the IConsole interface last
SAFE_RELEASE(m_pConsole); } return S_OK; }
STDMETHODIMP CComponentObject::GetResultViewType(MMC_COOKIE cookie, LPOLESTR* ppViewType, long* pViewOptions) { CTreeNode* pNode; if (cookie == NULL) { pNode = ((CComponentDataObject*)m_pComponentData)->GetRootData(); } else { pNode = reinterpret_cast<CTreeNode*>(cookie); } ASSERT(pNode != NULL);
if (pNode != NULL) { return pNode->GetResultViewType((CComponentDataObject*)m_pComponentData, ppViewType, pViewOptions); } // Use default view
if (((CComponentDataObject*)m_pComponentData)->IsMultiSelect()) { *pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT; } else { *pViewOptions = MMC_VIEW_OPTIONS_NONE; } *ppViewType = NULL; return S_FALSE; }
STDMETHODIMP CComponentObject::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject) { HRESULT hr = S_OK;
ASSERT(ppDataObject != NULL);
CComObject<CDataObject>* pObject; CComObject<CDataObject>::CreateInstance(&pObject); ASSERT(pObject != NULL);
if (pObject != NULL) { CTreeNode* pNode = NULL; if (cookie == MMC_MULTI_SELECT_COOKIE) { TRACE(_T("CDSEvent::GetDataObject() - multi-select.\n")); RESULTDATAITEM rdi; ZeroMemory(&rdi, sizeof(rdi)); rdi.mask = RDI_STATE; rdi.nIndex = -1; rdi.nState = LVIS_SELECTED; do { rdi.lParam = 0; ASSERT(rdi.mask == RDI_STATE); ASSERT(rdi.nState == LVIS_SELECTED); hr = m_pResult->GetNextItem(&rdi); if (hr != S_OK) break; pNode = reinterpret_cast<CTreeNode*>(rdi.lParam); pObject->AddCookie(pNode); } while (1); // addref() the new pointer and return it.
pObject->AddRef(); *ppDataObject = pObject; } else { // Delegate it to the IComponentData implementation
ASSERT(m_pComponentData != NULL); hr = m_pComponentData->QueryDataObject(cookie, type, ppDataObject); } } return hr; }
STDMETHODIMP CComponentObject::GetDisplayInfo(LPRESULTDATAITEM pResultDataItem) { ASSERT(pResultDataItem != NULL); CTreeNode* pNode = reinterpret_cast<CTreeNode*>(pResultDataItem->lParam); ASSERT(pNode != NULL); ASSERT(pResultDataItem->bScopeItem == pNode->IsContainer());
if (pResultDataItem->mask & RDI_STR) { LPCWSTR lpszString = pNode->GetString(pResultDataItem->nCol); if (lpszString != NULL) { pResultDataItem->str = (LPWSTR)lpszString; } } if ((pResultDataItem->mask & RDI_IMAGE) && (pResultDataItem->nCol == 0)) { pResultDataItem->nImage = pNode->GetImageIndex(FALSE); } return S_OK; }
STDMETHODIMP CComponentObject::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB) { // Delegate it to the IComponentData implementation
ASSERT(m_pComponentData != NULL); return m_pComponentData->CompareObjects(lpDataObjectA, lpDataObjectB); }
///////////////////////////////////////////////////////////////////////////////
// Message handlers for CComponentObject::IComponent::Notify()
HRESULT CComponentObject::OnFolder(CTreeNode*, LPARAM, LPARAM) { ASSERT(FALSE); return S_OK; }
HRESULT CComponentObject::OnShow(CInternalFormatCracker& ifc, LPARAM arg, LPARAM) { HRESULT hr = S_OK; ASSERT(ifc.GetCookieCount() == 1); //
// I shouldn't have to deal with multiple select here
//
CTreeNode* pNode = ifc.GetCookieAt(0); ASSERT(pNode != NULL); ASSERT(pNode->IsContainer()); CContainerNode* pContainerNode = (CContainerNode*)pNode;
// Note - arg is TRUE when it is time to enumerate
if (arg == TRUE) { long lResultView; LPOLESTR lpoleResultView = NULL; pNode->GetResultViewType((CComponentDataObject*)m_pComponentData, &lpoleResultView, &lResultView); if (lResultView == MMC_VIEW_OPTIONS_NONE || lResultView == MMC_VIEW_OPTIONS_MULTISELECT) { // Show the headers for this nodetype
InitializeHeaders(pContainerNode); EnumerateResultPane(pContainerNode); m_pSelectedContainerNode = pContainerNode; SetDescriptionBarText(pContainerNode); } else { m_pSelectedContainerNode = pContainerNode; hr = pNode->OnShow(m_pConsole); } } else { // Removed by JEFFJON : new column header implementation
// if we want we can notify ourselves that the focus is being lost
// SaveHeadersInfo(pContainerNode);
m_pSelectedContainerNode = NULL; // Free data associated with the result pane items, because
// your node is no longer being displayed.
// Note: The console will remove the items from the result pane
} #ifdef _DEBUG
if (m_pSelectedContainerNode == NULL) TRACE(_T("NULL selection\n")); else TRACE(_T("Node <%s> selected\n"), m_pSelectedContainerNode->GetDisplayName()); #endif
return hr; }
HRESULT CComponentObject::OnColumnsChanged(CInternalFormatCracker& ifc, LPARAM, LPARAM param) { CTreeNode* pNode = ifc.GetCookieAt(0); ASSERT(pNode != NULL); ASSERT(pNode->IsContainer()); CContainerNode* pContainerNode = (CContainerNode*)pNode;
MMC_VISIBLE_COLUMNS* pVisibleCols = reinterpret_cast<MMC_VISIBLE_COLUMNS*>(param); pContainerNode->OnColumnsChanged(pVisibleCols->rgVisibleCols, pVisibleCols->nVisibleColumns);
return S_OK; }
HRESULT CComponentObject::OnColumnSortChanged(LPARAM, LPARAM) { return S_OK; }
HRESULT CComponentObject::ForceSort(UINT iCol, DWORD dwDirection) { HRESULT hr = m_pResult->Sort(iCol, dwDirection, NULL); return hr; }
HRESULT CComponentObject::OnActivate(CTreeNode*, LPARAM, LPARAM) { ASSERT(FALSE); return S_OK; }
HRESULT CComponentObject::OnResultItemClk(CInternalFormatCracker&, BOOL) { return S_OK; }
HRESULT CComponentObject::OnMinimize(CInternalFormatCracker&, LPARAM, LPARAM) { return S_OK; }
HRESULT CComponentObject::OnPropertyChange(LPARAM param, long fScopePane) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); ASSERT(param != NULL); #ifdef _DEBUG
TRACE(_T("CComponentObject::OnPropertyChange()\n")); CPropertyPageHolderBase* pPPHolder = reinterpret_cast<CPropertyPageHolderBase*>(param); ASSERT(pPPHolder != NULL); CTreeNode* pNode = pPPHolder->GetTreeNode(); ASSERT(pNode != NULL);
// the item must be a result item and in the result pane
ASSERT(!fScopePane); #endif
// we delegate the call to the IComponentData implementation
CComponentDataObject* pComponentDataObject = (CComponentDataObject*)m_pComponentData; ASSERT(pComponentDataObject != NULL); return pComponentDataObject->OnPropertyChange(param, fScopePane); }
HRESULT CComponentObject::OnUpdateView(LPDATAOBJECT, LPARAM data, LONG_PTR hint) { if (m_pSelectedContainerNode == NULL) { return S_OK; // no selection for our IComponentData
}
if (hint == DELETE_ALL_RESULT_ITEMS) { // data contains the container whose result pane has to be refreshed
CContainerNode* pNode = reinterpret_cast<CContainerNode*>(data); ASSERT(pNode != NULL);
// do it only if selected and we are using the standard list view,
// if not, reselecting will do a delete/enumeration
long lResultView; LPOLESTR lpoleResultView = NULL; pNode->GetResultViewType((CComponentDataObject*)m_pComponentData, &lpoleResultView, &lResultView); if (m_pSelectedContainerNode == pNode && (lResultView == MMC_VIEW_OPTIONS_NONE || lResultView == MMC_VIEW_OPTIONS_MULTISELECT)) { ASSERT(m_pResult != NULL); VERIFY(SUCCEEDED(m_pResult->DeleteAllRsltItems())); SetDescriptionBarText(pNode); } } else if (hint == SORT_RESULT_PANE) { // data contains the container whose result pane has to be refreshed
CContainerNode* pNode = reinterpret_cast<CContainerNode*>(data); ASSERT(pNode != NULL); // do it only if selected, if not, reselecting will do a delete/enumeration
if (m_pSelectedContainerNode == pNode) { MMC_SORT_SET_DATA* pColumnSortData = NULL;
// build the column id
LPCWSTR lpszColumnID = pNode->GetColumnID(); size_t iLen = wcslen(lpszColumnID);
// allocate memory for the struct and add on enough to make the byte[1] into a string
// for the column id
SColumnSetID* pColumnID = (SColumnSetID*)malloc(sizeof(SColumnSetID) + (iLen * sizeof(WCHAR))); memset(pColumnID, 0, sizeof(SColumnSetID) + (iLen * sizeof(WCHAR))); pColumnID->cBytes = static_cast<DWORD>(iLen * sizeof(WCHAR)); wcscpy((LPWSTR)pColumnID->id, lpszColumnID);
// Get the sort column and direction
IColumnData* pColumnData = NULL; HRESULT hr = m_pConsole->QueryInterface(IID_IColumnData, reinterpret_cast<void**>(&pColumnData)); if (pColumnData != NULL) hr = pColumnData->GetColumnSortData(pColumnID, &pColumnSortData); if (SUCCEEDED(hr)) { if (pColumnSortData != NULL) { UINT iCurrentSortColumn = pColumnSortData->pSortData->nColIndex; DWORD dwCurrentSortDirection = pColumnSortData->pSortData->dwSortOptions;
VERIFY(SUCCEEDED(ForceSort(iCurrentSortColumn, dwCurrentSortDirection))); CoTaskMemFree(pColumnSortData); } } if (pColumnData != NULL) pColumnData->Release(); free(pColumnID); } } else if (hint == REPAINT_RESULT_PANE) { // data contains the container whose result pane has to be refreshed
CContainerNode* pNode = reinterpret_cast<CContainerNode*>(data); if (pNode == NULL) pNode = m_pSelectedContainerNode; // passing NULL means apply to the current selection
// update all the leaf nodes in the result pane
CNodeList* pChildList = ((CContainerNode*)pNode)->GetLeafChildList(); for( POSITION pos = pChildList->GetHeadPosition(); pos != NULL; ) { CLeafNode* pCurrentChild = (CLeafNode*)pChildList->GetNext(pos); ChangeResultPaneItem(pCurrentChild,CHANGE_RESULT_ITEM); } } else if ( hint == DELETE_MULTIPLE_RESULT_ITEMS) { CNodeList* pNodeList = reinterpret_cast<CNodeList*>(data); ASSERT(pNodeList != NULL);
POSITION pos = pNodeList->GetHeadPosition(); while (pos != NULL) { CTreeNode* pNode = pNodeList->GetNext(pos); ASSERT(pNode != NULL); if (!pNode->IsContainer()) { DeleteResultPaneItem(static_cast<CLeafNode*>(pNode)); } } SetDescriptionBarText(pNodeList->GetHead()->GetContainer()); } else if ( (hint == ADD_RESULT_ITEM) || (hint == DELETE_RESULT_ITEM) || (hint & CHANGE_RESULT_ITEM)) { // we deal with a leaf node
CLeafNode* pNode = reinterpret_cast<CLeafNode*>(data); ASSERT(pNode != NULL); // consider only if the parent is selected, otherwise will enumerate later when selected
if (m_pSelectedContainerNode == pNode->GetContainer()) { if (hint & CHANGE_RESULT_ITEM) { ChangeResultPaneItem(pNode,hint); } else if ( hint == ADD_RESULT_ITEM) { AddResultPaneItem(pNode); SetDescriptionBarText(pNode); } else if ( hint == DELETE_RESULT_ITEM) { DeleteResultPaneItem(pNode); SetDescriptionBarText(pNode); } } } else if (hint == UPDATE_VERB_STATE) { CTreeNode* pTreeNode = reinterpret_cast<CTreeNode*>(data); ASSERT(pTreeNode != NULL); if (m_pSelectedNode == pTreeNode) { ASSERT(m_selectedType != CCT_UNINITIALIZED); CNodeList nodeList; nodeList.AddTail(pTreeNode); m_pConsoleVerb->SetDefaultVerb(pTreeNode->GetDefaultVerb(m_selectedType, &nodeList)); pTreeNode->OnSetVerbState(m_pConsoleVerb, m_selectedType, &nodeList); } } else if (hint == UPDATE_DESCRIPTION_BAR) { CTreeNode* pTreeNode = reinterpret_cast<CTreeNode*>(data); ASSERT(pTreeNode != NULL); SetDescriptionBarText(pTreeNode); } else if (hint == UPDATE_RESULT_PANE_VIEW) { CContainerNode* pNode = reinterpret_cast<CContainerNode*>(data); ASSERT(pNode != NULL); HSCOPEITEM hScopeID = pNode->GetScopeID(); if (hScopeID != 0) { m_pConsole->SelectScopeItem(hScopeID); } } return S_OK; }
HRESULT CComponentObject::SetDescriptionBarText(CTreeNode* pTreeNode) { ASSERT(pTreeNode != NULL); HRESULT hr = S_OK; if (m_pSelectedContainerNode == pTreeNode) { LPWSTR lpszText = pTreeNode->GetDescriptionBarText(); hr = m_pResult->SetDescBarText(lpszText); } else if (m_pSelectedContainerNode == pTreeNode->GetContainer()) { LPWSTR lpszText = pTreeNode->GetContainer()->GetDescriptionBarText(); hr = m_pResult->SetDescBarText(lpszText); }
return hr; }
HRESULT CComponentObject::OnAddImages(CInternalFormatCracker& ifc, LPARAM, LPARAM) { CTreeNode* pNode = ifc.GetCookieAt(0); ASSERT(pNode != NULL); return InitializeBitmaps(pNode); }
void CComponentObject::HandleStandardVerbs(BOOL bScope, BOOL bSelect, LPDATAOBJECT lpDataObject) { if (lpDataObject == NULL) { return; } ((CComponentDataObject*)m_pComponentData)->HandleStandardVerbsHelper( this, m_pConsoleVerb, bScope, bSelect, lpDataObject); }
void CComponentObject::EnumerateResultPane(CContainerNode* pContainerNode) { ASSERT(m_pResult != NULL); // make sure we QI'ed for the interfaces
ASSERT(m_pComponentData != NULL); ASSERT(pContainerNode != NULL);
//
// get the list of children
// subfolders already added by console, add only the leaf nodes
//
CNodeList* pChildList = pContainerNode->GetLeafChildList(); ASSERT(pChildList != NULL);
POSITION pos; for( pos = pChildList->GetHeadPosition(); pos != NULL; ) { CTreeNode* pCurrChildNode = pChildList->GetNext(pos); ASSERT(pCurrChildNode != NULL);
if(pCurrChildNode->IsVisible()) { VERIFY(SUCCEEDED(AddResultPaneItem((CLeafNode*)pCurrChildNode))); } } }
HRESULT CComponentObject::AddResultPaneItem(CLeafNode* pNodeToInsert) { ASSERT(m_pResult != NULL); ASSERT(pNodeToInsert != NULL); RESULTDATAITEM resultItem; memset(&resultItem, 0, sizeof(RESULTDATAITEM));
resultItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM; resultItem.str = MMC_CALLBACK;
//use close image index on result pane
resultItem.nImage = pNodeToInsert->GetImageIndex(FALSE); resultItem.lParam = reinterpret_cast<LPARAM>(pNodeToInsert); return m_pResult->InsertItem(&resultItem); }
HRESULT CComponentObject::DeleteResultPaneItem(CLeafNode* pNodeToDelete) { ASSERT(m_pResult != NULL); ASSERT(pNodeToDelete != NULL); RESULTDATAITEM resultItem; memset(&resultItem, 0, sizeof(RESULTDATAITEM));
HRESULTITEM itemID; HRESULT hr = m_pResult->FindItemByLParam(reinterpret_cast<LPARAM>(pNodeToDelete), &itemID); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) { return hr; } return m_pResult->DeleteItem(itemID,0 /* all cols */); }
HRESULT CComponentObject::ChangeResultPaneItem(CLeafNode* pNodeToChange, LONG_PTR changeMask) { ASSERT(changeMask & CHANGE_RESULT_ITEM); ASSERT(m_pResult != NULL); ASSERT(pNodeToChange != NULL); HRESULTITEM itemID;
HRESULT hr = m_pResult->FindItemByLParam(reinterpret_cast<LPARAM>(pNodeToChange), &itemID); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) { return hr; }
RESULTDATAITEM resultItem; memset(&resultItem, 0, sizeof(RESULTDATAITEM)); resultItem.itemID = itemID; if (changeMask & CHANGE_RESULT_ITEM_DATA) { //
// UpdateItem() alone does not allow the
// item string buffer to grow and you get "foo..." when
// "foo" changes to "foobar" the first time (buffer grows)
//
resultItem.mask |= RDI_STR; resultItem.str = MMC_CALLBACK; //
// this line asserts, use the one above ask Tony
//
//resultItem.str = (LPWSTR)pNodeToChange->GetDisplayName();
} if (changeMask & CHANGE_RESULT_ITEM_ICON) { resultItem.mask |= RDI_IMAGE; resultItem.nImage = pNodeToChange->GetImageIndex(FALSE); } hr = m_pResult->SetItem(&resultItem); ASSERT(SUCCEEDED(hr)); hr = m_pResult->UpdateItem(itemID); ASSERT(SUCCEEDED(hr)); return hr; }
HRESULT CComponentObject::FindResultPaneItemID(CLeafNode* pNode, HRESULTITEM*) { ASSERT(FALSE); ASSERT(m_pResult != NULL); RESULTDATAITEM resultItem; memset(&resultItem, 0, sizeof(RESULTDATAITEM));
resultItem.mask = SDI_PARAM; resultItem.lParam = reinterpret_cast<LPARAM>(pNode); HRESULT hr = m_pResult->GetItem(&resultItem); ASSERT(SUCCEEDED(hr)); return E_FAIL; }
///////////////////////////////////////////////////////////////////////////////
// CComponentObject::IExtendPropertySheet2 members
STDMETHODIMP CComponentObject::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider, LONG_PTR handle, LPDATAOBJECT lpIDataObject) { // Delegate it to the IComponentData implementation
ASSERT(m_pComponentData != NULL); IExtendPropertySheet2* pIExtendPropertySheet2; VERIFY(SUCCEEDED(m_pComponentData->QueryInterface(IID_IExtendPropertySheet2, reinterpret_cast<void**>(&pIExtendPropertySheet2)))); ASSERT(pIExtendPropertySheet2 != NULL); HRESULT hr = pIExtendPropertySheet2->CreatePropertyPages(lpProvider, handle, lpIDataObject); pIExtendPropertySheet2->Release(); return hr; }
STDMETHODIMP CComponentObject::QueryPagesFor(LPDATAOBJECT lpDataObject) { // Delegate it to the IComponentData implementation
ASSERT(m_pComponentData != NULL); IExtendPropertySheet2* pIExtendPropertySheet2; VERIFY(SUCCEEDED(m_pComponentData->QueryInterface(IID_IExtendPropertySheet2, reinterpret_cast<void**>(&pIExtendPropertySheet2)))); ASSERT(pIExtendPropertySheet2 != NULL); HRESULT hr = pIExtendPropertySheet2->QueryPagesFor(lpDataObject); pIExtendPropertySheet2->Release(); return hr; }
STDMETHODIMP CComponentObject::GetWatermarks(LPDATAOBJECT lpDataObject, HBITMAP* lphWatermark, HBITMAP* lphHeader, HPALETTE* lphPalette, BOOL* pbStretch) { // Delegate it to the IComponentData implementation
ASSERT(m_pComponentData != NULL); IExtendPropertySheet2* pIExtendPropertySheet2; VERIFY(SUCCEEDED(m_pComponentData->QueryInterface(IID_IExtendPropertySheet2, reinterpret_cast<void**>(&pIExtendPropertySheet2)))); ASSERT(pIExtendPropertySheet2 != NULL); HRESULT hr = pIExtendPropertySheet2->GetWatermarks(lpDataObject, lphWatermark, lphHeader, lphPalette, pbStretch); pIExtendPropertySheet2->Release(); return hr; }
///////////////////////////////////////////////////////////////////////////////
// CComponentObject::IExtendContextMenu members
STDMETHODIMP CComponentObject::AddMenuItems(LPDATAOBJECT pDataObject, LPCONTEXTMENUCALLBACK pContextMenuCallback, long *pInsertionAllowed) { HRESULT hr = S_OK;
CComPtr<IContextMenuCallback2> spContextMenuCallback2; hr = pContextMenuCallback->QueryInterface(IID_IContextMenuCallback2, (PVOID*)&spContextMenuCallback2); if (FAILED(hr)) { return hr; }
if (pDataObject == DOBJ_CUSTOMOCX) { //
// A custom result pane is being used and we don't know what node it cooresponds to so we assume that it
// is the previously selected container.
//
ASSERT(m_pSelectedContainerNode != NULL); CTreeNode* pNode = (CTreeNode*)m_pSelectedContainerNode; CNodeList nodeList; nodeList.AddTail(pNode); hr = m_pSelectedContainerNode->OnAddMenuItems(spContextMenuCallback2, CCT_UNINITIALIZED, pInsertionAllowed, &nodeList); } else { //
// Delegate it to the IComponentData implementation
//
ASSERT(m_pComponentData != NULL); IExtendContextMenu* pIExtendContextMenu; VERIFY(SUCCEEDED(m_pComponentData->QueryInterface(IID_IExtendContextMenu, reinterpret_cast<void**>(&pIExtendContextMenu)))); ASSERT(pIExtendContextMenu != NULL); hr = pIExtendContextMenu->AddMenuItems(pDataObject, pContextMenuCallback, pInsertionAllowed); pIExtendContextMenu->Release(); } return hr; }
STDMETHODIMP CComponentObject::Command(long nCommandID, LPDATAOBJECT pDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr = S_OK; if (pDataObject == DOBJ_CUSTOMOCX) { //
// A custom result pane is being used and we don't know what node it cooresponds to so we assume that it
// is the previously selected container.
//
ASSERT(m_pSelectedContainerNode != NULL); CTreeNode* pNode = (CTreeNode*)m_pSelectedContainerNode; CNodeList nodeList; nodeList.AddTail(pNode); hr = m_pSelectedContainerNode->OnCommand(nCommandID, CCT_UNINITIALIZED, (CComponentDataObject*)m_pComponentData, &nodeList); } else { // Delegate it to the IComponentData implementation
ASSERT(m_pComponentData != NULL); IExtendContextMenu* pIExtendContextMenu; VERIFY(SUCCEEDED(m_pComponentData->QueryInterface(IID_IExtendContextMenu, reinterpret_cast<void**>(&pIExtendContextMenu)))); ASSERT(pIExtendContextMenu != NULL); hr = pIExtendContextMenu->Command(nCommandID, pDataObject); pIExtendContextMenu->Release(); } return hr; }
///////////////////////////////////////////////////////////////////////////////
// CComponentObject::IExtendControlbar members
STDMETHODIMP CComponentObject::SetControlbar(LPCONTROLBAR pControlbar) { HRESULT hr = S_OK;
if (pControlbar == NULL) { //
// Detach the controls here
//
if (m_pControlbar != NULL && m_pToolbar != NULL) { hr = m_pControlbar->Detach((IUnknown *) m_pToolbar); SAFE_RELEASE(m_pControlbar); } } else { //
// Save the controlbar interface pointer
//
if (m_pControlbar == NULL) { m_pControlbar = pControlbar; m_pControlbar->AddRef(); }
//
// Do something here that checks to see if we have toolbars
// already created and use those. If not then create one
// and load everything necessary for it.
//
//
// Create the toolbar
//
hr = m_pControlbar->Create (TOOLBAR, this, (IUnknown **) &m_pToolbar); if (SUCCEEDED(hr)) { //
// Load the toolbar
//
AFX_MANAGE_STATE(AfxGetStaticModuleState()); hr = InitializeToolbar(m_pToolbar); if (FAILED(hr)) { hr = m_pControlbar->Detach((IUnknown*) m_pToolbar); SAFE_RELEASE(m_pControlbar); } } } return hr; }
STDMETHODIMP CComponentObject::ControlbarNotify(MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
HRESULT hr = S_OK;
if (m_pControlbar == NULL) { return hr; }
//
// MMC provides two events here MMCN_SELECT at the time a node is selected
// and MMCN_BTN_CLICK when a toolbar button is pressed
//
switch (event) { case MMCN_SELECT: { //
// Attach the toolbar to the controlbar
//
hr = m_pControlbar->Attach(TOOLBAR, (IUnknown *) m_pToolbar);
if (SUCCEEDED(hr)) { ASSERT(m_pToolbar != NULL);
//
// bSelect is TRUE if the node was selected, FALSE if the node was deselected
// bScope is TRUE if the a scope node is selected, FALSE if a result node was selected
//
BOOL bSelect = HIWORD(arg);
if (bSelect) { CInternalFormatCracker ifc; hr = ifc.Extract((LPDATAOBJECT)param); if (SUCCEEDED(hr)) {
CTreeNode* pNode = ifc.GetCookieAt(0); ASSERT(pNode != NULL);
CNodeList nodeList; ifc.GetCookieList(nodeList);
if (ifc.GetCookieCount() > 1) // multiple selection
{ ASSERT(pNode->GetContainer() != NULL); hr = pNode->GetContainer()->OnSetToolbarVerbState(m_pToolbar, &nodeList); } else if (ifc.GetCookieCount() == 1) // single selection
{ hr = pNode->OnSetToolbarVerbState(m_pToolbar, &nodeList); } } } } break; } case MMCN_BTN_CLICK: { //
// The arg is -1 for custom views like MessageView
//
if (DOBJ_CUSTOMOCX == (LPDATAOBJECT)arg) { if (m_pSelectedContainerNode != NULL) { CNodeList nodeList; nodeList.AddTail(m_pSelectedContainerNode);
hr = m_pSelectedContainerNode->ToolbarNotify(static_cast<int>(param), (CComponentDataObject*)m_pComponentData, &nodeList); } else { hr = S_FALSE; } } else { CInternalFormatCracker ifc; hr = ifc.Extract((LPDATAOBJECT)arg);
CTreeNode* pNode = ifc.GetCookieAt(0); ASSERT(pNode != NULL);
CNodeList nodeList; ifc.GetCookieList(nodeList);
if (ifc.GetCookieCount() > 1) // multiple selection
{ ASSERT(pNode->GetContainer() != NULL); hr = pNode->GetContainer()->ToolbarNotify(static_cast<int>(param), (CComponentDataObject*)m_pComponentData, &nodeList); } else if (ifc.GetCookieCount() == 1) // single selection
{ hr = pNode->ToolbarNotify(static_cast<int>(param), (CComponentDataObject*)m_pComponentData, &nodeList); } else { hr = S_FALSE; } } break; }
default: { break; } }
return hr; }
///////////////////////////////////////////////////////////////////////////////
// CComponentObject::IResultDataCompareEx members
// This compare is used to sort the item's in the listview
//
// Note: Assum sort is ascending when comparing.
STDMETHODIMP CComponentObject::Compare(RDCOMPARE* prdc, int* pnResult) { if (pnResult == NULL) { ASSERT(FALSE); return E_POINTER; }
if (prdc == NULL) { ASSERT(FALSE); return E_POINTER; }
CTreeNode* pNodeA = reinterpret_cast<CTreeNode*>(prdc->prdch1->cookie); CTreeNode* pNodeB = reinterpret_cast<CTreeNode*>(prdc->prdch2->cookie); ASSERT(pNodeA != NULL); ASSERT(pNodeB != NULL); CContainerNode* pContNode = pNodeA->GetContainer(); ASSERT(pContNode != NULL);
// delegate the sorting to the container
int nCol = prdc->nColumn; *pnResult = pContNode->Compare(pNodeA, pNodeB, nCol, prdc->lUserParam);
return S_OK; }
///////////////////////////////////////////////////////////////////////////////
// CComponentObject Helpers
// This wrapper function required to make prefast shut up when we are
// initializing a critical section in a constructor.
void ExceptionPropagatingInitializeCriticalSection(LPCRITICAL_SECTION critsec) { __try { ::InitializeCriticalSection(critsec); }
//
// propagate the exception to our caller.
//
__except (EXCEPTION_CONTINUE_SEARCH) { } }
|