Link to home
Start Free TrialLog in
Avatar of tofff
tofff

asked on

Character messages to windows

What am I doing wrong? I've got a windows app, but I can't get char messages through to it. I've tried using an accelerator table, but that doesn't work either. I'm using TranslateAccelerator and TranslateMessage, and both appear to be succeeding, but the WM_CHAR messages just don't get through.

This a standard Win32 application, using C, with a number of
dialog boxes as the front end. The app starts off (in WinMain):

accel.fVirt = FCONTROL;
accel.key = (int)'s';
accel.cmd = IDM_SWAP;
hAccel = CreateAcceleratorTable(&accel,
                                1);
if (NULL != hAccel)
{
    if (NULL != CreateDialogParam(StoreDLLInstanceHandle(NULL),
                                  MAKEINTRESOURCE(IDDB_DIAGNOSTIC_CONFIGURATION),
                                  NULL,
                                  DiagnosticConfigurationDlgProc,
                                  (LPARAM)szComputer))
    {                                      
        while (GetMessage(&msg,
                          NULL,
                          0,
                          0))
        {
            if (!TranslateAccelerator(msg.hwnd,
                                      hAccel,
                                      &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    }              
    else
    {
        t(TRACE_ERROR,
          "CreateDialogParam failed due to a GetLastError of %d.\n",
          GetLastError());
    }
}    

I have in the dialog proc of every window:

switch (wMessage)
{
    case WM_CHAR:
    case WM_DEADCHAR:
    case WM_SYSCHAR:
    case WM_SYSDEADCHAR:
        t(TRACE_ENTRY,
          "WM_CHAR received by DataCollectionSetupDlgProc, '%c' selected.\n",
          (TCHAR)wparam);            
        break;
           
None of them ever get invoked - the CHAR messages just aren't getting through.

If this isn't enough info, please let me know, I need this pretty desparately.
Avatar of jhance
jhance

More information would really be helpful here.  What kind of app is it, dialog, SDI, MDI?  How about posting some code?
Avatar of tofff

ASKER

Edited text of question
the character messages will go to the window that has the focus.  If that is an edit box or other "built-in" control you do not have a window procedure for, you will not "see" the message.  

You could put a test for the messages in you message loop.  The messages will go through there before beig dispatched to the window with the focus.
To be more specific, your main program won't get any WM_CHAR messages from an EDIT control by default.  These controls are setup to handle all key presses by themselves.  In order to get WM_CHAR messages to go to the main message loop for your window, you must subclass the EDIT control (in Win32 API) using the SetWindowLong() function.  Using the HWND to the EDIT control and GWL_WNDPROC, you can replace the WndProc with a new one which will handle WM_CHAR.
I don't think that is quite correct.  I beleive that the WM_CHAR messages will go to the main message loop, that is, I believe, they are posted, not sent.  So you should see them in the message loop.  But from there they go to the edit control window or other control window, not to the dialog window.

If I am wrong however, and they are sent, not posted.  Then the edit control must be sub-classed as jhance said.  However, his reasoning is wrong (or more likely, he was a little careless in what he said)  If the messages are sent, then sub-classing the edit control would allow you to intercept the message in the new edit control's window procedure.  (not in the message loop as jhance suggested.)  If the message is sent, you cannot intercept the message in the message loop regardless of sub-clssing.
nietod, you are correct that perhaps my language are not 100% precise.  But, to get WM_CHAR messages from an EDIT control (and it's kin) you need to subclass it (at least that is one way to do it).  Since the EDIT control is a window of it's own and has it's own message loop, you don't normally see the WM_CHAR messages.  They are handled internally by the control in Windows so as avoid burdening the programmer with unnecessary messages fro the control.  When you want to get at them, however, you can subclass it and substitute your own WndProc that can intercept the WM_CHAR messages and take the appropriate action.
I can give you an example of this in MFC (that is subclassing a CEdit) but I'm a bit rusty in my Win32 API.  You might want to look at the SUBCLASS sample if you have MSDN.  It shows how to do this in the Win32 API.
Your absolutly right.  I forgot that when a modal dialog is open windows uses a private message loop so you application holds up until the dialog closes.  (I don't use the built-in dialogs and my dialog's don't hold up execution.)  

However, this is a dialog related issue, not an edit control related issue.  If the edit control is in a regular window, the edit control's messages would go through the program's message loop.  That's the kind of case I was thinking of.  

Avatar of tofff

ASKER

I have tried this with the focus both on an edit field, on no control, and with the the focus on pushbuttons, etc. I even created a dialog box with no controls at all and put it into the program. It didn't get the messages, either.
ASKER CERTIFIED SOLUTION
Avatar of jhance
jhance

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
OK, you forced me to break out my Programming Windows book (by Charles Petzold).  If you don't have one, go and get one.  No real Windows programmer would be without it!!!  Anyway, there is a nice example in Chapter 10 on making a windows that on one hand acts like a dialog box in that it is created from a resource, but also acts like a normal window in that it's WndProc is supplied by you and not the default dialog WndProc that Windows provides for dialogs.  (By the way, the SetWindowLong method will also do the same thing but this might be clearer).  

The basic idea is to add WS_OVERLAPPED to the STYLE directive in your RC file for the dialog.  Then  you need to call CreateWindow() and also set the WS_OVERLAPPED flag.  I'd suggest looking at the example as my copy is so old that it didn't come with a CD and it a lot to type in here.
The dialog between jnahce and I may be a little confussing for you, especialy since we both made some mistakes.  let me try to make this clear.

The WM_CHAR message goes to two places.  First it goes to a message loop and then it goes to the window procedure of the window with the focus.  Thus there are two potential places to intercept it.

Now if you have a dialog up, windows uses its own message loop so you can't intercept it in you message loop.  (If a regular window is up, your are fine.)  Thus option one is in this case.

That means that in this case you have to intercept it at the window procedure.  Okay?  Problem.  You don't write the window procedures for the edit control/push button/dialog window/listbox etc.  If items like this have the focus they will get the message, but the window procedure or procedures you've written are not for these windows, so you can't intercept the message.

Workaround.

As jhance suggested.  You must have a window procedure for the window that is receiving the character message, that is, the edit control/push button, list box, etc.  The way to do this is to sub-class the window.  This allows you to provide a short window procedure for these types of windows and then use the window procedure that windows would ordinarily have used.  You can then intercept the WM_CHAR message in the short window procedure.

However, I wonder if this is a good idea.  I suspect that if you tell us what you are trying to do there might be a better way.  Often there is no reason to get character messages for these type of windows (or any type of window really).