Take the 2-minute tour ×

It seems that CListCtrl doesn't send mouse up events unless there is a double click.

I've attempted sending the missing message from the mouse down handlers to compensate but that causes other undesirable behavior. Then I thought I could send the message within the mouse move handler to be a bit more accurate by checking state. However these are horrible hacks and apart from being ugly they may not work properly for every possible implementation of derived controls.

If anyone knows why mouse up events are not received I'd be curious. More importantly how do I get the CListCtrl using the LVS_OWNERDATA style to send mouse up messages like every other control?

EDIT: I am aware of LVN_BEGINDRAG, LVN_BEGINRDRAG, etc however in order to use these I would need to prevent WM_LBUTTONDOWN, WM_RBUTTONDOWN, and WM_MOUSEMOVE from going to the parent window or DragDropManager hooked into CWinAppEx/CMDIFrameWndEx so I could make a special one-off case for this control to work with the existing system.

This is because I have a central drag and drop manager which can notify various types of controls when to begin a drag operation, when to end, cancel, change animation, pass display objects for source and target in custom messages, etc. It needs to be flexible enough to have differing way of initiating as well as differing actions depending on the control, the input, the type of items selected or targeted, differing control types including 3D, or even different applications, etc.

share|improve this question
-1 If you have code to share with the community that directly relates to your question, it needs to occur in the body of the question - NOT AS AN ANSWER. It is obviously not a valid answer, or a candidate to be an answer. It makes understanding your question harder, since one does not normally search answers for extra portion of the question. –  Mordachai Oct 27 '11 at 18:43
I moved it to be an answer because no one had any applicable answers that were better and apparently that is the solution I will be going with. –  AJG85 Oct 27 '11 at 20:31
add comment

4 Answers

up vote 2 down vote accepted

For reference here's what I have that works but it's a shameful hack. If no one can come up with anything better than this that's really sad.


#pragma once

// CListCtrlEx
class CListCtrlEx : public CListCtrl

    virtual ~CListCtrlEx();

    bool IsSelected(int index);
    BOOL SelectDropTarget(int item);


    afx_msg void OnStateChanged(NMHDR* pNMHDR, LRESULT* pResult);

    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);

    bool m_lbDown;
    bool m_rbDown;


#include "stdafx.h"
#include "ListCtrlEx.h"

// CListCtrlEx

CListCtrlEx::CListCtrlEx() : m_lbDown(false), m_rbDown(false)




// CListCtrlEx message handlers
void CListCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
    m_lbDown = true;
    CListCtrl::OnLButtonDown(nFlags, point);

void CListCtrlEx::OnRButtonDown(UINT nFlags, CPoint point)
    m_rbDown = true;
    CListCtrl::OnRButtonDown(nFlags, point);

void CListCtrlEx::OnLButtonUp(UINT nFlags, CPoint point)
    m_lbDown = false;
    CListCtrl::OnLButtonUp(nFlags, point);

void CListCtrlEx::OnRButtonUp(UINT nFlags, CPoint point)
    m_rbDown = false;
    CListCtrl::OnRButtonUp(nFlags, point);

void CListCtrlEx::OnMouseMove(UINT nFlags, CPoint point)
    if (m_lbDown && ((nFlags & MK_LBUTTON) == 0))
            MAKEWPARAM(LOWORD(nFlags), HIWORD(nFlags)),
            MAKELPARAM(point.x, point.y));

    if (m_rbDown && ((nFlags & MK_RBUTTON) == 0))
            MAKELPARAM(point.x, point.y));

    CListCtrl::OnMouseMove(nFlags, point);

bool CListCtrlEx::IsSelected(int index)
    return (GetItemState(index, LVIS_SELECTED) & LVIS_SELECTED) != 0;

// highlight drop targets sort of like CTreeCtrl
BOOL CListCtrlEx::SelectDropTarget(int item)
    static int prevHighlight(-1);
    if (item >= 0 && item < GetItemCount())
        if (item != prevHighlight)
            if (prevHighlight >= 0)
                SetItemState(prevHighlight, 0, LVIS_DROPHILITED); // remove highlight from previous target
                RedrawItems(prevHighlight, prevHighlight);

            prevHighlight = item;
            SetItemState(item, LVIS_DROPHILITED, LVIS_DROPHILITED); // highlight target
            RedrawItems(item, item);

            return TRUE;
        for (int i(0); i < GetItemCount(); ++i)
            SetItemState(i, 0, LVIS_DROPHILITED); // un-highlight all
        prevHighlight = -1;

    return FALSE;

