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.
Who is Participating?
SaGSConnect With a Mentor Commented:
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.
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!
dirtdartAuthor Commented:
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.
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

dirtdartAuthor Commented:
Well, I've waited two weeks for more of an explination, so I guess now I'll have to open the question back up.
dirtdartAuthor Commented:
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?
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).
dirtdartAuthor Commented:
Sounds great.  Thanks for all the help.  Now maybe I can get this junk finished!
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.