Subclassing example in context.

I have been looking around on this sites forums/search and at codeguru, codeproject, google, yahoo, etc for a sample code of subclassing in it's original context. The examples at MSDN http://msdn.microsoft.com/en-us/library/bb773183(VS.85).aspx leave a little to be desired in that how they relate to the rest of the code is lost. I'm programming in c++ from DevC so many of the tutorials are geared torward the VisualC++ and VB crowd do not help.

I'm specifically interested in seeing an actual implementation of SetWindowSubclass() and it's related functions rather than the older way of using SetWindowLong().

Perhaps a generous soul to add an article on the subject?

Thanks,

You can ask on Adv.Win32 api newsgroup :
news://194.177.96.26/comp.os.ms-windows.programmer.win32
where it has often been discussed
(C and C++ code)
Sorry I'm just getting back on this. My cable service was out. I don't have news that I know of. Had it on my old service.

I have been working on getting the code working on my own and have run into a linker problem.
[Linker error] undefined reference to `_Z17SetWindowSubclassP6HWND__PFlS0_jjljmEjm@16'

[Linker error] undefined reference to `_Z15DefSubclassProcP6HWND__jjl@16'

I have included commctrl.h and linked libcomctrl32.a too so I'm miffed.
Are you sure you included them before your (other) files that need them?
I have tried it before the other includes. If it is included before windows.h it is very ugly indeed.
Just a couple of the errors:
128 C:\Dev-Cpp\include\prsht.h `DWORD' does not name a type
129 C:\Dev-Cpp\include\prsht.h `HINSTANCE' does not name a type
130 C:\Dev-Cpp\include\prsht.h expected `;' before "union"
140 C:\Dev-Cpp\include\prsht.h `LPARAM' does not name a type

anywhere after windows.h and the results are the same.
I also had to create function defs for all the functions that were in the includes.

Here is a question.. What includes are needed? MSDN only says that it needs commctrl.h and I beginning to think that they are wrong. Also where is ComCtl32.dll supposed to be? I can't seem to locate it on my system.
I'm running XP sp2 so it HAS to be here right?

I'm deeply trying to refrain from using the old SetWindowLong()
way. I have Petzolds 5th edition and it only shows that method.

cheers,
Hrmm...You could try doing a search for comctl32.dll and see if you have it...did you download this header file from somewhere else?
I searched F3 for comctrl32.dll including hidden/system a couple days ago did and not find it. I don't think that missing dll is my only problem. The header file commctrl.h came with DevC++. MSDN only calls for the one header file but I'm not sure that is correct or perhaps I have a bad library. A known functional piece of code would probably be helpful in getting at what the problem is.
Hm, well I would suggest going and DLing it from where (MS probably)...since IIRC a dll is a precompiled library (which could contain definitions of the functions you need)
As I said, this has been given dozens of times on Win32 api ng, since 1992)
(very, very basic stuff...)
It would probably be very helpful but I don't have newsgroups from my service provider.

firedraco -- I have the comctl32.dll on my system. I just was not able to find it. Searching for comctrl32.dll will not find comctl32.dll .... D'oh!

I'm going to write a simple example program with a single edit control and post the code and the compile log later this evening. Hopefully the code is not too far off course.

thanks for the patience,
Lol, nice...ok, good luck.
Many thanks in advance for everyone's help here.
I'm pretty sure my handling of the handle to the child window is wrong as well as other aspects.
My folly of programming:

My enviroment is XP with SP2
Dev-Cpp 4.9.9.2
libcomctl32.a is linked in the project options


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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <windows.h>
#include <cstdio>

#include <commctrl.h> //for subclassing
// linked libcomctl32.a in the project options

using namespace std;

// for subclass 
DWORD dwRefData;
UINT uIdSubclass;
UINT uMsg;
LRESULT CALLBACK EditControlProc (HWND, UINT, WPARAM, LPARAM, UINT, DWORD);
LRESULT WINAPI DefSubclassProc(HWND,UINT,WPARAM,LPARAM);
typedef LRESULT (CALLBACK *SUBCLASSPROC)( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
BOOL SetWindowSubclass( HWND hwnd, SUBCLASSPROC pfnSubclass, UINT_PTR uIdSubclass, DWORD_PTR dwRefData );


/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "WindowsApp";

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil)

