VS 2010 - SubClass - FromHandlePermanent Assert
-
Trying to subclass a combobox i order to have the entries have a tab stop. When I perform the subclass I get an assert. This code use to work in the early days of MFC but with 2010 it fails. I did not try it with any VS version in between. Is it something very simple I'm missing? Thanks
class CTabCBox : public CComboBox
{
public:
CTabCBox() {icTab=0; lpiTab=NULL;}
~CTabCBox() {if (lpiTab) free(lpiTab);}// subclassed construction BOOL SubclassCBox(UINT nID,CWnd\* pParent,int icTabs,LPINT lpiTabs);
protected:
int icTab; // count of tab stops
LPINT lpiTab; // tab stops in logical unitsvirtual void MeasureItem(LPMEASUREITEMSTRUCT lpMis); virtual void DrawItem(LPDRAWITEMSTRUCT lpDis);
};
// CtestDlg dialog
class CtestDlg : public CDialogEx
{
// Construction
public:
CtestDlg(CWnd* pParent = NULL); // standard constructor// Dialog Data
enum { IDD = IDD_TEST_DIALOG };protected: virtual void DoDataExchange(CDataExchange\* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;// Generated message map functions virtual BOOL OnInitDialog(); afx\_msg void OnSysCommand(UINT nID, LPARAM lParam); afx\_msg void OnPaint(); afx\_msg HCURSOR OnQueryDragIcon(); DECLARE\_MESSAGE\_MAP()
public:
CTabCBox m_ctrlFontsX;
CComboBox m_ctrlFonts;
};// from INITDIALOG
// TODO: Add extra initialization here
TEXTMETRIC tm;
int iTab;// compute tab stop if (m\_ctrlFonts.GetDC()->GetTextMetrics(&tm)) iTab = (33+8) \* tm.tmAveCharWidth; m\_ctrlFontsX.SubclassCBox(IDC\_COMBO1,this,1,&iTab); CString csS("Font title string\\tnnnnnnnn"); m\_ctrlFontsX.AddString(csS);
BOOL CTabCBox::SubclassCBox(UINT nID, CWnd* pParent, int icTabs, LPINT lpiTabs)
{
DWORD dwcb;
int iRc = 0;// make very sure all tab members are free and clear if (lpiTab) free(lpiTab); lpiTab = NULL; icTab = 0; if (icTabs>0) { // make copy of tab info dwcb = icTabs\*sizeof(int); if (!(lpiTab = (LPINT)malloc(dwcb))) return(FALSE); memcpy(lpiTab,lpiTabs,(size\_t)dwcb); icTab = icTabs; } iRc = SubclassDlgItem(nID, pParent); // THIS CAUSES THE ASSERT return(iRc);
} // end of SubclassCBox
It always fails on the second assert (FromHandle....) from wincore.cpp
BOOL CWnd::Attach(HWND hWndNew)
{
ASSERT(m_hWnd == NULL); // only attach once, detach on destroy
ASSERT(FromHandlePermanent(hWndNew) == NULL);
// must not already be in permanent mapTony Teveris Gerb
-
Trying to subclass a combobox i order to have the entries have a tab stop. When I perform the subclass I get an assert. This code use to work in the early days of MFC but with 2010 it fails. I did not try it with any VS version in between. Is it something very simple I'm missing? Thanks
class CTabCBox : public CComboBox
{
public:
CTabCBox() {icTab=0; lpiTab=NULL;}
~CTabCBox() {if (lpiTab) free(lpiTab);}// subclassed construction BOOL SubclassCBox(UINT nID,CWnd\* pParent,int icTabs,LPINT lpiTabs);
protected:
int icTab; // count of tab stops
LPINT lpiTab; // tab stops in logical unitsvirtual void MeasureItem(LPMEASUREITEMSTRUCT lpMis); virtual void DrawItem(LPDRAWITEMSTRUCT lpDis);
};
// CtestDlg dialog
class CtestDlg : public CDialogEx
{
// Construction
public:
CtestDlg(CWnd* pParent = NULL); // standard constructor// Dialog Data
enum { IDD = IDD_TEST_DIALOG };protected: virtual void DoDataExchange(CDataExchange\* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;// Generated message map functions virtual BOOL OnInitDialog(); afx\_msg void OnSysCommand(UINT nID, LPARAM lParam); afx\_msg void OnPaint(); afx\_msg HCURSOR OnQueryDragIcon(); DECLARE\_MESSAGE\_MAP()
public:
CTabCBox m_ctrlFontsX;
CComboBox m_ctrlFonts;
};// from INITDIALOG
// TODO: Add extra initialization here
TEXTMETRIC tm;
int iTab;// compute tab stop if (m\_ctrlFonts.GetDC()->GetTextMetrics(&tm)) iTab = (33+8) \* tm.tmAveCharWidth; m\_ctrlFontsX.SubclassCBox(IDC\_COMBO1,this,1,&iTab); CString csS("Font title string\\tnnnnnnnn"); m\_ctrlFontsX.AddString(csS);
BOOL CTabCBox::SubclassCBox(UINT nID, CWnd* pParent, int icTabs, LPINT lpiTabs)
{
DWORD dwcb;
int iRc = 0;// make very sure all tab members are free and clear if (lpiTab) free(lpiTab); lpiTab = NULL; icTab = 0; if (icTabs>0) { // make copy of tab info dwcb = icTabs\*sizeof(int); if (!(lpiTab = (LPINT)malloc(dwcb))) return(FALSE); memcpy(lpiTab,lpiTabs,(size\_t)dwcb); icTab = icTabs; } iRc = SubclassDlgItem(nID, pParent); // THIS CAUSES THE ASSERT return(iRc);
} // end of SubclassCBox
It always fails on the second assert (FromHandle....) from wincore.cpp
BOOL CWnd::Attach(HWND hWndNew)
{
ASSERT(m_hWnd == NULL); // only attach once, detach on destroy
ASSERT(FromHandlePermanent(hWndNew) == NULL);
// must not already be in permanent mapTony Teveris Gerb
Hi Tony, My guess would be that your CtestDlg::DoDataExchange function has a DDX_Control[^] entry for the m_ctrlFontsX member. If I am correct then you should comment it out or remove it. This happens when you right click a control in the VS dialog editor and choose 'Add Variable'. Visual Studio will add a member variable along with a DDX entry in the DoDataExchange function. Essentially what is happening is that MFC has already subclassed the control and added the handle into the internal permanent handle map. Here is an excellent document explaining MFC handles and temporary CWnd* objects: Inside MFC: Handle Maps and Temporary Objects[^] Let me know if I was correct. Best Wishes, -David Delaune