2025-11-27 16:46:48 +09:00

502 lines
13 KiB
C++

// OXCoolControlOrganizer.cpp: implementation of the COXCoolControlOrganizer class.
//
//////////////////////////////////////////////////////////////////////
// Version: 9.3
#include "stdafx.h"
#include "OXCoolControlOrganizer.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
// static variables
CMap<DWORD,DWORD,COXCoolControlOrganizer*,COXCoolControlOrganizer*>
COXCoolControlOrganizer::m_arrThreadOrganizers;
HHOOK COXCoolControlOrganizer::m_pfnOriginalCBTHookProc=NULL;
HHOOK COXCoolControlOrganizer::m_pfnOriginalGetMessageHookProc=NULL;
/////////////////
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
COXCoolControlOrganizer::COXCoolControlOrganizer() :
m_dwThreadID(NULL),
m_pfnOldCBTHookProc(NULL),
m_pfnOldGetMessageHookProc(NULL)
{
}
COXCoolControlOrganizer::~COXCoolControlOrganizer()
{
if(IsAttachedAllInThread())
{
VERIFY(DetachAllInThread());
}
else
{
VERIFY(Detach(NULL));
}
ASSERT(m_pfnOriginalCBTHookProc==NULL);
ASSERT(m_pfnOldCBTHookProc==NULL);
ASSERT(m_pfnOriginalGetMessageHookProc==NULL);
}
BOOL COXCoolControlOrganizer::Attach(HWND hWnd)
{
ASSERT(hWnd!=NULL);
ASSERT(::IsWindow(hWnd));
if(IsAttached(hWnd))
{
TRACE(_T("COXCoolControlOrganizer::Attach: specified window has already been attached to a cool control object\n"));
return FALSE;
}
if(IsRejected(hWnd))
{
TRACE(_T("COXCoolControlOrganizer::Attach: specified window has been rejected before\n"));
return FALSE;
}
CWnd* pWnd=CWnd::FromHandlePermanent(hWnd);
if(pWnd!=NULL)
{
#ifdef _DEBUG
if(!IsAttachedAllInThread())
{
TRACE(_T("COXCoolControlOrganizer::Attach: cannot attach already subclassed window\n"));
}
#endif // _DEBUG
m_mapRejectedControls.SetAt(hWnd,1);
return FALSE;
}
CString sWndClass;
::GetClassName(hWnd,sWndClass.GetBuffer(512),512);
if(!IsQualified(hWnd,sWndClass))
{
#ifdef _DEBUG
if(!IsAttachedAllInThread())
{
TRACE(_T("COXCoolControlOrganizer::Attach: the window didn't qualify to be attached\n"));
}
#endif // _DEBUG
m_mapRejectedControls.SetAt(hWnd,2);
return FALSE;
}
void* pCoolCtrl=CreateCoolCtrl(hWnd,sWndClass);
if(pCoolCtrl==NULL)
{
TRACE(_T("COXCoolControlOrganizer::Attach: failed to create cool control for the specified window\n"));
m_mapRejectedControls.SetAt(hWnd,3);
return FALSE;
}
m_mapAttachedControls.SetAt(hWnd,pCoolCtrl);
::RedrawWindow(hWnd,NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
return TRUE;
}
BOOL COXCoolControlOrganizer::IsAttached(const HWND hWnd) const
{
void* pCoolCtrl=NULL;
BOOL bResult=m_mapAttachedControls.Lookup(hWnd,pCoolCtrl);
ASSERT(!bResult || pCoolCtrl!=NULL);
return bResult;
}
BOOL COXCoolControlOrganizer::IsRejected(const HWND hWnd) const
{
DWORD dwReason=0;
BOOL bResult=m_mapRejectedControls.Lookup(hWnd,dwReason);
ASSERT(!bResult || dwReason!=0);
return bResult;
}
BOOL COXCoolControlOrganizer::Detach(HWND hWnd)
{
if(hWnd!=NULL)
{
if(!IsAttached(hWnd))
{
TRACE(_T("COXCoolControlOrganizer::Detach: the specified window is not currently attached to a cool control object\n"));
return FALSE;
}
void* pCoolCtrl=NULL;
VERIFY(m_mapAttachedControls.Lookup(hWnd,pCoolCtrl));
ASSERT(pCoolCtrl!=NULL);
if(::IsWindow(((COXCoolCtrl<CWnd>*)pCoolCtrl)->GetSafeHwnd()))
{
((COXCoolCtrl<CWnd>*)pCoolCtrl)->UnsubclassWindow();
::RedrawWindow(hWnd,NULL,NULL,
RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
}
else
{
((COXCoolCtrl<CWnd>*)pCoolCtrl)->m_hWnd=NULL;
}
delete (COXCoolCtrl<CWnd>*)pCoolCtrl;
m_mapAttachedControls.RemoveKey(hWnd);
return TRUE;
}
else
{
for(POSITION pos=m_mapAttachedControls.GetStartPosition(); pos!=NULL;
pos=m_mapAttachedControls.GetStartPosition())
{
HWND hWndAttached=NULL;
void* pCoolCtrl=NULL;
m_mapAttachedControls.GetNextAssoc(pos,hWndAttached,pCoolCtrl);
ASSERT(hWndAttached!=NULL && pCoolCtrl!=NULL);
VERIFY(Detach(hWndAttached));
}
return TRUE;
}
}
BOOL COXCoolControlOrganizer::
AttachAllInThread(DWORD dwThreadID/*=::GetCurrentThreadId()*/)
{
if(IsAttachedAllInThread())
{
TRACE(_T("COXCoolControlOrganizer::AttachAllInThread: this object already attached to a thread\n"));
return FALSE;
}
COXCoolControlOrganizer* pOrganizer=NULL;
if(m_arrThreadOrganizers.Lookup(dwThreadID,pOrganizer))
{
ASSERT(pOrganizer!=NULL);
TRACE(_T("COXCoolControlOrganizer::AttachAllInThread: specified thread already attached to a COXCoolControlOrganizer object\n"));
return FALSE;
}
m_arrThreadOrganizers.SetAt(dwThreadID,this);
m_dwThreadID=dwThreadID;
// go through all windows and attach them
::EnumWindows(&EnumThreadWindows,(LPARAM)this);
// setup hooks for Computer Based Training
if(m_pfnOriginalCBTHookProc==NULL)
{
m_pfnOriginalCBTHookProc=
::SetWindowsHookEx(WH_CBT,CoolControlOrganizerCBTHookProc,NULL,dwThreadID);
m_pfnOldCBTHookProc=m_pfnOriginalCBTHookProc;
}
else
{
m_pfnOldCBTHookProc=
::SetWindowsHookEx(WH_CBT,CoolControlOrganizerCBTHookProc,NULL,dwThreadID);
}
// setup hooks for GetMessage
if(m_pfnOriginalGetMessageHookProc==NULL)
{
m_pfnOriginalGetMessageHookProc=::SetWindowsHookEx(WH_GETMESSAGE,
CoolControlOrganizerGetMessageHookProc,NULL,dwThreadID);
m_pfnOldGetMessageHookProc=m_pfnOriginalGetMessageHookProc;
}
else
{
m_pfnOldGetMessageHookProc=::SetWindowsHookEx(WH_GETMESSAGE,
CoolControlOrganizerGetMessageHookProc,NULL,dwThreadID);
}
return TRUE;
}
void COXCoolControlOrganizer::AttachAllWindows(HWND hWndStartFrom)
{
ASSERT(hWndStartFrom!=NULL);
HWND hWnd=hWndStartFrom;
while(hWnd!=NULL)
{
DWORD dwThreadID=::GetWindowThreadProcessId(hWnd,NULL);
if(dwThreadID!=GetAttachedThread())
break;
if(!IsAttached(hWnd) && !IsRejected(hWnd))
{
Attach(hWnd);
}
// loop through children
HWND hWndChild=::GetWindow(hWnd,GW_CHILD);
if(!IsAttached(hWndChild) && !IsRejected(hWndChild) && hWndChild!=NULL)
{
AttachAllWindows(hWndChild);
}
// loop through windows
hWnd=::GetWindow(hWnd,GW_HWNDNEXT);
}
}
LRESULT CALLBACK COXCoolControlOrganizer::
CoolControlOrganizerCBTHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
if(nCode>=0 && ::IsWindow((HWND)wParam))
{
DWORD dwThreadID=::GetWindowThreadProcessId((HWND)wParam,NULL);
COXCoolControlOrganizer* pOrganizer=NULL;
if(COXCoolControlOrganizer::m_arrThreadOrganizers.
Lookup(dwThreadID,pOrganizer))
{
ASSERT(pOrganizer!=NULL);
ASSERT(pOrganizer->IsAttachedAllInThread());
if(nCode==HCBT_DESTROYWND)
{
// check if the window that is about to be destroyed
// had been added to cool control organizer list
if(pOrganizer->IsAttached((HWND)wParam))
pOrganizer->Detach((HWND)wParam);
}
return ::CallNextHookEx(pOrganizer->GetSavedCBTHookProc(),
nCode,wParam,lParam);
}
}
return ::CallNextHookEx(COXCoolControlOrganizer::GetOriginalCBTHookProc(),
nCode,wParam,lParam);
}
LRESULT CALLBACK COXCoolControlOrganizer::
CoolControlOrganizerGetMessageHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
HWND hWnd=((MSG*)lParam)->hwnd;
if(nCode>=0 && ::IsWindow(hWnd))
{
DWORD dwThreadID=::GetWindowThreadProcessId(hWnd,NULL);
COXCoolControlOrganizer* pOrganizer=NULL;
if(COXCoolControlOrganizer::
m_arrThreadOrganizers.Lookup(dwThreadID,pOrganizer))
{
ASSERT(pOrganizer!=NULL);
ASSERT(pOrganizer->IsAttachedAllInThread());
// check if new window is created and attach it.
if(pOrganizer->IsAttached(hWnd) && ((MSG*)lParam)->message==WM_DESTROY)
{
pOrganizer->Detach(hWnd);
}
else if(!pOrganizer->IsAttached(hWnd))
{
pOrganizer->AttachAllWindows(hWnd);
}
return ::CallNextHookEx(pOrganizer->GetSavedGetMessageHookProc(),
nCode,wParam,lParam);
}
}
return ::CallNextHookEx(COXCoolControlOrganizer::GetOriginalGetMessageHookProc(),
nCode,wParam,lParam);
}
BOOL CALLBACK COXCoolControlOrganizer::EnumThreadWindows(HWND hWnd, LPARAM lParam)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
ASSERT(lParam!=NULL);
ASSERT(::IsWindow(hWnd));
COXCoolControlOrganizer* pOrganizer=(COXCoolControlOrganizer*)lParam;
ASSERT(pOrganizer->IsAttachedAllInThread());
DWORD dwThreadID=::GetWindowThreadProcessId(hWnd,NULL);
if(dwThreadID==pOrganizer->GetAttachedThread())
{
pOrganizer->AttachAllWindows(hWnd);
return FALSE;
}
return TRUE;
}
BOOL COXCoolControlOrganizer::DetachAllInThread()
{
if(!IsAttachedAllInThread())
return FALSE;
ASSERT(m_dwThreadID!=NULL);
ASSERT(m_pfnOldCBTHookProc!=NULL);
ASSERT(m_pfnOriginalCBTHookProc!=NULL);
ASSERT(m_pfnOldGetMessageHookProc!=NULL);
ASSERT(m_pfnOriginalGetMessageHookProc!=NULL);
// unhook CBT
if(m_pfnOldCBTHookProc!=NULL)
{
VERIFY(::UnhookWindowsHookEx(m_pfnOldCBTHookProc));
m_pfnOldCBTHookProc=NULL;
m_pfnOriginalCBTHookProc=NULL;
}
// unhook GetMessage
if(m_pfnOldGetMessageHookProc!=NULL)
{
VERIFY(::UnhookWindowsHookEx(m_pfnOldGetMessageHookProc));
m_pfnOldGetMessageHookProc=NULL;
m_pfnOriginalGetMessageHookProc=NULL;
}
// clear map of rejected windows
m_mapRejectedControls.RemoveAll();
m_arrThreadOrganizers.RemoveKey(m_dwThreadID);
m_dwThreadID=NULL;
return Detach(NULL);
}
BOOL COXCoolControlOrganizer::IsQualified(HWND hWnd, LPCTSTR lpszWndClass)
{
ASSERT(::IsWindow(hWnd));
CString sWndClass=lpszWndClass;
if(sWndClass.CompareNoCase(EDIT_CLASSNAME)==0 ||
sWndClass.CompareNoCase(BUTTON_CLASSNAME)==0 ||
sWndClass.CompareNoCase(SPIN_CLASSNAME)==0 ||
sWndClass.CompareNoCase(HOTKEY_CLASSNAME)==0 ||
sWndClass.CompareNoCase(COMBOBOX_CLASSNAME)==0 ||
sWndClass.CompareNoCase(SCROLLBAR_CLASSNAME)==0 ||
sWndClass.CompareNoCase(PROGRESS_CLASSNAME)==0 ||
sWndClass.CompareNoCase(SLIDER_CLASSNAME)==0 ||
#if _MFC_VER > 0x0421
sWndClass.CompareNoCase(DATETIME_CLASSNAME)==0 ||
sWndClass.CompareNoCase(MONTHCAL_CLASSNAME)==0 ||
sWndClass.CompareNoCase(IPADDRESS_CLASSNAME)==0 ||
#endif // _MFC_VER > 0x0421
sWndClass.CompareNoCase(LISTVIEW_CLASSNAME)==0 ||
sWndClass.CompareNoCase(TREEVIEW_CLASSNAME)==0 ||
sWndClass.CompareNoCase(LISTBOX_CLASSNAME)==0 ||
sWndClass.CompareNoCase(RICHEDIT_CLASSNAME)==0)
{
// special case with combo box - it subclasses its child edit and list box
// controls internally
if(sWndClass.CompareNoCase(EDIT_CLASSNAME)==0/* ||
sWndClass.CompareNoCase(LISTBOX_CLASSNAME)==0*/)
{
HWND hWndParent=::GetParent(hWnd);
if(hWndParent!=NULL)
{
if(COXCoolCtrl<CWnd>::IsComboBox(hWndParent))
{
m_mapRejectedControls.SetAt(hWnd,4);
return FALSE;
}
}
}
return TRUE;
}
return FALSE;
}
void* COXCoolControlOrganizer::CreateCoolCtrl(HWND hWnd, LPCTSTR lpszWndClass)
{
CString sWndClass=lpszWndClass;
COXCoolCtrl<CWnd>* pCoolCtrl=NULL;
if(sWndClass.CompareNoCase(EDIT_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolEdit;
else if(sWndClass.CompareNoCase(BUTTON_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolButton;
else if(sWndClass.CompareNoCase(SPIN_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolSpinButtonCtrl;
else if(sWndClass.CompareNoCase(HOTKEY_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolHotKeyCtrl;
else if(sWndClass.CompareNoCase(COMBOBOX_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolComboBox;
else if(sWndClass.CompareNoCase(SCROLLBAR_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolScrollBar;
else if(sWndClass.CompareNoCase(PROGRESS_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolProgressCtrl;
else if(sWndClass.CompareNoCase(SLIDER_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolSliderCtrl;
#if _MFC_VER > 0x0421
else if(sWndClass.CompareNoCase(DATETIME_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolDateTimeCtrl;
else if(sWndClass.CompareNoCase(MONTHCAL_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolMonthCalCtrl;
else if(sWndClass.CompareNoCase(IPADDRESS_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolIPAddressCtrl;
#endif // _MFC_VER > 0x0421
else if(sWndClass.CompareNoCase(LISTVIEW_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolListCtrl;
else if(sWndClass.CompareNoCase(TREEVIEW_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolTreeCtrl;
else if(sWndClass.CompareNoCase(LISTBOX_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolListBox;
else if(sWndClass.CompareNoCase(RICHEDIT_CLASSNAME)==0)
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolRichEditCtrl;
else
pCoolCtrl=(COXCoolCtrl<CWnd>*)new COXCoolCtrl<CWnd>;
ASSERT(pCoolCtrl!=NULL);
if(!pCoolCtrl->SubclassWindow(hWnd))
{
TRACE(_T("COXCoolControlOrganizer::CreateCoolCtrl: failed to subclass the window\n"));
delete pCoolCtrl;
return NULL;
}
return (void*)pCoolCtrl;
}