{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);
    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default color as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "Subclass Example",       /* Title Text */
           WS_OVERLAPPEDWINDOW,
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           319,                 /* The programs width */
           120,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nFunsterStil);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        
        HDC      hdc;
        
    switch (message)                  /* handle the messages */
    {
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */

        case WM_COMMAND:

            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
            
        case WM_CREATE:

    SetWindowSubclass(hwnd,EditControlProc,uIdSubclass,dwRefData);

    CreateWindow ( TEXT("edit"), NULL,
             WS_CHILD | WS_VISIBLE |
             ES_AUTOHSCROLL | ES_AUTOVSCROLL,
             5,5,300,18, hwnd, (HMENU) 0,
             ((LPCREATESTRUCT) lParam)->hInstance, //instance handle
             NULL) ;


             return 0 ;

    }
        
        
//----------------------BEGIN Subclass to capture tabs and enter for setfocus---------------------
EditControlProc ( hwnd, uMsg, wParam, lParam, uIdSubclass, dwRefData);
{
    switch (uMsg)
    {
    case WM_CHAR:
         switch (wParam){
                    case 0x09:
                         MessageBox(hwnd,"That was the tab key!", "tab key", MB_OK );
                         //process the tab key
                         break;
        return TRUE;
    } 
    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
//----------------------END Subclass to capture tabs and enter for setfocus---------------------


                       

    return 0;
}
} // I have to add an extra } to make this compile 




Compile Log: Compiler: Default compiler
Building Makefile: "C:\Dev-Cpp\subclassingWIN\Makefile.win"
Executing make clean
rm -f main.o Project1.exe

g++.exe -c main.cpp -o main.o -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include" -ansi

g++.exe main.o -o "Project1.exe" -L"C:/Dev-Cpp/lib" -mwindows ../lib/libcomctl32.a

main.o(.text+0x20e):main.cpp: undefined reference to `_Z15EditControlProcP6HWND__jjljm@24'
main.o(.text+0x219):main.cpp: undefined reference to `SetWindowSubclass(HWND__*, long (*)(HWND__*, unsigned int, unsigned int, long, unsigned int, unsigned long), unsigned int, unsigned long)'
main.o(.text+0x2c1):main.cpp: undefined reference to `_Z15EditControlProcP6HWND__jjljm@24'
main.o(.text+0x324):main.cpp: undefined reference to `_Z15DefSubclassProcP6HWND__jjl@16'
collect2: ld returned 1 exit status

make.exe: *** [Project1.exe] Error 1

Execution terminated
Last edited on
Ok, well "needing" an extra } at the end problem means you are missing one somewhere else <.<;

You are missing a } on the end of WindowProcedure (unless EditControlProc is supposed to be inside there for some reason...Also, you should probably put break; on the end of your cases that don't return (line 99) (you could even put them on the ones that return to be safe, but it's not really needed).
firedraco -- I relocated the } to the end of WindowProcedure() and replaced the break; that I cut out accidentally.
After a full rebuild the compiler throws a probably simple error. I'm looking at the code have not yet seen the problem.

One thing that bugs me is that in the compile log the linking of ../lib/libcomctl32.a is not shown. If I go and check in the
project options it shows up there. On this note I'm looking at
the resources at www.bloodshed.net/dev/ to see if perhaps I can find answer there.

The compiler log is:

Compiler: Default compiler
Building Makefile: "C:\Dev-Cpp\subclassingWIN\Makefile.win"
Executing make clean
rm -f main.o Project1.exe

g++.exe -c main.cpp -o main.o -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include" -ansi

