Multiple Windows Procedure

could someone just give me an example on how to make multiple window procedures? i just cant seem to place it right.
Thanks,
-Austin
Hmmmm. I take it you didn't understand the examples to which I provided a link?
The operative principals are fairly straightforward. You have to have two calls to RegisterClassEx(), each with a different Window Procedure name and WNDCLASSEX::szClassName name.

You can put both RegisterClassEx() calls down in WinMain() if you like, but I usually put my second call in the WM_CREATE handler of my main window.

For ease of seeing what's going on, you can put both Window Procedures in the same code file, say Main.cpp or whatever you have.

To show your second form you just do a CreateWindowEx() call passing in the registered class name of your 2nd form in the szClassName parameter, i.e., the 2nd parameter. I usually use the WS_OVERLAPPEDWINDOW style for main forms.
Last edited on
If you still can't figure it out I'll code the simplest possible example for you.
-A "window procedure" is just a normal function with a well specific signature. It is used not only with RegisterClassEx(), but also with DialogBox(), with different prototypes and return values.
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
#include <windows.h>
#include <tchar.h>
#define IDC_SECOND_SCREEN 1500


LRESULT CALLBACK fnOutputScreen_WndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 switch(msg)
 {
  case WM_CREATE:
    {
       WNDCLASSEX wc;
       HINSTANCE hIns      = ((LPCREATESTRUCT)lParam)->hInstance;
       HWND hWnd           = CreateWindow(_T("button"),_T("Show Output Screen"),WS_CHILD|WS_VISIBLE,95,40,150,25,hwnd,(HMENU)IDC_SECOND_SCREEN,hIns,0);
       TCHAR szClassName[] = _T("OutputScreen");
       wc.lpszClassName    = szClassName;
       wc.lpfnWndProc      = fnOutputScreen_WndProc;
       wc.cbSize           = sizeof(WNDCLASSEX);
       wc.style            = 0;
       wc.hIcon            = LoadIcon(NULL,IDI_APPLICATION);
       wc.hInstance        = hIns;
       wc.hIconSm          = 0;
       wc.hCursor          = LoadCursor(NULL,IDC_ARROW);
       wc.hbrBackground    = (HBRUSH)GetStockObject(WHITE_BRUSH);
       wc.cbWndExtra       = 0;
       wc.lpszMenuName     = NULL;
       wc.cbClsExtra       = 0;
       RegisterClassEx(&wc);
       return 0;
    }
  case WM_COMMAND:
    switch(LOWORD(wParam))
    {
      case IDC_SECOND_SCREEN:
        HWND hWnd=CreateWindowEx(0,_T("OutputScreen"),_T("Output Screen"),WS_OVERLAPPEDWINDOW,350,450,450,450,HWND_DESKTOP,0,GetModuleHandle(NULL),0);
        ShowWindow(hWnd,SW_SHOWNORMAL);
        break;
    }
    return 0;
  case WM_DESTROY:
    {
       PostQuitMessage(0);
       return 0;
    }
 }

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


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int iShow)
{
 TCHAR szClassName[]=_T("Form1");
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 wc.lpszClassName=szClassName,                wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX),               wc.style=0;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION),     wc.hInstance=hInstance;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION),  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW,    wc.cbWndExtra=0;
 wc.lpszMenuName=NULL,                        wc.cbClsExtra=0;
 RegisterClassEx(&wc),
 hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,150,150,350,150,HWND_DESKTOP,0,hInstance,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
 }

 return messages.wParam;
}
Thank you Freddie, that was exactly what i was looking for
But if you dont mind could you explain the <tchar.h> header to me?
Thanks.
But if you dont mind could you explain the <tchar.h> header to me?


Do yourself a favor and don't use TCHARs. They do nothing but complicate things. Using them correctly is a huge pain.

Decide whether or not you want to code with Unicode support, and choose your character type from there.


