实例化基类-Win32对话框类
Instancing a Base Class - Win32 Dialog Classes
我有三个类。。。Base、Derived 1和Derived 2。基类持有一个静态LONG(this*),它在一个静态函数中使用它来处理窗口消息。我遇到的问题是,当我声明多个派生类时,基类中的静态LONG在第二个派生类声明时发生了更改。。。这里是实现:
BaseDialog.h:
class CBaseDialog;
typedef void(CBaseDialog::*fpMessageHandler)(HWND hDlg,WPARAM wParam,LPARAM lParam);
struct t_MessageEntry
{
fpMessageHandler MsgHandler;
};
/////////////////////////////// MACROS
#define IMPLEMENT_MESSAGE_HANDLER(base,derived) void derived::AddHandler(UINT MessageId, void(derived::*Handler)(HWND hDlg,WPARAM wParam,LPARAM lParam))
{
AddMessageHandler(MessageId, (void(base::*)(HWND hDlg,WPARAM wParam,LPARAM lParam))Handler);
}
#define DECLARE_MESSAGE_HANDLER(derived) void AddHandler(UINT MessageId, void(derived::*Handler)(HWND hDlg,WPARAM wParam,LPARAM lParam));
void HandleManager(void);
#define BEGIN_MESSAGE_MAP(derived) void derived::HandleManager(void) {
#define ADD_MESSAGE_HANDLER(message,handler) AddHandler(message, handler);
#define END_MESSAGE_MAP() }
#define ENABLE_MESSAGE_MAP() HandleManager();
class CBaseDialog
{
public:
std::map<UINT,t_MessageEntry> m_MessageMap;
std::map<UINT,t_MessageEntry>::iterator m_MessageMapIterator;
CBaseDialog(int nResId, HWND hParent=NULL);
virtual ~CBaseDialog();
int DoModal(void);
static BOOL CALLBACK DialogProcStatic(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
void OnOK(void);
void OnCancel(void);
void AddMessageHandler(UINT MessageId, void(CBaseDialog::*Handler)(HWND hDlg,WPARAM wParam,LPARAM lParam));
protected:
int m_nResId;
HWND m_hParent;
static HWND m_hWindow;
static long m_lSaveThis;
};
BaseDialog.cpp:
HWND CBaseDialog::m_hWindow = NULL;
long CBaseDialog::m_lSaveThis = 0; // Changes on second declaration of derived class
CBaseDialog::CBaseDialog(int nResId, HWND hParent)
{
m_lSaveThis = (long)this; /// store this pointer
m_nResId = nResId;
m_hParent = hParent;
}
CBaseDialog::~CBaseDialog()
{
m_hWindow = NULL;
m_lSaveThis = 0;
}
int CBaseDialog::DoModal(void)
{
HWND hWnd = CreateDialog( GetModuleHandle( NULL ), MAKEINTRESOURCE( m_nResId ), m_hParent, ( DLGPROC )DialogProcStatic );
return 0;
}
void CBaseDialog::AddMessageHandler(UINT MessageId, void(CBaseDialog::*MsgHandler)(HWND hDlg,WPARAM wParam,LPARAM lParam))
{
t_MessageEntry MessageEntry;
MessageEntry.MsgHandler = MsgHandler;
m_MessageMap.insert(std::map<UINT,t_MessageEntry>::value_type(MessageId, MessageEntry)); /// insert key & data to map
}
BOOL CALLBACK CBaseDialog::DialogProcStatic(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if(m_hWindow == NULL)
{
m_hWindow = hDlg;
}
CBaseDialog *pThis = (CBaseDialog*)m_lSaveThis; /// typecast stored this-pointer to CBaseDialog pointer
return pThis->DialogProc( hDlg, uMsg, wParam, lParam );
}
BOOL CALLBACK CBaseDialog::DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
m_MessageMapIterator = m_MessageMap.find(message); /// find message entry by key
if(m_MessageMapIterator == m_MessageMap.end()) /// check if message entry available
{
return 0;
}
else
{
t_MessageEntry MessageEntry = (*m_MessageMapIterator).second; /// dereference iterator and get message entry
void (CBaseDialog::*MessageHandler)(HWND hDlg,WPARAM wParam,LPARAM lParam);
MessageHandler = MessageEntry.MsgHandler;
(this->*MessageHandler)(hDlg, wParam, lParam); /// execute function
return 0;
}
}
void CBaseDialog::OnOK(void)
{
EndDialog(m_hWindow, IDOK);
}
void CBaseDialog::OnCancel(void)
{
EndDialog(m_hWindow, IDCANCEL);
}
Outliner.h:
#include "BaseDialog.h"
class COutlinerDlg : public CBaseDialog
{
public:
COutlinerDlg( int nResId, HWND hParent=NULL );
virtual ~COutlinerDlg();
void Initialize( LPCWSTR strRootName )
{
m_strRootName = strRootName;
}
public:
VOID Resize( RECT rc );
HWND GetHWND(){ return m_hWindow; }
HWND GetTREEDLG(){ return m_hTreeDlg; }
BOOL GetVisible(){ return m_bVisible; }
VOID SetVisible( BOOL b ){ m_bVisible = b; }
BOOL GetDragging(){ return m_bDragging; }
VOID SetDragging( BOOL b ){ m_bDragging = b; }
VOID SetParentHWND( HWND hWnd ){ m_hParent = hWnd; }
HWND GetParentHWND(){ return m_hParent; }
BOOL Show( DWORD dwFlags ){ return ShowWindow( m_hWindow, dwFlags ); }
HRESULT BuildOutlinerFromDirectory( LPCWSTR rootName, LPCWSTR directory );
HRESULT BuildChildDirectory( LPCWSTR child );
protected:
void On_WM_INITDIALOG( HWND hDlg, WPARAM wParam, LPARAM lParam );
void On_WM_COMMAND( HWND hDlg, WPARAM wParam, LPARAM lParam );
void On_WM_NOTIFY( HWND hDlg, WPARAM wParam, LPARAM lParam );
void On_WM_LBUTTONDOWN( HWND hDlg, WPARAM wParam, LPARAM lParam );
void On_WM_LBUTTONUP( HWND hDlg, WPARAM wParam, LPARAM lParam );
void On_WM_MOUSEMOVE( HWND hDlg, WPARAM wParam, LPARAM lParam );
void On_WM_PAINT( HWND hDlg, WPARAM wParam, LPARAM lParam );
void On_WM_SIZE( HWND hDlg, WPARAM wParam, LPARAM lParam );
void On_WM_CLOSE( HWND hDlg, WPARAM wParam, LPARAM lParam );
DECLARE_MESSAGE_HANDLER(COutlinerDlg);
private:
// Tree Root name
LPCWSTR m_strRootName;
// Directory
LPCWSTR m_strDirectory;
// Dialog Dimensions
RECT m_rcDlg;
TV_ITEM m_tvi;
TV_INSERTSTRUCT m_tvinsert; // struct to config out tree control
HTREEITEM m_hTISelected;
HTREEITEM m_hTIParent; // Tree item handle
HTREEITEM m_hTIBefore; // .......
HTREEITEM m_hTIRoot; // .......
HIMAGELIST m_hImageList; // Image list array hadle
bool m_bSelected;
// for drag and drop
HWND m_hTreeDlg;
HTREEITEM m_hTIHitTarget;
TVHITTESTINFO m_tvht;
POINTS m_ptsPos;
bool m_bDragging;
bool m_bVisible;
// for lable editing
HWND m_hEdit;
};
Outliner.cpp:
#include "Outliner.h"
IMPLEMENT_MESSAGE_HANDLER( CBaseDialog, COutlinerDlg )
BEGIN_MESSAGE_MAP( COutlinerDlg )
ADD_MESSAGE_HANDLER( WM_INITDIALOG, &COutlinerDlg::On_WM_INITDIALOG )
ADD_MESSAGE_HANDLER( WM_COMMAND, &COutlinerDlg::On_WM_COMMAND )
ADD_MESSAGE_HANDLER( WM_NOTIFY, &COutlinerDlg::On_WM_NOTIFY )
ADD_MESSAGE_HANDLER( WM_LBUTTONDOWN, &COutlinerDlg::On_WM_LBUTTONDOWN )
ADD_MESSAGE_HANDLER( WM_LBUTTONUP, &COutlinerDlg::On_WM_LBUTTONUP )
ADD_MESSAGE_HANDLER( WM_MOUSEMOVE, &COutlinerDlg::On_WM_MOUSEMOVE )
ADD_MESSAGE_HANDLER( WM_PAINT, &COutlinerDlg::On_WM_PAINT )
ADD_MESSAGE_HANDLER( WM_CLOSE, &COutlinerDlg::On_WM_CLOSE )
END_MESSAGE_MAP( )
COutlinerDlg::COutlinerDlg( int nResId, HWND hParent ) : CBaseDialog( nResId, hParent )
{
ENABLE_MESSAGE_MAP( );
m_hTISelected = m_hTIParent = m_hTIBefore = m_hTIRoot = m_hTIHitTarget = NULL;
m_hImageList = NULL;
m_bSelected = m_bDragging = false;
m_bVisible = true;
m_hTreeDlg = NULL;
ZeroMemory( &m_tvi, sizeof( TV_ITEM ) );
ZeroMemory( &m_tvinsert, sizeof( TV_INSERTSTRUCT ) );
ZeroMemory( &m_tvht, sizeof( TVHITTESTINFO ) );
ZeroMemory( &m_ptsPos, sizeof( POINTS ) );
}
COutlinerDlg::~COutlinerDlg( )
{
m_hWindow = NULL;
m_lSaveThis = 0;
}
void COutlinerDlg::On_WM_INITDIALOG( HWND hDlg, WPARAM wParam, LPARAM lParam )
{
...
}
这段代码来自我在代码项目中发现的一个演示,我想。。。
我是否可以实例化基类,以便在声明大纲视图的新实例时不会覆盖静态LONG?
即使实例化基类,static long m_lSaveThis;
在实例化新大纲视图时仍会更改其值。
原因:由于m_lSaveThis
是静态的,所以它在内存中只有一个副本,并且基类构造函数m_lSaveThis = (long)this;
中的此代码将为CBaseDialog或COutlinerDlg的每个实例调用,因为COutlineerDlg继承自CBase Dialog,因此它也调用其构造函数。使用此代码,m_lSaveThis
将只指向您创建的最新实例,无论是基类还是派生类
这里使用的是static long m_lSaveThis
,因此静态声明对于类的所有实例都是通用的(它是类级别,而不是实例级别)。那么,为什么要使用静态呢?我认为如果你声明m_lSaveThis
没有静态,你的要求可以达到。
protected:
long m_lSaveThis;
CBaseDialog::CBaseDialog(int nResId, HWND hParent)
{
m_lSaveThis = (long)this;
}
这里有我的代码,声明一个静态映射对象来处理类实例和窗口句柄。下面的头文件显示了示例代码:
CDialogBase
{
...
static BOOL CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static std::map<HWND, CDialogBase*> m_mapInstance;
}
并像这样实现DialogProc:
BOOL CALLBACK CDialogBase::DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
CDialogBase * pThis = NULL;
std::map<HWND, CDialogBase*>::iterator it = m_mapInstance.find(hwnd);
if (it != m_mapInstance.end())
{
pThis = m_mapInstance[hwnd];
}
switch (msg)
{
case WM_INITDIALOG:
{
if (pThis != NULL)
{
m_mapInstance.erase(hwnd);
pThis = NULL;
}
if (lParam == NULL)
{
return FALSE; //Should start dialog by DialogBoxParam and lParam must not be null.
}
pThis = (CDialogBase*)lParam;
m_mapInstance.insert(std::map<HWND, CDialogBase*>::value_type(hwnd, pThis));
pThis->OnInitDialog();
}
break;
case WM_DESTROY:
{
if (pThis != NULL)
{
pThis->OnDestroy();
m_mapInstance.erase(hwnd);
}
}
default:
break;
}
if(pThis != NULL)
return pThis->OnDefaultDialogProc(msg, wParam, lParam); //Must implement this function and default return FALSE.
else
return FALSE;
}
并且,显示对话框:
UINT CDialogBase::DoModal(HINSTANCE hInst, HWND hParent, UINT nDlgID)
{
m_nDialogResourceID = nDlgID;
return ::DialogBoxParam(hInst, MAKEINTRESOURCE(nDlgID),
hParent, DialogProc, (LPARAM) this);
}
我希望这对你有帮助。
相关文章:
- C++/Win32 构造函数不使用从对话框获取的字符串初始化变量
- 在 Win32 应用中,如果未选择文件夹并且用户单击"确定",则文件夹选择对话框将关闭
- 在DLL中关闭Win32对话框时(来自WPF应用程序)时例外
- 如何使用C Win32 API在登录对话框中显示最后一个登录用户名
- 以程序方式关闭对话框-win32
- Win32 API 检查当前窗口是对话框还是普通窗口
- 如何查找 win32 对话框绘图挂起的原因
- 如何在 Win32 API 的对话框中显示自定义消息
- 关闭对话框时,Win32 应用程序将立即退出
- 使用Richedit控件时,基于对话框的Win32 API程序将不会显示窗口
- Win32 C++资源对话框更改中的字体
- Win32“浏览文件夹”对话框:用户创建新文件夹时返回错误的文件夹
- 从资源生成的C++/Win32 对话框行为不正常
- 来自非托管 win32 dll 的 C# 运行对话框
- 我如何在Win32中使用对话框资源
- c++ win32为对话框添加一个超链接
- 在没有MFC的win32中保存/打开公用对话框
- Win32 API从带有两个组合框的对话框中读取组合框值
- 当我在win32项目c++应用程序中单击菜单项时,如何编写代码来加载一个特殊的对话框?
- Win32 API:打开对话框窗口后应用程序冻结