void CListCtrlEx::OnStateChanged(NMHDR* pNMHDR, LRESULT* pResult)
// MSDN:
// If a list-view control has the LVS_OWNERDATA style,
// and the user selects a range of items by holding down the SHIFT key and clicking the mouse,
// LVN_ITEMCHANGED notification codes are not sent for each selected or deselected item.
// Instead, you will receive a single LVN_ODSTATECHANGED notification code,
// indicating that a range of items has changed state.


    // redraw newly selected items
    if (pStateChanged->uNewState == LVIS_SELECTED)
        RedrawItems(pStateChanged->iFrom, pStateChanged->iTo);
share|improve this answer
Okay, you're subclassing the CListCtrl - so what is it that is a problem? –  Mordachai Oct 25 '11 at 15:31
Having to fake mouse up messages because by default they aren't sent. –  AJG85 Oct 25 '11 at 15:33
add comment

You don't need those events. The control provides you with everything you need.

From your code I gather that you want to implement drag'n'drop of items in the list control. Instead of hacking together something that won't work anyway and badmouth MS, do it the right way instead:

Handle the LVN_BEGINDRAG notification to start the drag operation.

share|improve this answer
The idea was to have a central drag & drop manager and interfaces for sources and targets so that it works with a 3d view, tree, edit, list, etc using system metrics for SM_CXDRAG and SM_CYDRAG without having write the same logic repeatedly. The CListCtrl is the only place where there is a problem. –  AJG85 Oct 14 '11 at 16:10
for tree control its TVN_BEGINDRAG instead of LVN_BEGINDRAG. Other controls provide similar notifications. –  Stefan Oct 17 '11 at 14:31
I suppose I could make some custom messages and have the controls notify the manager when they want to drag rather than the manager notifying the controls. I think the problem that would remain is that begin drag would need to be on one control while end drag could be on another. –  AJG85 Oct 17 '11 at 16:29
add comment

Can you please go through the following link and let us know if it worked .


You can get an idea from there.

share|improve this answer
Doesn't work NM_CLICK/NM_RCLICK fire on mouse down not on mouse up. This is good for a hit test and to check or modify selection as it's a notification not a mouse event but it is otherwise unrelated. I had found a similar article previously when googling and tried it to no avail. –  AJG85 Oct 25 '11 at 19:12
The problem is that you are not able to received the mouse events. Let me give this a try. –  Sujay Ghosh Oct 26 '11 at 7:22
Yup, I made a seperate test app that just had a dialog with a CListCtrl and found the same behavior. That's kind of how I came up with the hack I'm currently using of synthesizing mouse up messages. –  AJG85 Oct 26 '11 at 15:32
add comment

You may be best served by Stefan's answer....

However, you could hook the CListCtrl's winproc (hell, in MFC you could just subclass the CListCtrl, provide your own virtual WindowProc() and forward / intercept whatever mouse messages you want.

Just use the standard MFC subclass a control mechanic at runtime to "substitute" your class for the standard CListCtrl on whatever dialog or window you wish.

I assume you know how to do that?

share|improve this answer
You seem to have missed the entire problem is that mouse up messages are not sent or received by default behavior. Stefan's answer only works for CTreeCtrl and CListCtrl I need custom controls, 3d views, other applications, etc. –  AJG85 Oct 25 '11 at 15:40
You seem to fail to understand how Win32 works. "CTreeCtrl" doesn't send WM_LBUTTONUP messages - it receives them from the OS. So if you intercept that message directly from the OS, then you cannot miss it. It cannot be hidden. Only if you're relying on some further point in the message chain can it be hidden from you. Your response, and -1, are extremely annoying to someone who's been writing MFC apps for the last 13 years. –  Mordachai Oct 27 '11 at 18:40
add comment

Your Answer


