NM_CUSTOMDRAW Failing On ListView

Anne Wilcoxen 46 Reputation points
2022-11-13T00:29:19.97+00:00

Part of my evil plans involve custom-drawing the holy living crap out of a ListView control.
259873-image.png
The ListView on the left works fine; the blue lines come from that pcdListViewDraw->clrTextBk = RGB( 0xE5, 0xF5, 0xFF ); line of code.
But the ListView on the right goes into if ( pcdListViewDraw->nmcd.dwDrawStage == CDDS_PREPAINT ) {, which always returns CDRF_NOTIFYITEMDRAW, but then nothing more.
It never goes into if ( pcdListViewDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT ) {

I’m not sure what else to say about them since there aren’t really any differences. They are both children of main windows, not dialog boxes, so there is no difference in how their return codes are handled. Both have LVS_OWNERDATA and respond to LVN_GETDISPINFOW to draw their texts. I can’t see any reason they would be drawn differently.

The code is simple:

					case NM_CUSTOMDRAW : {  
						LPNMCUSTOMDRAW pcdCustomDraw = reinterpret_cast<LPNMCUSTOMDRAW>(_lParam);  
						CWidget * pmwSrc = LSW_WIN2CLASS( pcdCustomDraw->hdr.hwndFrom );  
						if ( pmwSrc ) {  
							if ( pmwSrc->IsListView() ) {  
								LPNMLVCUSTOMDRAW pcdListViewDraw = reinterpret_cast<LPNMLVCUSTOMDRAW>(_lParam);  
								HWND hFrom = pcdCustomDraw->hdr.hwndFrom;  
								if ( pcdListViewDraw->nmcd.dwDrawStage == CDDS_PREPAINT ) {  
									return CDRF_NOTIFYITEMDRAW;  
								}  
								if ( pcdListViewDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT ) {  
									if ( pcdListViewDraw->nmcd.dwItemSpec % 2 == 0 ) {  
										pcdListViewDraw->clrText = ::GetSysColor( COLOR_WINDOWTEXT );  
										pcdListViewDraw->clrTextBk = RGB( 0xE5, 0xF5, 0xFF );  

										return CDRF_NEWFONT;  
									}  
								}  
							}  
						}  
						return 1;  
					}  

What could cause an evil ListView to go into dwDrawStage == CDDS_PREPAINT, which always returns CDRF_NOTIFYITEMDRAW, and then to not go into dwDrawStage == CDDS_ITEMPREPAINT?

L. Spiro

Windows development | Windows API - Win32
{count} votes

2 answers

Sort by: Most helpful
  1. Anne Wilcoxen 46 Reputation points
    2022-11-13T14:15:32.923+00:00

    The one on the left has the following styles:

    WS_CHILDWINDOW  
    WS_VISIBLE  
    WS_TABSTOP  
    LVS_REPORT  
    LVS_SHOWSELALWAYS  
    LVS_ALIGNLEFT  
    LVS_OWNERDATA  
    LVS_NOSORTHEADER  
      
    WS_EX_LEFT  
    WS_EX_LTRREADING  
    WS_EX_RIGHTSCROLLBAR  
    WS_EX_TRANSPARENT  
    WS_EX_CLIENTEDGE  
    WS_EX_CONTROLPARENT  
    LVS_EX_FULLROWSELECT  
    LVS_EX_DOUBLEBUFFER  
    

    The one on the right has the following styles:

    WS_CHILDWINDOW  
    WS_VISIBLE  
    WS_VSCROLL  
    WS_HSCROLL  
    WS_TABSTOP  
    LVS_REPORT  
    LVS_SHOWSELALWAYS  
    LVS_ALIGNLEFT  
    LVS_OWNERDATA  
      
    WS_EX_LEFT  
    WS_EX_LTRREADING  
    WS_EX_RIGHTSCROLLBAR  
    WS_EX_TRANSPARENT  
    WS_EX_CONTROLPARENT  
    LVS_EX_FULLROWSELECT  
    LVS_EX_DOUBLEBUFFER  
    

    Both are class “SysListView32”.

    L. Spiro


  2. Anne Wilcoxen 46 Reputation points
    2022-11-17T02:28:58.297+00:00

    pcdListViewDraw->nmcd.dwDrawStage is always set to 1 (CDDS_PREPAINT) for the right list view.
    It’s not that I am not catching the correct second value, it simply never comes back into this NM_CUSTOMDRAW section. No matter what I return. I’ve tried ::SetWindowLongPtrW( _hWnd, DWLP_MSGRESULT, CDRF_NOTIFYITEMDRAW ); even though this isn’t a dialog and still nothing.

    Why is this not working?

    L. Spiro

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.