NM_CUSTOMDRAW on Listview
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 7 of 7

Thread: NM_CUSTOMDRAW on Listview

  1. #1
    Join Date
    May 2011
    Posts
    4

    Question NM_CUSTOMDRAW on Listview

    Hi all,

    After being a silent observer for a while I've decided to ask for your help. It seems to me like I've search all the forums in the world for answers and couldn't find...

    I consider myself a newbie in win32, so the fact I couldn't find the answer doesn't say anything about the problem being complex .

    My task is pretty simple - I'm writing a dll to be used with nsis (Nullsoft Scriptable Install System). I want to change the color of specific subitems in a listview.

    I suspect that I'm not getting notifications for the items at all, but only for the titles: let's say I have 4 colums and 10 rows (that is 10 items with 4 subitems each). In the handler I get CDDS_PREPAINT and return CDRF_NOTIFYITEMDRAW then I get 4 CDDS_ITEMPREPAINTs and for each one of them I return CDRF_NOTIFYSUBITEMDRAW, and that's it.

    I also noticed that if instead of returning CDRF_NOTIFYSUBITEMDRAW I change the font and return CDRF_NEWFONT, also nothing is happening (and according to MSDN this should affect all subitems of the item).

    here is the code: http://www.mediafire.com/?pd6tf3p1r269d84
    it's a pack that contains also an nsis file that uses the dll, you need nsis compiler to use it. It also contains an example2.exe which is compiled with a dll in debug mode, so you can attach to it and see the notifications, and hopefully see where is the bug in my code.

    lines 279-344 of URLCtrl:

    LRESULT ProcessCustomDraw (LPARAM lParam)
    {
    LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;

    switch(lplvcd->nmcd.dwDrawStage)
    {
    case CDDS_PREPAINT : //Before the paint cycle begins
    //request notifications for individual listview items
    return CDRF_NOTIFYITEMDRAW;
    break;

    case CDDS_ITEMPREPAINT: //Before an item is drawn
    return CDRF_NOTIFYSUBITEMDRAW;
    break;

    //Before a subitem is drawn
    case (CDDS_ITEMPREPAINT | CDDS_SUBITEM):
    lplvcd->clrText = RGB(255,0,0);
    lplvcd->clrTextBk = RGB(255,255,255);
    return CDRF_NEWFONT;
    break;
    }
    return CDRF_DODEFAULT;
    }

    LRESULT CALLBACK urlctrl_lv_proc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
    { URLCTRLS *urls=(URLCTRLS*)GetWindowLong(hwnd,GWL_USERDATA);
    WNDPROC oldproc=urls->oldproc;
    LRESULT myResult = CDRF_DODEFAULT;
    switch(uMsg)
    { case WM_NOTIFY:
    { switch (((LPNMHDR)lParam)->code)
    { case NM_CUSTOMDRAW:
    { myResult = ProcessCustomDraw(lParam);
    return myResult;
    break;
    }
    }
    break;
    }

    ....
    ....

    }
    return CallWindowProc(oldproc,hwnd,uMsg,wParam,lParam);
    }


    Thanks!

    J

  2. #2
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,526

    Re: NM_CUSTOMDRAW on Listview

    Is your question about custom draw of the list control? Or about integration of your dll with nsis?
    I, for example, can’t get to your code. Not that I would want to compile the installer…
    Could you please isolate your problem? Create a simple app with one list control that does your custom drawing.
    If it doesn’t work – post your app here.
    Good luck!
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinViewer - an integrated GDI objects viewer for Visual C++ Debugger, and more...

  3. #3
    Join Date
    May 2011
    Posts
    4

    Re: NM_CUSTOMDRAW on Listview

    Hi Vladimir,

    First of all - Thanks for the reply. I did manage to isolate the problem and I'm sending a very small piece of code that demonstrate it - I don't get NM_CUSTOMDRAW from the list view.

    I try to add to the listview a url, in this code the subitem 1 of item 1 is a url and opens google.com when I press on it. I want to make its color blue.

    Thanks!
    Attached Files Attached Files

  4. #4
    ovidiucucu's Avatar
    ovidiucucu is offline Moderator/Reviewer Power Poster
    Join Date
    Feb 2003
    Location
    Iasi - Romania
    Posts
    8,023

    Re: NM_CUSTOMDRAW on Listview

    Notifications like NM_CUSTOMDRAW are sent via WM_NOTIFY to the parent of the control and NOT to the control itself.
    What you are receiving in listview control procedure are notifications from its child which is a header control.
    So, in your program you have to catch NM_CUSTOMDRAW in WndProc and not in urlctrl_lv_proc.

    Code:
    LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) 
    {
       //...
       switch (iMsg) 
       {
       case WM_NOTIFY:
          {
             LPNMHDR lpNHMDR = (LPNMHDR)lParam;
             switch(lpNHMDR->code)
             {
             case NM_CUSTOMDRAW:
                {
                   LPNMHDR lpNHMDR = (LPNMHDR)lParam;
                   HWND hWndList = lpNHMDR->hwndFrom;
                   URLCTRLS *urls=(URLCTRLS*)GetWindowLongPtr(hWndList,GWLP_USERDATA);
                   if(lpNHMDR->idFrom == (UINT)urls->idFrom)
                   {
                      // ... got it here!
                      // ...
       //...
    }
    Two additional remarks/advices:
    • Try to write stucture declarations (as well as any other declaration) in header files in order to be accesibile in any sources where is necessary;
    • Try to avoid writing code after '{' brackets; it took me time to re-format your code in order to put brakpoints and see what's going on.


    And finally:
    NMHDR is a general structure which gests very few information.
    In case of handling NM_CUSTOMDRAW for a listview control it's better to cast lParam to LPNMLVCUSTOMDRAW.
    It was not hecessary here for the monent, but never know...
    Last edited by ovidiucucu; May 17th, 2011 at 04:38 AM.
    Ovidiu Cucu
    "When in Rome, do as Romans do."
    Visit: Microsoft Virtual Academy
    Follow: https://twitter.com/#!/ovidiucucu
    My blog: http://codexpert.ro/blog/author/ovidiu-cucu/

  5. #5
    ovidiucucu's Avatar
    ovidiucucu is offline Moderator/Reviewer Power Poster
    Join Date
    Feb 2003
    Location
    Iasi - Romania
    Posts
    8,023

    Re: NM_CUSTOMDRAW on Listview

    One more remark.
    It is not necessary to keep the control ID in that structure (URLCTRLS) which has its address stored in control's user data.
    You know in your program the ID which has been passed to CreateWindowEx.

    All above being said, we can write a little bit better:
    Code:
    LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) 
    {
       //...
       switch (iMsg) 
       {
       case WM_NOTIFY :
          {
             LPNMHDR lpNHMDR = (LPNMHDR)lParam;
             switch(lpNHMDR->code)
             {
             case NM_CUSTOMDRAW:
                {
                   if(ID_LISTVIEW == lpNHMDR->idFrom)
                   {
                      HWND hWndList = lpNHMDR->hwndFrom ;
                      URLCTRL *url=(URLCTRL*)GetWindowLongPtr(hWndList,GWLP_USERDATA);
                      LPNMLVCUSTOMDRAW lpNMCustomDraw = (LPNMLVCUSTOMDRAW)lpNHMDR;;
                      // ... Enjoy!
                      // ...
       //...
    }
    Ovidiu Cucu
    "When in Rome, do as Romans do."
    Visit: Microsoft Virtual Academy
    Follow: https://twitter.com/#!/ovidiucucu
    My blog: http://codexpert.ro/blog/author/ovidiu-cucu/

  6. #6
    Join Date
    May 2011
    Posts
    4

    Talking Re: NM_CUSTOMDRAW on Listview

    hi ovidiucucu,

    Thanks! funny thing is that just 20 minutes before your post I got to the solution myself. I've made another handler for the parent and it worked .

    I really appreciate your tips and your explanation, and I'll try to apply them.

    Thanks again!

    J

  7. #7
    Join Date
    May 2011
    Posts
    4

    Re: NM_CUSTOMDRAW on Listview

    Quote Originally Posted by ovidiucucu View Post
    One more remark.
    It is not necessary to keep the control ID in that structure (URLCTRLS) which has its address stored in control's user data.
    You know in your program the ID which has been passed to CreateWindowEx.

    This is true for the small example but I'm actually writing a dll which adds the ability to change subitems to urls in an already exist listview which I get as hwnd from the caller, so I assumed that I wouldn't know the id of the listview in that case

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center