Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3633 lines
95 KiB

//+-------------------------------------------------------------------------
//
// 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)
{
}
}