Posted on 1998-12-24
Last Modified: 2008-02-01
I am working with VC++ 5.0 on a Win98 system, but have run into this same problem on a Win95 machine.  When I create a window and a group of controls on that window with the following code:

HWND hWnd = CreateWindowEx(WS_EX_NOPARENTNOTIFY, "RegScreen", "Install Pro 1.0", WS_VISIBLE | WS_CAPTION | WS_BORDER | WS_SYSMENU, pt.x, pt.y, 500, 400, NULL, NULL, hInst, NULL);


CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_TABSTOP | WS_CHILD | WS_BORDER| WS_VISIBLE | ES_LEFT, 165, 93, 305, 27, hWnd, (HMENU)IDC_COMPANY, hInst, NULL);      

CreateWindow("BUTTON", "<< Back", WS_TABSTOP | WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 210, 325, 65, 27, hWnd, (HMENU)IDC_BACK, hInst, NULL);

CreateWindow("BUTTON", "Next >>", WS_TABSTOP | WS_DISABLED | WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 275, 325, 65, 27, hWnd, (HMENU)IDC_NEXT, hInst, NULL);

CreateWindow("BUTTON", "Cancel", WS_TABSTOP | WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 410, 325, 65, 27, hWnd, (HMENU)IDC_CANCEL, hInst, NULL);

Why is it that the Tab button COMPLETLY REFUSES to work under any circumstances?  I was under the impression that if all the controls were created with the WS_TABSTOP style that the tab key would move between them.  However this does not happen on the window that I have created.
Question by:dirtdart
  • 4
  • 2

Expert Comment

ID: 1181005
I think...

The parent window for the controls needs to handle the WM_NEXTDLGCTL message.  The reason you don't need to include this code for dialog boxes, is that the default dialog procedure (DefDlgProc) handles this by default.  In your case, your parent window isn't a dialog, so you have to put in this code yourself in the parent window (the one you create first).

BTW if you are thinking of changing to use a dialog/modeless dialog box for the parent, watch out - I seem to recall that DefDlgProc only handles WM_NEXTDLGCTL message correctly for controls that are in the dialog's resource template at least under some versions of Windows.  Sorry I can't be more specific on this (extra) comment, as I simply don't remember too well!

Author Comment

ID: 1181006
Well, this seems like a logical answer, but I'm going to need a bit more information before I can grade it.  I attempted to process the message with what little information I can find on it in the Win32 SDK, but it certainly didn't work in the way I need it to.  My code:

            SetFocus(GetDlgItem(hWnd, wParam));
            return 0;

Since wParam supposedly returns the ID of the control that should receive focus, this seems to be a logical conclusion.  Whenever the Tab is pressed, it fires the message and the message pump sets the focus to the next provided control.  However.  When run, the above code simply prevents any of the controls on the form from receiving focus.

Author Comment

ID: 1181007
Well, I've waited two weeks for more of an explination, so I guess now I'll have to open the question back up.
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!


Accepted Solution

SaGS earned 200 total points
ID: 1181008
For the TAB key to work, you must call IsDialogMessage() in the main message loop. And call DefDlgProc() for default message processing, instead of DefWindowProc().

From your question&comment I see you are not using MS Foundation Classes. In this case, you have the control on the message loop - just insert IsDialogMessage() there (see help for details).

With MFC (the version I have, at least), CDialog accomplishes this by calling IsDialogMessage() from it's PreTranslateMessage() member function. You can define a CDialog-derived class (to provide the message table), and still create the window with CreateWindow(); just Attach() the HWND to the CDialog-derived object.

What you obtain is the equivalent of using a modeless dlgbox with a private class as the main window (I often use dlgboxes as main windows, it works fine), only that you don't rely on a template and CreateDialog() to create the window and the controls.

Author Comment

ID: 1181009
Well, that looks great, and it certainly answers my question.  However, I'd appreciate it if you'd give me one more piece of advice to go with this.  My main message loop processes messages for at least 12 different windows (kind of a wizard type thing).  How do I tell which window handle is currently being processed so that I can pass it to IsDialogMessage?

Expert Comment

ID: 1181010
The key is the WM_ACTIVATE message. Define a global variable:

HWND hActiveWnd = NULL;

and inside all windows procedures (in fact, it's enough to do this only for windows that need the extra processing) handle the WM_ACTIVATE message. When the window is activated (WA_ACTIVE, WA_CLICKACTIVE), store the window's handle into the global variable; when deactivated (WA_INACTIVE), set the global handle to NULL (Windows takes care to send these messages in the proper order - first deactivates the old window, then activates the new one). In the main message loop, examine the global variable to decide what to do (NULL => nothing to do, the active win does not belong to your app or needs nothing special, !=NULL => your window, the value is the active window's HWND).

Note: You can use a similar trick to implement a window-specific accelerators table (a global "HACCEL hActiveWndAccel = NULL;", and so on).

Author Comment

ID: 1181011
Sounds great.  Thanks for all the help.  Now maybe I can get this junk finished!

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now