Monday, December 31, 2007

Safe memory deletion

Always Set NULL when delete a memory. Otherwise the program may crash when the variable further referenced.

Example:

delete m_pComboArgs;

m_pComboArgs = NULL;

CBN_SELCHANGE and CBN_CLOSEUP message handler of CComboBox class made conflict

The MFC CComboBox is weird. The CBN_SELCHANGE and CBN_CLOSEUP message handler doesn’t call proper sequence. Sometimes the CBN_CLOSEUP call first time and later CBN_SELCHANGE. It’s made confusion. So carefully write code in those two event handler.

Change Default Dialog Font of CDialog

Sometimes it is desirable to change the default font specified in dialog templates (usually "MS Sans Serif", 8 pts.) at runtime (dynamically). For example, you may want to increase the font size to make it more readable under higher screen resolutions. MFC library contains a class CDialogTemplate, that serves exactly this purpose, but Microsoft has not bothered to include its description in standard MFC reference. This is how you can use this class in your code:

1. Place the following string somewhere in your "StdAfx.h" file:

#include 

2. Override DoModal() function in your dialog class:

int CSimpleDialog::DoModal()

{

CDialogTemplate dlt;

int nResult;

// load dialog template

if (!dlt.Load(MAKEINTRESOURCE(CSimpleDialog::IDD))) return -1;

// set your own font, for example "Arial", 10 pts.

dlt.SetFont("Arial", 10);

// get pointer to the modified dialog template

LPSTR pdata = (LPSTR)GlobalLock(dlt.m_hTemplate);

// let MFC know that you are using your own template

m_lpszTemplateName = NULL;

InitModalIndirect(pdata);

// display dialog box

nResult = CDialog::DoModal();

// unlock memory object

GlobalUnlock(dlt.m_hTemplate);

return nResult;

}

Set Default font to any custom made MFC control

LOGFONT lf;

int nRet = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &lf);

if (nRet)

{

// Set the Default font to the Custom window control

m_hotListCtrl.SetFont(&lf);

}

Wednesday, December 5, 2007

Using TrackMouseEvent to find out when the Mouse Leaves from the Window

Using TrackMouseEvent is pretty simple. When the mouse enters the window you want to track, you call track mouse event telling it to inform you when the mouse leaves. When it does, it will send a WM_MOUSELEAVE message to that window.

Sample code:

// HotEdit.h changes
class CHotEdit : public CEdit
{
protected:
BOOL m_bMouseTracking;
afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);
...
};
// HotEdit.cpp changes
BEGIN_MESSAGE_MAP(CHotEdit, CEdit)
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
END_MESSAGE_MAP()
CHotEdit::CHotEdit()
{
m_bMouseTracking = FALSE;
}
LRESULT CHotEdit::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
m_bMouseTracking = FALSE;
return TRUE;
}
void CHotEdit::OnMouseMove(UINT nFlags, CPoint point)
{
if (!m_bMouseTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize =
sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack =
this->m_hWnd;
  if (::_TrackMouseEvent(&tme))
{
m_bMouseTracking = TRUE;
}
 }

CEdit::OnMouseMove(nFlags, point);
}

How to subclass CListBox and CEdit inside of CComboBox

SUMMARY

While it is simple to directly subclass a combo box control, it is not simple to subclass the edit or list box inside a combo box. The problem is that it is difficult to get the HWNDs of the child controls in a portable manner.

One safe way to subclass the internal edit and list box controls is to subclass them in the WM_CTLCOLORXXX messages. Because Win32 sends separate WM_CTLCOLOREDIT and WM_CTLCOLORLISTBOX messages, these messages are safe and easy ways to get the HWNDs of the child controls of the combo box.

Below is a CSuperComboBox class, which is an MFC implementation of this method. Because MFC routes all the WM_CTLCOLOR messages to OnCtlColor, the subclassing takes place there.

MORE INFORMATION

Use ClassWizard to derive a class from CComboBox and add message handlers for WM_CTLCOLOR and WM_DESTROY. Then manually edit the header file to add the data members, m_edit and m_listbox. Finally, copy the code from the message handlers below:

Sample code:

// SuperComboBox.h : header file

class CSuperComboBox : public CComboBox

{

public:

CEdit m_edit;

CListBox m_listbox;

protected:

afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);

afx_msg void OnDestroy();

...

};

// SuperComboBox.cpp : implementation file

HBRUSH CSuperComboBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)

{

if (nCtlColor == CTLCOLOR_EDIT)

{

// Edit control

if (m_edit.GetSafeHwnd() == NULL)

m_edit.SubclassWindow(pWnd->GetSafeHwnd());

}

else if (nCtlColor == CTLCOLOR_LISTBOX)

{

//ListBox control

if (m_listbox.GetSafeHwnd() == NULL)

m_listbox.SubclassWindow(pWnd->GetSafeHwnd());

}

HBRUSH hbr = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor);

return hbr;

}

void CSuperComboBox::OnDestroy()

{

if (m_edit.GetSafeHwnd() != NULL)

m_edit.UnsubclassWindow();

if (m_listbox.GetSafeHwnd() != NULL)

m_listbox.UnsubclassWindow();

CComboBox::OnDestroy();

}