Changing WinProcs

I'm trying to change the winproc while a program is running, I have it set to do this when the user clicks the mouse so I can test it, but nothing happens, any tips?

1
2
3
	case WM_LBUTTONDOWN:
		SetWindowLongPtr(hwnd,GWLP_WNDPROC,(long) countdown);//countdown is the new winproc
		return 0;


is the problem that the new winproc doesn't receive a WM_CREATE message?

Also, if I do this are all the static variables from the first winproc still in play, or are all of those variables out of range/deallocated?
Last edited on
Here is a complete example in PowerBASIC syntax Newbieg. It would be nearly indistinguisable in C/C++. It is an example of subclassing an edit control. Note first of all, I've declared a global variable fnOldEdit which I'm using to receive the return value from SetWindowLong(). You are not doing that, I see. Why do you need the return? Because you need to call that address from your subclass proc countdown. See CallWindowProc() in my subclass EditProc....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
'SimplestSubClass.bas
#Compile Exe
$Dim All
#Include "Win32Api.inc"
%IDC_TEXT1=%WM_USER + 1
Global fnOldEdit As Long


Function EditProc(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  If wMsg=%WM_CHAR Then
     If Lowrd(wParam) < 48 Or Lowrd(wParam) > 57 Then
        wParam=0
     End If
  End If

  EditProc=CallWindowProc(fnOldEdit, hWnd, wMsg, wParam, lParam)
End Function


Function WndProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
  Local hEdit As Dword
  Local hIns As Long

  Select Case wMsg
    Case %WM_CREATE
      hIns=GetModuleHandle(CurDir$ & "\SimplestSubClass.exe")
      hEdit=CreateWindow("edit","",%WS_CHILD Or %WS_VISIBLE Or %WS_BORDER Or %ES_RIGHT,25,40,200,25,hWnd,%IDC_TEXT1,hIns,0)
      fnOldEdit=SetWindowLong(hEdit,%GWL_WNDPROC,CodePtr(EditProc))
      WndProc=0
      Exit Function
    Case %WM_CLOSE
      Call PostQuitMessage(%NULL)
      WndProc=0
      Exit Function
  End Select

  WndProc=DefWindowProc(hWnd, wMsg, wParam, lParam)
End Function


Function WinMain(ByVal hIns As Long, ByVal hPrev As Long,ByVal lpCL As Asciiz Ptr, ByVal iShow As Long) As Long
  Local szAppName As Asciiz*16
  Local winclass As WndClassEx
  Local hWnd As Dword
  Local Msg As tagMsg

  szAppName="SubClass"                                   : winclass.cbSize=SizeOf(winclass)
  winclass.style=%CS_HREDRAW Or %CS_VREDRAW              : winclass.lpfnWndProc=CodePtr(WndProc)
  winclass.cbClsExtra=0                                  : winclass.cbWndExtra=0
  winclass.hInstance=hIns                                : winclass.hIcon=LoadIcon(%NULL,ByVal %IDI_APPLICATION)
  winclass.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW)   : winclass.hbrBackground=GetStockObject(%LTGRAY_BRUSH)
  winclass.lpszMenuName=%NULL                            : winclass.lpszClassName=VarPtr(szAppName)
  winclass.hIconSm=LoadIcon(hIns, ByVal %IDI_APPLICATION)
  Call RegisterClassEx(winclass)
  hWnd=CreateWindowEx(0,szAppName,szAppName,%WS_OVERLAPPEDWINDOW,200,100,260,175,0,0,hIns,ByVal 0)
  Call ShowWindow(hWnd,iShow)
  Call UpdateWindow(hWnd)
  While GetMessage(Msg,%NULL,0,0)
    Call TranslateMessage(Msg)
    Call DispatchMessage(Msg)
  Wend

  Function=msg.wParam
End Function 


In terms of the visibility of statics declared in the original WndProc, they will not be visible from the subclass proc. In terms of why no WM_CREATE, the window has already been created apparently, and a window gets only 1 WM_CREATE. Sorry about posting a PowerBASIC program, but that was the 1st one I found.
Last edited on
Found almost the same program in one of my old Dev-C++ directories ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <windows.h>
#define IDC_TEXTBOX  1200
WNDPROC fnOldEdit;

LRESULT CALLBACK EditProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{
 if(wParam==VK_CONTROL && iMsg==WM_KEYDOWN)
    SendMessage(hwnd,WM_CHAR,65,0);
 
 return CallWindowProc(fnOldEdit, hwnd, iMsg, wParam, lParam);
}

LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
 HINSTANCE hIns;
 HWND hTextBox;
 int iStyle;

 switch (message)
 {
  case WM_CREATE:
    hIns=((LPCREATESTRUCT)lParam)->hInstance;
    iStyle = WS_CHILD | WS_VISIBLE | WS_BORDER;
    hTextBox=CreateWindow("edit",0,iStyle,90,60,50,25,hwnd,(HMENU)(IDC_TEXTBOX),hIns,0);
    fnOldEdit=(WNDPROC)SetWindowLong(hTextBox,GWL_WNDPROC,(LONG)EditProc);
    return 0;
  case WM_CLOSE:
    SetWindowLong(GetDlgItem(hwnd,IDC_TEXTBOX),GWL_WNDPROC,(DWORD)fnOldEdit);
    PostQuitMessage(0);
    return 0;
 }

 return DefWindowProc(hwnd,message,wParam,lParam);
}

int WINAPI WinMain(HINSTANCE hIns,HINSTANCE hPrev,LPSTR lpszArg,int iShow)
{
 char szClassName[]="Form4";
 WNDCLASSEX wincl;
 HWND hMainWnd;
 MSG messages;

 wincl.hInstance         = hIns;
 wincl.lpszClassName     = szClassName;
 wincl.lpfnWndProc       = WndProc;
 wincl.style             = CS_HREDRAW | CS_VREDRAW;
 wincl.cbSize            = sizeof(WNDCLASSEX);
 wincl.hIcon             = LoadIcon(NULL, IDI_APPLICATION);
 wincl.hIconSm           = LoadIcon(NULL, IDI_APPLICATION);
 wincl.hCursor           = LoadCursor(NULL, IDC_ARROW);
 wincl.lpszMenuName      = NULL;
 wincl.cbClsExtra        = 0;
 wincl.cbWndExtra        = 0;
 wincl.hbrBackground     = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
 RegisterClassEx(&wincl);
 hMainWnd=CreateWindow("Form4","Form4",WS_OVERLAPPEDWINDOW,150,200,250,200,0,0,hIns,0);
 ShowWindow(hMainWnd,iShow);
 while(GetMessage(&messages, NULL, 0, 0))
 {
       TranslateMessage(&messages);
       DispatchMessage(&messages);
 }

 return messages.wParam;
}
Last edited on
Thanks Freddie1, there's a lot of new stuff in that code that I'll have to read up on, I didn't even know there was a WNDPROC type like that. I kind of get what's going on, but I'll be doing a lot of studying before I get it all down.
Last edited on
A really, really, really important topic in Win32/64 is function pointers. That is what WNDPROC is, i.e. a function pointer type. Think about it for a moment ... When you set up your WNDCLASSEX struct in WinMain(), you told Windows the address of your Window Procedure - not its name. It is calling into your application through a function pointer address - not a name. When you subclass a Window Procedure, you are simply informing Windows of another number it must call into. And for you app not to GPF, the function signature of all Window Procedures must be the same. The function signature is described as a WNDPROC type. Look it up in the header.
I remember reading about function pointers in one of my C++ books, but it was several months before I even thought of starting to program in windows api, it sounded like a neat idea, but in my head I filed it under "not important" since the book didn't mention why you would want to use it, and I moved on.
Thanks for the tip, I'll brush up on them again.

And thanks again for the code/advise above, now I can set my programs to flip back and forth between wndprocs and I'm expanding almost all of my projects.
I knew I had posted something about using function pointers somewhere, and I found it here ...

http://www.jose.it-berater.org/smfforum/index.php?topic=3391.0

Might be worth checking out.

The thing with function pointers is that to some extent, they were more used in C than C++ because, what the C++ compiler does behind the scenes, so to speak, in creating a class, eliminates a lot of the need for a lot of function pointer work. But since the Windows Api is basically object oriented programming in C rather than C++, you'll see a lot of function pointer based Apis, e.g., subclassing windows with WNDPROC as you've already run into, all the various enumerators, i.e., EnumChildWindows(), etc. As an aside, I see a new post where somebody's lost with EnumChildWindows(). Likely same problem, i.e., doesn't understand function pointers. If you don't understand them, a lot of code is going to look like chinese (to an American!). They do have a wacky syntax and can be downright evil looking in C/C++. In PowerBASIC which I use a lot the syntax is a lot clearer.
Topic archived. No new replies allowed.