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.