Window handle of listview becomes unusable after subclassing

时间:2015-05-24 21:07:38

标签: c winapi

In one of my c winapi applications I have the following lines:

(1) ListView_SetImageList(hwnd_listview, himagelist, LVSIL_SMALL);

(2) SetWindowLong(hwnd_listview, GWL_WNDPROC, (LPARAM) ListViewWndproc);

(3) ListView_GetBkColor(hwnd_listview);

After command 2 (SetWindowLong) - subclassing - the handle (hwnd_listview) becomes unusable. The application crashes with command 3.

(The application runs on Windows Server 2003.)

Is this normal?

What can I do to retain the handle?

Thanks a lot in advance.

Edit:

Thanks for the link - IInspectable - I cannot use the new method since my application is ansi.

@JosephH: The ListViewWndproc is pretty long. Why should it be relevant in this case?

LRESULT CALLBACK ListViewWndproc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)   
{
  switch (msg) {
    case WM_CREATE:
      ...
      break;
    case WM_KEYDOWN:
      switch (wParam) {
        case 0x4E: 
          ...
          break;
      }
      break;
    case WM_MOUSEMOVE:
      ...
      break;
    case WM_LBUTTONDOWN:
      ...
      break;
    case WM_RBUTTONDOWN:
      ...
      break;
    case WM_LBUTTONDBLCLK:
      ...
      break;
    case WM_COMMAND:
      if (HIWORD (wParam) == CBN_SELCHANGE) {
        ...
      }
      else if (HIWORD (wParam) == CBN_SELENDCANCEL) {
        ...
      }
      else {
        ...
        }
      }
      break;
    case WM_NOTIFY:
      lpNmHdr = (LPNMHDR) lParam;
      if (lpNmHdr->code == MCN_SELECT) {
        ...
      }
      break;
  }
  return CallWindowProc(self->OldListViewWndproc, hwnd, msg, wParam, lParam);
}

Dr. Watson Log says: Exception number: c0000005 (access violation)

When I log each call to the new windows procedure I get one entry with the msg number 4127!??

Now I see the problem:

In the window procedure of my main application window I need a certain pointer (self). I get this value by this:

case WM_CREATE:
      cs   = (CREATESTRUCT*) lParam;
      self =  cs->lpCreateParams;      
  break;

In the window procedure of the subclassed listview I also need this pointer. So I just "copied" the lines and forgot that in the case of the listview I subclass an existing listview so this code (WM_CREATE) never gets executed.

But what is - in this case the best way to get the pointer into the window procedure of the listview?

I searched and found it: I need global subclassing.

In step 1 I create a hidden listview in order to get a listview handle.

Then I call the following to do global subclassing:

self->OldListViewWndproc = (WNDPROC) SetClassLong(hwnd_listview, GCL_WNDPROC, (LONG) ListViewWndproc);

Now I can create the "real" listview widget and I can pass the "self" value to the window procedure in the same way as with the main window.

0 个答案:

没有答案