title: How to Subclass WinAPI ListView to modify its drawing
body: <p>I am trying to create a <code>ListView</code> class that essentially wraps the WINAPI <code>ListView</code> control. I am succeeded in putting everything in the class and subclassing the <code>WNDPROC</code>; however, I cannot figure out how to modify its look. I know that it is possible to us OwnerDraw or CustomDraw, but I believe that these messages are sent to the parent window. I would like to be able to keep all the drawing code within my<code>ListView</code> class without having to catch the message in the parent window and reflect it to the class. Is there a way to essentially hop into the <code>WM_PAINT</code> of the <code>ListView</code> control? I really don't want to (and don't really know how to) write everything from scratch. Here is my list view class:</p>
  <pre><code> //ListView Class 
      #pragma once
      class ListView
      {
      private:
          int x, y;
          int w, h;
          int itemCount;
      
          int columnCount;
  
          bool mouseTracking;
      
          HWND listViewHandle;
          HWND parentWindow;
          HFONT lvFont;
      
         
          static LRESULT CALLBACK listViewProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
      public:
          ListView();
      
          BOOL Create(HWND parentWND, int xPos, int yPos, int width, int height, DWORD styles, HINSTANCE hInstance, HMENU hMenu);
      
          void SetPosition(int xPos, int yPos, int width, int height);
          void SetColumnWidth(int index, int width);
      
          BOOL CreateColumn(int width, int index);
          BOOL InsertItems(int numItems);
          BOOL ClearItems();
          BOOL EraseItem(int index);
      
      
          //getters &amp; setters
          BOOL SetFont(HFONT font);
      
          inline int getX() { return x; }
          inline int getY() { return y; }
          inline int getW() { return w; }
          inline int getH() { return h; }
          inline int getItemCount() { return itemCount; }
          inline int getColumnCount() { return columnCount; }
          inline HWND getHendle() { return listViewHandle; }
          inline HWND getParentHandle() { return parentWindow; }
      
      };
  
  
  ListView::ListView()
  : mouseTracking(false)
  {}
  
  //TO CONSIDER: Do I want all these arguments? Even X, Y, W, &amp; H?
  BOOL ListView::Create(HWND parentWND, int xPos, int yPos, int width, int height, DWORD styles, HINSTANCE hInstance, HMENU hMenu)
  {
      parentWindow = parentWND;
      x = xPos;
      y = yPos;
      w = width;
      h = height;
  
      //CreateListView
      listViewHandle = CreateWindow(WC_LISTVIEW, L&quot;&quot;, styles, x, y, w, h, parentWindow, hMenu, hInstance, NULL);
  
      SetWindowSubclass(listViewHandle, listViewProc, 0, (DWORD_PTR)this);
  
      if (listViewHandle)
              return TRUE;
          return FALSE;
      }
      
      void ListView::SetPosition(int xPos, int yPos, int width, int height)
      {
          x = xPos;
          y = yPos;
          w = width;
          h = height;
          SetWindowPos(listViewHandle, HWND_TOP, xPos, yPos, width, height, SWP_SHOWWINDOW);
      }
      
      
      LRESULT CALLBACK ListView::listViewProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
      {
      ListView* listView = reinterpret_cast&lt;ListView*&gt;(dwRefData);
      
          switch (message)
          {
          case WM_MOUSEHOVER:
          {
              OutputDebugStringA(std::to_string(LOWORD(lParam)).c_str());
              OutputDebugStringA(&quot; , &quot;);
              OutputDebugStringA(std::to_string(HIWORD(lParam)).c_str());
              OutputDebugStringA(&quot;\n&quot;);
              return 0;
          }
      
          case  WM_MOUSEMOVE:
              if (!listView-&gt;mouseTracking)
              {
                  // start tracking if we aren't already
                  TRACKMOUSEEVENT tme;
                  tme.cbSize = sizeof(TRACKMOUSEEVENT);
                  tme.dwFlags = TME_HOVER | TME_LEAVE;
                  tme.hwndTrack = hWnd; //This is the handle to the ListView window
                  tme.dwHoverTime = HOVER_DEFAULT;
                  listView-&gt;mouseTracking = TrackMouseEvent(&amp;tme);
              }
              break;
          case  WM_MOUSELEAVE:
              listView-&gt;mouseTracking = FALSE;
              break;
          case WM_NOTIFY:
              switch (((LPNMHDR)lParam)-&gt;code)
              {
              case NM_CUSTOMDRAW:
                  OutputDebugStringA(&quot;CUSTOM DRAW\n&quot;);
                  break;
              }
              break;
          }
      return DefSubclassProc(hWnd, message, wParam, lParam);
  }
  
  
  void ListView::SetColumnWidth(int index, int width)
  {
      SendMessage(listViewHandle, LVM_SETCOLUMNWIDTH, index, width);
  }
  
  BOOL ListView::CreateColumn(int width, int index)
  {
      LVCOLUMN lvc;
      lvc.mask = LVCF_FMT | LVCF_WIDTH  | LVCF_SUBITEM;
      // Initialize LVITEM members that are common to all items.
  
      // Initialize LVITEM members that are different for each item.
      lvc.iSubItem = 0;
      lvc.cx = 200;
      // Insert items into the list.
      if (ListView_InsertColumn(listViewHandle, index, &amp;lvc) == -1)
          return FALSE;
      return TRUE;
  }
  BOOL ListView::InsertItems(int numItems)
  {
      itemCount += numItems;
  
      LVITEM lvI;
      // Initialize LVITEM members that are common to all items.
      lvI.pszText = LPSTR_TEXTCALLBACK; //This should send an LVN_GETDISPINFO message
      lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
      lvI.stateMask = 0;
      lvI.iSubItem = 0;
      lvI.state = 0;
  
      // Initialize LVITEM members that are different for each item.
      for (int index = 0; index &lt; numItems; index++)
      {
          lvI.iItem = index;
          lvI.iImage = index;
  
          // Insert items into the list.
          if (ListView_InsertItem(listViewHandle, &amp;lvI) == -1)
              return FALSE;
      }
      return TRUE;
  }
  
  BOOL ListView::ClearItems()
  {
      for (int i = itemCount; i &gt;= 0; i--)
      {
          ListView_DeleteItem(listViewHandle, i);
      }
      itemCount = 0;
      return TRUE;
  }
  
  BOOL ListView::EraseItem(int index)
  {
      ListView_DeleteItem(listViewHandle, index);
      itemCount--;
      return TRUE;
  }
  
  BOOL ListView::SetFont(HFONT font)
  {
      return SendMessage(listViewHandle, WM_SETFONT, (WPARAM)font, TRUE);
  }
  </code></pre>