0

我有三个类... 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 )
{
...
}

这段代码来自我在代码项目中在线找到的一个演示,我认为......

我可以实例化基类,以便在声明 Outliner 的新实例时不会覆盖静态 LONG 吗?

4

3 回答 3

2

即使你实例化了基类,static long m_lSaveThis;当你实例化一个新的 Outliner 时它的值仍然会改变。

原因:由于m_lSaveThis是静态的,它在内存中只有一个副本,并且您的 Base 类构造函数中的这段代码 m_lSaveThis = (long)this;将为 CBaseDialog 或 COutlinerDlg 的每个实例调用,因为 COutlinerDlg 从 CBaseDialog 继承,因此它也调用其构造函数。使用此代码,m_lSaveThis将仅指向您创建的最新实例,无论是基类还是派生类

于 2013-02-22T02:53:24.170 回答
0

在这里,您使用的static long m_lSaveThis静态声明对于类的所有实例都是通用的(它是类级别而不是实例级别)。那么为什么要使用静态呢?我认为如果您声明m_lSaveThis没有静态,您的要求可以达到。

protected:
  long m_lSaveThis;

CBaseDialog::CBaseDialog(int nResId, HWND hParent)
{
  m_lSaveThis = (long)this; 
}
于 2013-02-22T02:13:19.653 回答
0

有我的代码,声明一个静态地图对象来处理类实例和窗口句柄。下面的头文件显示了示例代码:

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);
}

我希望这对你有帮助。

于 2018-02-02T08:06:09.967 回答