Using derived CListCtrl in CListView – Undocumented

If you weren’t satisfied with the answer to this same issue in the previous topic then maybe this one will. However, there is a big risk involved. It uses some undocumented features of MFC and maybe I haven’t got all the angles covered. So use this at your own RISK.

The basic idea to make this work is that we set up a couple of member variable of the CListCtrl class to connect it to the actual control and we funnel the windows messages on to the CListCtrl object. The actual list view control is owned by the CListView derived object and MFC does not allow a single control to be owned by multiple C++ objects.

In the discusssions below, CMyListCtrl is the CListCtrl derived class we want to use in CListVw which is turn is a CListView derived class.

Step 1: Derive a new class from CMyListCtrl

There are two reasons for deriving a new class. First, the CListView derived class needs access to some of the protected members of CListCtrl, so this class declares the CListView derived class as a friend. Second, we override AssertValid(). AssertValid() is defined for debug builds only and our overridden function does nothing. The default version would have asserted since our object is not really in a consistent state as far as MFC is concerned.

class CFriendlyListCtrl : public CMyListCtrl
	CFriendlyListCtrl() {};

#ifdef _DEBUG
	void AssertValid() const {}

	friend class CListVw;

Step 2: Add member variable in CListVw

Add a protected member of the type CFriendlyListCtrl in ClistVw. We will use this object to connect to the list view control and channel the messages to. Use this member whereever you would use GetListCtrl().

	CFriendlyListCtrl m_listctrl;

Step 3: Override OnCreate in CListVw

Override the OnCreate() function. The framework calls this function immediately after the window is created. After calling the base class version we initialize the member variable m_listctrl. We assign the handle of the control to the m_hWnd member. This member is implicitly used by many of the function of a CWnd derived class. The next variable is probably unfamiliar. The m_pfnSuper is a function pointer and it holds the original WndProc of the control before it was sub-classed by MFC. We call the PreSubclassWindow() to make sure that any code in there will be executed.

int CListVw::OnCreate(LPCREATESTRUCT lpCreateStruct)
	if (CListView::OnCreate(lpCreateStruct) == -1)
		return -1;

	m_listctrl.m_hWnd = m_hWnd;
	m_listctrl.m_pfnSuper = m_pfnSuper;

Step 4: Override message handling functions

There are three message handling functions that we have to override. In each of these, if the CListVw class does not handle the message we forward it to the CMyListCtrl class.

BOOL CListVw::PreTranslateMessage(MSG* pMsg)
	if( ! CListView::PreTranslateMessage(pMsg) )
		return m_listctrl.PreTranslateMessage(pMsg);

	return FALSE;

LRESULT CListVw::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
	LRESULT lResult = 0;
	if (!OnWndMsg(message, wParam, lParam, &lResult))
		if( !m_listctrl.OnWndMsg(message, wParam, lParam, &lResult))
			lResult = DefWindowProc(message, wParam, lParam);
	return lResult;

BOOL CListVw::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam,
							LRESULT* pLResult)
	if( !CListView::OnChildNotify(message, wParam, lParam, pLResult) )
		return m_listctrl.OnChildNotify(message, wParam, lParam, pLResult) ;

	return FALSE;

More by Author

Must Read