If you want Unicode support
- Use std::wstring, and wchar_t for characters.
- Call 'W' versions of WinAPI functions (ie: "CreateWindowExW" instead of "CreateWindowEx").
- Use 'W' versions of WinAPI structs (ie: "OPENFILENAMEW" instead of "OPENFILENAME")

If you do not want Unicode support
- Use std::string and char for characters.
- Call 'A' versions of WinAPI functions (ie: "CreateWindowExA" instead of "CreateWindowEx"
- Use 'A' versions of WinAPI structs (ie: "OPENFILENAMEA")



Do not use the "normal" version of WinAPI functions unless they don't have a A/W counterpart. "Normal" versions take TCHARs, and TCHARs are retarded.
Disch wrote:
TCHARs are retarded.
May you explain why? I never Unicode but TCHARS seem to be an useful abstraction - only one line (#define UNICODE) controls the charset used in whole program.

Do yourself a favor and don't use TCHARs. They do nothing but complicate things. Using them correctly is a huge pain.


Might be a good idea for someone just starting out. For me however, I could never accept giving up the function calls I've been using for 16 years, such as CreateWindowEx(), RegisterClassEx(), etc.

There's just no easy way out on this one. Its the cost of doing business in C or C++ I guess!
May you explain why?


Gladly.

1) They're variable size.

A TCHAR can be either 1 or 2 bytes wide. This means you cannot do file IO (or any other IO that doesn't use TCHARs) without first converting. But how can you convert if you don't know what kind of char you have?

WinAPI provides MultiByteToWideChar and vice versa functions... but where's the TCharToWideChar function?

This means that if you're using strings for any IO other than WinAPI function calls you have a whole new can of worms to deal with.

2) They're weak typed and therefore error prone

TCHAR is not its own type but is instead a typedef of either char or wchar_t. This means that code that should give an error or warning doesn't. The classic example:

 
MessageBox( NULL, "example", NULL, MB_OK );


This code is wrong. "example" is not a TCHAR string and therefore should not ever be passed to MessageBox. However this will still compile for some people depending on the UNICODE macro.

Make this slip-up even once, and you entirely defeat the whole point of using TCHARs in the first place.

3) Due to reasons 1 & 2, you can't easily write them into external libraries

If you want to make a dll or something that does string processing, you can't use TCHARs to do it... again because TCHARs are not a real type.

So you either have to do what WinAPI does and write 2 completely different routines (one for wide and one for narrow), or do some other equally asinine workaround.


4) For all the trouble they cost... you gain practically nothing from using them

The only advantage to using TCHARs? Being able to toggle between a Unicode-supporting build and a non-supporting build.

But if you're going through all the work to make it support Unicode with TCHARs... why would you ever do a non-supporting build? What's the point?

If you're going to go through the work to support unicode.. you might as well just do it outright and use wide chars like a sane person.



I get the impression that TCHARs are just legacy crap that MS can't abolish for backward compatibility reasons. I see no other reason for their existence.



freddie1 wrote:
For me however, I could never accept giving up the function calls I've been using for 16 years


If you're unable to change your coding practices after 16 years, that doesn't reflect very well. =P

This field moves and evolves crazy fast. Getting stuck in doing things the same way for long periods of time is really bad.



EDIT: This made it sound like I'm saying you're wrong for using TCHARs. I didn't mean that and I apologize. Please disregard

There's just no easy way out on this one.


Putting a 'A' or 'W' at the end of function calls is pretty freaking easy. ;P
Last edited on
The original poster appears to be a real beginner to Windows programming, who will no doubt rely heavily on the MSDN documentation. All the Microsoft documentation I am aware of regarding Win32 coding specifies either LPCTSTR or LPTSTR for character array parameters, e.g.,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HWND WINAPI CreateWindowEx
(
  _In_      DWORD dwExStyle,
  _In_opt_  LPCTSTR lpClassName,
  _In_opt_  LPCTSTR lpWindowName,
  _In_      DWORD dwStyle,
  _In_      int x,
  _In_      int y,
  _In_      int nWidth,
  _In_      int nHeight,
  _In_opt_  HWND hWndParent,
  _In_opt_  HMENU hMenu,
  _In_opt_  HINSTANCE hInstance,
  _In_opt_  LPVOID lpParam
);


