头文件
class CBlxDialog
{
public:
CBlxDialog();
virtual ~CBlxDialog();
BOOL Create(HINSTANCE hInstance, UINT uDialogID, UINT uIconId = NULL);
BOOL Destroy();
HWND m_hWnd;
HICON m_hIcon;
protected:
virtual BOOL CALLBACK DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
virtual void OnCommand(WORD wID, WORD wCmdCode);
virtual BOOL OnInitDialog();
virtual void OnClose();
virtual void OnDestroy();
virtual void OnOK();
virtual void OnCancel();
private:
friend BOOL CALLBACK _DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};
CPP文件
CBlxDialog::CBlxDialog()
{
m_hWnd = NULL;
m_hIcon = NULL;
}
CBlxDialog::~CBlxDialog()
{
}
BOOL CALLBACK _DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CBlxDialog *pDlg;
if(uMsg == WM_INITDIALOG)
{
CBlxDialog *pDlg = (CBlxDialog*)lParam;
SetWindowLong(hWnd, GWL_USERDATA, lParam);//<-------------
//在WM_INITDIALOG中取得this指针,将该指针设置到GWL_USERDATA
//这样就完成了对象与窗口过程的关联了,只需要每次获取GetWindowLong一下,即可获得this指针。
//实测双核机器,1秒时间内可以执行1000w+次 pDlg = (CBlxDialog *)GetWindowLong(hWnd, GWL_USERDATA); 所以在效率上的影响是微乎其微的。
pDlg->m_hWnd = hWnd;
return pDlg->OnInitDialog();
}
else
{
pDlg = (CBlxDialog *)GetWindowLong(hWnd, GWL_USERDATA);
}
return pDlg ? pDlg->DlgProc(hWnd, uMsg, wParam, lParam) : FALSE;
}
BOOL CALLBACK CBlxDialog::DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_COMMAND:
OnCommand(LOWORD(wParam), HIWORD(wParam));
return TRUE;
case WM_CLOSE:
OnClose();
return TRUE;
case WM_DESTROY:
OnDestroy();
break;
default:
break;
}
return FALSE;
}
BOOL CBlxDialog::Create(HINSTANCE hInstance, UINT uDialogID, UINT uIconId)
{
//该例子基于资源创建对话框,毕竟对于对话框程序来说,有资源的可视化编辑拖拖拉拉,要比纯靠代码实现的要方便
//uIconId是传入的图标ID,该参数默认为NULL,也就是无图标。
if(uDialogID)
{
if(uIconId)
m_hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(uIconId));
return DialogBoxParamA(hInstance, MAKEINTRESOURCE(uDialogID), NULL, _DlgProc, (LPARAM)this);//<---传入this指针到WM_INITDIALOG中的lParam参数
}
return -1;
}
BOOL CBlxDialog::Destroy()
{
return EndDialog(m_hWnd, 0);
}
BOOL CBlxDialog::OnInitDialog()
{
if(m_hIcon)
{
SendMessage(m_hWnd, WM_SETICON, TRUE, (LPARAM)m_hIcon);
SendMessage(m_hWnd, WM_SETICON, FALSE, (LPARAM)m_hIcon);
}
return TRUE;
}
void CBlxDialog::OnClose()
{
EndDialog(m_hWnd, 0);
}
void CBlxDialog::OnDestroy()
{
}
void CBlxDialog::OnCommand(WORD wID, WORD wCmdCode)
{
if(wID == IDOK)
OnOK();
else if(wID == IDCANCEL)
OnCancel();
}
void CBlxDialog::OnOK()
{
EndDialog(m_hWnd, IDOK);
}
void CBlxDialog::OnCancel()
{
EndDialog(m_hWnd, IDCANCEL);
}
这个类只是基本的封装,只是为了说明可以依靠SetWindowLong和GetWindowLong来进行窗口与类的关联。
另外,该类中声明的友元函数,只是为了让原始对话框消息函数能够访问到类中的protected函数。在该函数中,我并没有依靠参数来传递this指针(废话,消息函数也传不了),所以,可见面向对象的public protected private这几个概念,只是在针对编译器的设定。而除了友元函数,还可以使用静态函数来实现访问,但是静态会被显示到类成员中,所以在这里我选择了友元函数。
最后,对于这个方式,不得不说存在瑕疵,因为存在安全隐患,因为SetWindowLong本身是没有什么权限要求的。