Class`成员不知何故不情愿地改变

Posted

技术标签:

【中文标题】Class`成员不知何故不情愿地改变【英文标题】:Class` member changes unwillingly somehow 【发布时间】:2011-05-08 16:23:35 【问题描述】:

我创建了以下两个 CDialog 类,用于从模板创建对话框窗口,以及一个从 CDialog 派生的 CMainDialog 类,并且有一些方法可以操作对话框上的控件。

class CDialog
    
    public:
        CDialog(DWORD dwTemplate) : m_dwTemplateID(dwTemplate), m_hWnd(NULL) ;
        virtual ~CDialog() ;

        static INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

        virtual BOOL Create(HINSTANCE hInstance, HWND hParent = NULL);

        BOOL Show(BOOL bShow);
    private:
        DWORD m_dwTemplateID;

    protected:
        HWND m_hWnd;
        virtual INT_PTR HandleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    ;

//基础对话框实现

#include "BaseDialog.h"

//statics

INT_PTR CALLBACK Inc::CDialog::DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

    Inc::CDialog* pDialog = nullptr;

    if(uMsg == WM_INITDIALOG)
    
        //save address of the CDialog-object into the dialog´s userdata
        pDialog = (Inc::CDialog*)lParam;
        SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pDialog);
    
    else
    
        //get the pointer
        pDialog = (Inc::CDialog*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
    

    if(pDialog)
    
        //handle messages
        return pDialog->HandleMessages(hWnd, uMsg, wParam, lParam);
    

    return FALSE;       //!pDialog


INT_PTR Inc::CDialog::HandleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

    switch(uMsg)
    
    case WM_CLOSE:
            DestroyWindow(m_hWnd);
        return TRUE;
    case WM_DESTROY:
            PostQuitMessage(0);
            return TRUE;
    ;

    return FALSE;       //Message not handled => system will take action


BOOL Inc::CDialog::Create(HINSTANCE hInstance, HWND hParent)

    m_hWnd = CreateDialogParam(hInstance, MAKEINTRESOURCE(m_dwTemplateID), hParent, DialogProc, (LPARAM)this);
    if(m_hWnd == NULL)
        return FALSE;

    return TRUE;


//return values: TRUE => window was previously visible, FALSE otherwise
BOOL Inc::CDialog::Show(BOOL bShow)

    if(bShow)
        return ShowWindow(m_hWnd, SW_SHOWNORMAL);
    return ShowWindow(m_hWnd, SW_HIDE);

//CMainDialog

class CMainDialog :
        public Inc::CDialog
    
    public:
        CMainDialog(DWORD dwTemplateID);
        virtual ~CMainDialog(void);

        virtual INT_PTR HandleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

    private:
        static const char m_szDates[8][14];

        //Dialog control item
        HWND m_hDateComboBox;
        HWND m_hItemListBox;
        HWND m_hDescriptionEditBox;
        HWND m_hButtonClose;
        HWND m_hButtonSave;
        HWND m_hButtonDelete;

        //get save the control item handles
    public:
        void GetControlHandles();
    public:
        void PopulateDateComboBox();
    ;

//CMain对话框实现

#include "MainDialog.h"
#include <WindowsX.h>
#include "resource.h"
#include <stdexcept>

//statics
const char Inc::CMainDialog::m_szDates[8][14] = "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "Single Event";

Inc::CMainDialog::CMainDialog(DWORD dwTemplateID) : CDialog(dwTemplateID)




Inc::CMainDialog::~CMainDialog(void)



//adds the entries in m_szDates to the Combo Box for choosing the date
void Inc::CMainDialog::PopulateDateComboBox()

    for(unsigned short s = 0; s < 8; s++)
    
        if(ComboBox_AddString(m_hDateComboBox, m_szDates[s]) <= CB_ERR)
            throw(std::runtime_error("ComboBox_AddString() failed"));
    


INT_PTR Inc::CMainDialog::HandleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

    switch(uMsg)
    
    case WM_INITDIALOG:
            this->GetControlHandles();    // It happens here !!!!!!! <====
            this->PopulateDateComboBox();
        return TRUE;
    

    return Inc::CDialog::HandleMessages(hWnd, uMsg, wParam, lParam);        //if message isnt handled here, default handling


void Inc::CMainDialog::GetControlHandles()

    //Get Control window handles
    m_hDateComboBox = GetDlgItem(m_hWnd, IDC_COMBO_DAY);
    m_hItemListBox = GetDlgItem(m_hWnd, IDC_LIST);
    m_hDescriptionEditBox = GetDlgItem(m_hWnd, IDC_EDIT_DESCRIPTION);
    m_hButtonClose = GetDlgItem(m_hWnd, IDC_BUTTON_CLOSE);
    m_hButtonSave = GetDlgItem(m_hWnd, IDC_BUTTON_SAVE_CHANGE);
    m_hButtonDelete = GetDlgItem(m_hWnd, IDC_BUTTON_DELETE_ITEM);

我遇到的问题是,在 CMainDialog::HandleMessages() 成员函数中,当 WM_INITDIALOG 应该被处理时 m_hWnd 成员是 NULL 即使 CDialog::Create() 函数确实成功并将窗口句柄返回给 m_hWnd。

CDialog::DialogProc-procedure 似乎以某种方式工作,它从 WM_INITDIALOG 的 LPARAM 获取正确的地址并让 pDialog 指针指向到正确的对象并调用它的成员函数。

也许你会看到我错过了什么或做错了什么。

提前谢谢你

【问题讨论】:

【参考方案1】:

您的 WM_INITDIALOG 消息在调用 CreateDialog 期间被处理,而对 m_hWnd(CreateDialog 的结果)的分配在 CreateDialog 结束后完成。

解决方法:将 hWnd 传递给 GetControlHandle(HWND hWnd) 或在 Base 类的 WM_INITDIALOG 中设置 m_hWnd。

【讨论】:

【参考方案2】:

解决此问题的方法是在处理WM_INITDIALOG 时添加pDialog-&gt;m_hWnd = hWnd;

if(uMsg == WM_INITDIALOG)

    //save address of the CDialog-object into the dialog´s userdata
    pDialog = (Inc::CDialog*)lParam;
    SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pDialog);
    pDialog->m_hWnd = hWnd;

这可确保在调用 HandleMessage 之前设置 m_hWnd

【讨论】:

以上是关于Class`成员不知何故不情愿地改变的主要内容,如果未能解决你的问题,请参考以下文章

const成员函数总结

为啥要返回对小类成员的 const 引用?

静态成员 rx 不能在实例类型 UICollectionView 上使用

c++ std::thread 与静态成员挂起

OC-category 为什么不能添加成员变量

无法运行查询给出 mySQL 错误 #1093 - 您无法在 FROM 子句中指定目标表“成员”进行更新 [重复]