Therefore, I don't believe the TCHAR macros and tchar.h can be so easily dismissed as Disch would like. Further, in order for a beginner to successfully navigate the character encoding morass, and in the end decide to use either the 'A' or 'W' WinApi functions directly instead of the macros, said beginner must study and understand the issues involved, and how Microsoft tried to solve them with the TCHAR macros.

I try to help beginners in this forum, and have found that the TCHAR macros are the best bet when posting code for beginners, in that the function calls will resemble more closely the MSDN documentation they are apt to be using (as well as Petzold's book - if they are using that), and will work regardless of which IDE they have.

So it doesn't appear to me that a beginner has any real choice but to immediately delve into this issue and attempt to understand it fully. Having done that a beginner can decide which route he/she wants to take regarding the tchar macros or the 'A' verses 'W' functions.

All the Microsoft documentation I am aware of regarding Win32 coding specifies either LPCTSTR or LPTSTR for character array parameters


All that documentation also mentions ANSI/Unicode versions of the functions on the same page. e.g.,

MSDN wrote:
Unicode and ANSI names CreateWindowExW (Unicode) and CreateWindowExA (ANSI)


It's very well defined.


Further, in order for a beginner to successfully navigate the character encoding morass, and in the end decide to use either the 'A' or 'W' WinApi functions directly instead of the macros, said beginner must study and understand the issues involved


There is far more to study and understand when using TCHARs because they're far more complicated, and the implications of them are not immediately clear.

Case in point, since TCHAR encompasses both ANSI and Unicode -- to understand TCHARs you must understand both ANSI/Unicode on top of understanding the complications of having a variable type.

Whereas if you just use Unicode forms from the get go, you only have to understand the implications of using Unicode strings. ANSI/Unicode forms are extremely clear and there are minimal hidden implications.

, and how Microsoft tried to solve them with the TCHAR macros.


My understanding for the existence of TCHAR is that it's support for legacy code. Nothing more. If I'm mistaken I would love to hear another explanation and/or an article which goes into the history.


I try to help beginners in this forum, and have found that the TCHAR macros are the best bet when posting code for beginners, in that the function calls will resemble more closely the MSDN documentation they are apt to be using (as well as Petzold's book - if they are using that)


Beginners always get it wrong. I can't tell you how many posts I've replied to on this forum where I had to correct someone because they were writing broken code due to TCHAR mismatching. I've even argued with people who didn't understand that the code was broken because "it's compiling fine, you're just crazy".

In fact here's a couple threads of people misunderstanding/misusing TCHARs that I found from a quick google search. And these are only the threads that I replied in... I know I've passed by at least an equal amount of threads without saying a word.

http://www.cplusplus.com/forum/general/99717/
http://www.cplusplus.com/forum/windows/79761/
http://www.cplusplus.com/forum/general/92220/
http://www.cplusplus.com/forum/windows/32574/
http://www.cplusplus.com/forum/windows/45287/
http://www.cplusplus.com/forum/windows/45112/
http://www.cplusplus.com/forum/windows/98803/
http://www.cplusplus.com/forum/windows/44514/
http://www.cplusplus.com/forum/windows/48654/


As you can see... it's a huge source of confusion and errors for many, many people.

[TCHAR] will work regardless of which IDE they have.


So will ANSI/Unicode strings. The 'A'/'W' thing isn't just a VS-specific implementation... those functions are formally defined in WinAPI. They are as real and as dependable as the TCHAR forms (arguably moreso).

So it doesn't appear to me that a beginner has any real choice but to immediately delve into this issue and attempt to understand it fully.


Immediately delve into? Yes.
Understand fully? No way. That's asking way too much of a beginner. It's hard enough explaining to a beginner what Unicode is, let alone explaining all the subtleties of TCHAR.
Topic archived. No new replies allowed.