main.cpp:124: error: expected constructor, destructor, or type conversion before '(' token
main.cpp:124: error: expected `,' or `;' before '(' token
main.cpp:125: error: expected unqualified-id before '{' token
main.cpp:125: error: expected `,' or `;' before '{' token

make.exe: *** [main.o] Error 1

Execution terminated
Last edited on
I think you want that function to return an 'int' (BOOL).
I have fixed one of the problems and combed through the code.
Are you referring to line 124 EditControlProc returning an int.
LRESULT CALLBACK for the EditControlProc
http://msdn.microsoft.com/en-us/library/bb776774(VS.85).aspx

The only BOOL declared is SetWindowSubclass().
MSDN calls for a BOOL on http://msdn.microsoft.com/en-us/library/bb762102(VS.85).aspx

Assuming that MS is correct. .. And perhaps a bigger assumption that I have done this correctly.

The remaining errors are:

Compiler: Default compiler
Building Makefile: "C:\Dev-Cpp\subclassingWIN\Makefile.win"
Executing make...
make.exe -f "C:\Dev-Cpp\subclassingWIN\Makefile.win" all
g++.exe -c main.cpp -o main.o -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include" -ansi

g++.exe main.o -o "Project1.exe" -L"C:/Dev-Cpp/lib" -mwindows ../lib/libcomctl32.a

main.o(.text+0x20e):main.cpp: undefined reference to `_Z15EditControlProcP6HWND__jjljm@24'
main.o(.text+0x219):main.cpp: undefined reference to `SetWindowSubclass(HWND__*, long (*)(HWND__*, unsigned int, unsigned int, long, unsigned int, unsigned long), unsigned int, unsigned long)'
collect2: ld returned 1 exit status

make.exe: *** [Project1.exe] Error 1

Execution terminated
> I don't have newsgroups from my service provider.
???

Are you aware that you can use any news server like 194.177.96.26 (nntp.aioe.org) and that all ngs are on http://groups.google.com/ ?
(18 years of archives...)
And don't use Dev cpp (not professional) .
Use VS.NET (Express or other), 100 times better (IDE, debugger, etc)
Last edited on
george135 --> I was not aware of aioe.org or groups.google. :-) Sweet!
There was a time when service providers would not provide newgroups or charged extra. Resource consumption (.binaries. especially) Bandwidth + servers = $. So it became hard to find news servers.

I have been using DevCpp since if does not hide the API. Effort to really learn to program the API. Avoiding MFC for similar reason.

I downloaded VS express month or so ago. Thought I'd install it when I pulled out the remainder of my hair getting DevC to work. :-) My machine is old so I'm not sure it will run okay either.

Thanks for the groups.google. lead.
And don't use Dev cpp (not professional)


!MS != !professional
I installed Visual Studio and tried the code with the same results as devC.
I'm still getting the linker errors.

When I add #pragma comment(lib, "comctl32.lib")
two of the linker errors go away in both VS and DevC.

In Visual Studio the output is:

------ Build started: Project: subclasswindow, Configuration: Debug Win32 ------
Linking...
main.obj : error LNK2019: unresolved external symbol "long __stdcall EditControlProc(struct HWND__ *,unsigned int,unsigned int,long,unsigned int,unsigned long)" (?EditControlProc@@YGJPAUHWND__@@IIJIK@Z) referenced in function "long __stdcall WindowProcedure(struct HWND__ *,unsigned int,unsigned int,long)" (?WindowProcedure@@YGJPAUHWND__@@IIJ@Z)
C:\Documents and Settings\admin\My Documents\Visual Studio 2008\Projects\subclasswindow\Debug\subclasswindow.exe : fatal error LNK1120: 1 unresolved externals
Build log was saved at "file://c:\Documents and Settings\admin\My Documents\Visual Studio 2008\Projects\subclasswindow\subclasswindow\Debug\BuildLog.htm"
subclasswindow - 2 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========


In DevC the compile Log is:

Compiler: Default compiler
Building Makefile: "C:\Dev-Cpp\subclassingWIN\Makefile.win"
Finding dependencies for file: C:\Dev-Cpp\subclassingWIN\main.cpp
Executing make...
make.exe -f "C:\Dev-Cpp\subclassingWIN\Makefile.win" all
g++.exe main.o -o "Project1.exe" -L"C:/Dev-Cpp/lib" -mwindows ../lib/libcomctl32.a

main.o(.text+0x20e):main.cpp: undefined reference to `_Z15EditControlProcP6HWND__jjljm@24'
main.o(.text+0x219):main.cpp: undefined reference to `SetWindowSubclass(HWND__*, long (*)(HWND__*, unsigned int, unsigned int, long, unsigned int, unsigned long), unsigned int, unsigned long)'
collect2: ld returned 1 exit status

make.exe: *** [Project1.exe] Error 1

Execution terminated



FYI: I have been searching for an answer to my question elsewhere and
have found that this thread is at the top of the search engine just behind
the MSDN articles listed earlier in this thread. Info on using this method of
subclassing is very thin. Hoping someone can get this code working as it
appears it would be the only full code example on the net at this time. It would be of benefit to others.
Topic archived. No new replies allowed.