2013-02-22 74 views
0

我有三個類... Base,Derived 1和Derived 2.基類包含一個靜態LONG(this *),它使用靜態函數來處理窗口消息。說我遇到的問題是,當我宣佈多個派生類,靜態LONG基類內於第二派生類的聲明改變了...這裏是實現:實例化基類 - Win32對話框類

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) 
{ 
... 
} 

此代碼是從演示中,我在網上找到的代碼的項目,我想......

我可以實例的基類,這樣我就不會宣佈大綱的新實例時覆蓋靜態多久?

+1

您不應該將'this'強制轉換爲64位版本。使用DWORD_PTR或類似的(或者只是使用CBaseDialog *並避免完全投射)。 – 2013-02-22 02:44:41

+0

這個想法是有一個類來處理win32應用程序中的許多不同的對話框窗口消息 – 2013-02-22 03:36:40

+0

是的我明白,它不會改變你應該存儲指針大小適當的變量的事實:) – 2013-02-22 03:43:35

回答

2

即使你實例化基類中,static long m_lSaveThis;仍然會當你實例化一個新大綱改變其值。

原因: 因爲,m_lSaveThis是靜態的,它只有一個在內存中拷貝,並在基類構造函數m_lSaveThis = (long)this;這個代碼將被調用的CBaseDialog或COutlinerDlg的每一個實例,因爲COutlinerDlg從CBaseDialog繼承所以它也調用它的構造函數。使用此代碼,m_lSaveThis只會指向您創建的最新實例,無論是基類還是派生類

0

這裏您使用的是static long m_lSaveThis,所以靜態聲明對於類的所有實例(它是類級別而非實例級別)是通用的。那麼爲什麼你使用靜態?我認爲你的要求可以達到,如果你宣佈m_lSaveThis沒有靜態。

protected: 
    long m_lSaveThis; 

CBaseDialog::CBaseDialog(int nResId, HWND hParent) 
{ 
    m_lSaveThis = (long)this; 
} 
+0

static long被用於如此靜態函數指針可以引用它... – 2013-02-22 03:33:46

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

我希望這有助於您。

+0

請在您的代碼中使用英文。 – xskxzr 2018-02-02 08:35:59