I have a problem: I use SendMessage from a procedure in a DLL to communicate with the main window; procedure is a hook procedure that allows main window to know when mouse right button is clicked in a editbox; it sends also handle of the editbox. It works well, except for this bug: when program is running without breakpoints main window receives twice the same message (in this case WM_APP), while if I put a breakpoint in the hook procedure or in the block that handles WM_APP messages the message is considered once. For further descriptions ask me. Following the code of the hook procedure and of the block that handles WM_APP messages. Thanks
Hook procedure
MYDLL_API LRESULT CALLBACK mouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// processes the message
if(nCode >= 0)
{
// if user clicked with mouse right button
if(wParam != NULL && (wParam == WM_RBUTTONDOWN || wParam == WM_RBUTTONUP))
{
wchar_t *s = (wchar_t*) malloc(CLASSNAMELEN*sizeof(wchar_t));
//MessageBox(mainHwnd, (LPCWSTR)L"Captured mouse right button", (LPCWSTR)L"Test", MB_OK);
MOUSEHOOKSTRUCT *m = (MOUSEHOOKSTRUCT*) lParam;
GetClassName(m->hwnd, (LPWSTR) s, CLASSNAMELEN);
//MessageBox(mainHwnd, (LPCWSTR) s, (LPCWSTR)L"Test", MB_OK);
// only if user clicked on a edit box
if(wcsncmp(s, L"Edit", 4) == 0)
SendMessage(mainHwnd, WM_APP, 0, (LPARAM) lParam);
free(s);
s = NULL;
}
}
// calls next hook in chain
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
block in main program that handles WM_APP messages
case WM_APP:
{
//MessageBox(hWnd, (LPCWSTR)L"Received WM_APP", (LPCWSTR)L"Test", MB_OK);
// copies text from the edit box
MOUSEHOOKSTRUCT *m = (MOUSEHOOKSTRUCT*) lParam;
int n = GetWindowTextLength(m->hwnd);
// if text has been inserted
if(n > 0 && n < 1024)
{
wchar_t *s = (wchar_t*) malloc((n+1)*sizeof(wchar_t));
// gets text
GetWindowText(m->hwnd, (LPWSTR) s, n+1);
s[n] = (wchar_t) 0;
//MessageBox(hWnd, (LPCWSTR)s, (LPCWSTR)L"Test", MB_OK);
// saves text in database
stateClassPointer->insertInList(s);
}
}
break;
It is probably because you are sending the message for WM_RBUTTONDOWN and WM_RBUTTONUP, that is when the right button is pressed and when it is released.
When you are debugging the WM_RBUTTONUP is eaten by the debugger so you don't get it.
PS: Shouldn't you use PostMessage() instead of SendMessage(), just to be safe?
Related
In my Win32 CPP program, I have defined some Child Window to display various text strings using something like:
hnd_to_this_ch_window = CreateWindow(
L"EDIT",L"Some initial text", WS_VISIBLE | WS_CHILD | ES_LEFT,
position_of_this_window_X,
position_of_this_window_Y,
TEXTOUT_DEFAULT_WIDTH,
TEXTOUT_DEFAULT_HEIGHT,
handle_to_my_parent_window, NULL,
hinstance_variable_used_by_create_window,
NULL )
My problem is that if I click with my mouse to select the text in one of such child windows (to, say, copy it somewhere), the focus of the application goes to this child window and so any keypresses which used to be handled through my main windows CALLBACK (with case WM_KEYDOWN:) are now captured into the child window, where they appear as inputted characters. What magic function do I call to have the focus go back to the parent (so that my WM_KEYDOWN) can work again? I was hoping I could just click on the main Window's title bar and that would take it back to normal, but that isn't working (because, obviously, my program is lacking some extra logic).
Handle the WM_KILLFOCUS message in the window procedure of the window you want to focus, and restore the focus using the SetFocus function.
If you want to focus the window when it is clicked, handle the WM_LBUTTONDOWN message.
LRESULT CALLBACK MyWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
// Restore the focus when it was lost.
if (Msg == WM_KILLFOCUS) {
SetFocus(hWnd);
// Msg was handled, return zero.
return 0;
}
// Or when the window is clicked.
if (Msg == WM_LBUTTONDOWN) {
SetFocus(hWnd);
// Msg was handled, return zero.
return 0;
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
case WM_KEYDOWN:
SetFocus(Parent_Hwnd);
return SendMessage(Parent_Hwnd,WM_KEYDOWN,wParam,lParam);
I am having issues with creating a modeless dialog from a DLL file. My dialog has nothing special on it, just an OK button and an edit box. I have looked at this Microsoft KB Article (http://support.microsoft.com/kb/233263) and have implemented its solution to create a window hook to grab and process messages.
The method provided by Microsoft solves the tab key problem, however, it creates another problem. When I type into the edit box on the dialog, whatever I press is duplicated 4 times. For example, if I press 'a' on the keyboard, 'aaaa' will show up in the edit box.
If I disable the Window Hook, then the edit box works correctly and only displays one 'a'.
What do I need to do to the Window Hook procedure to solve this problem?
Any help is greatly appreciated.
- - EDIT - -
As per request, my Window Hook Procedure Code: (It's the same as the KB article)
LRESULT FAR PASCAL GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) {
LPMSG lpMsg = (LPMSG) lParam;
if (nCode >= 0 && PM_REMOVE == wParam) {
// Don't translate non-input events.
if ((lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST)) {
if (IsDialogMessage(hwndDllDlg, lpMsg)) {
// The value returned from this hookproc is ignored,
// and it cannot be used to tell Windows the message has been handled.
// To avoid further processing, convert the message to WM_NULL
// before returning.
lpMsg->message = WM_NULL;
lpMsg->lParam = 0;
lpMsg->wParam = 0;
}
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
My Dialog Callback Procedure:
BOOL CALLBACK DllDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_INITDIALOG:
hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, NULL, GetCurrentThreadId());
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
DestroyWindow(hwndDlg);
hwndDllDlg = NULL;
}
return TRUE;
case WM_DESTROY:
UnhookWindowsHookEx(hHook);
return FALSE;
}
return FALSE;
}
}
Both hHook and hwndDllDlg are defined as HHOOK and HWND respectively.
HHOOK hHook;
HWND hwndDllDlg = CreateDialog(0, MAKEINTRESOURCE(DLG_MAIN), 0, DllDlgProc);
I looked at the KB article. It sounds reasonable. There is some point where you was not enough accurate while following the instructions from KB. Post your code. This may help.
If you have control over the message pump of the executable and can add IsDialogMessage there, then you do not need any hook. Code from the dll is part of the code of the process. Window handles are in the common space either.
Other approach is starting your own UI thread. If you create your dialog on this thread, then you will have your own message pump. The hook will not be needed in this case either.
Well, this is more of a question to author of the post..
I have the tab key issue and am trying to understand the microsoft article better.
So my dialog is shipped out as Dll and the application which I don't have access to is launching dialog from my dll.
HWND hwndDllDlg = CreateDialog(0, MAKEINTRESOURCE(DLG_MAIN), 0, DllDlgProc);
I don't understand what dialog the code refers to when they said hwndDllDlg in the article. Should I point my dialog creation to this variable ?
I have a program with several custom controls. One of these custom controls is a text input control. Since a window does not automatically receive keyboard focus when you click on it, i've created a mouse hook in my program that calls SetFocus() on a window when the user clicks in that window. However, there is a problem.
If another program has focus when you click on my program's window (or any of the controls in that window) SetFocus() fails. I then have to click again for it to succeed. Here's the code:
LRESULT CALLBACK kbfProc(int nCode, WPARAM wParam, LPARAM lParam) // Keyboard focus switching procedure
{
switch(nCode)
{
case HC_ACTION:
{
if(wParam == WM_LBUTTONDOWN || wParam == WM_NCLBUTTONDOWN)
{
MOUSEHOOKSTRUCT * mhs = (MOUSEHOOKSTRUCT*) lParam;
if(SetFocus(mhs->hwnd) == NULL)
{
printf("SetFocus(Hwnd = %.8x) failed. Error code: %lu\n", mhs->hwnd, GetLastError());
} else {
printf("SetFocus(Hwnd = %.8x) returned success.\n", mhs->hwnd);
}
}
}
break;
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
And the output of those printf calls is this:
SetFocus(Hwnd = 00410c06) failed. Error code: 87
SetFocus(Hwnd = 00410c06) returned success.
SetFocus(Hwnd = 01740fc8) failed. Error code: 87
SetFocus(Hwnd = 01740fc8) returned success.
Error code 87 is ERROR_INVALID_PARAMETER, but i'm obviously passing a valid window handle to the function, so why is it failing?
Whenever you're calling SetFocus, the window must be attached to the calling thread's message queue or SetFocus will return invalid if it's not. To workaround this, use SetForegroundWindow first when the mouse moves over your window before calling SetFocus.
I know I'm couple of days late, but since I just spent a whole day trying to fix this, I'll add my fix here as well, just in case it helps someone.
Basically it was the AttachThreadInput thing mentioned above in a comment. GetActiveWindow() was always returning NULL as well. Which window you need to attach to might vary case by case, but I needed the root window, so I used GetAncestor. If you know the window handle you want, then you can just use it instead. So this is the code that fixed it for me:
AttachThreadInput(GetCurrentThreadId(), GetWindowThreadProcessId(GetAncestor(hWnd, GA_ROOT), NULL), TRUE);
I've found a solution. After a lot of googling and trial & error I eventually came across this webpage (backup link). It goes over the behavior of window focus and activation in detail.
I ended up adding some code to the WM_ACTIVATE handler of my main window that searches for the child window that was clicked when the window is activated. Here's all the code:
Here's the hook procedure:
LRESULT CALLBACK kbfProc(int nCode, WPARAM wParam, LPARAM lParam)
{
switch(nCode)
{
case HC_ACTION:
{
if(wParam == WM_LBUTTONDOWN || wParam == WM_NCLBUTTONDOWN)
{
MOUSEHOOKSTRUCT * mhs = (MOUSEHOOKSTRUCT*) lParam;
BringWindowToTop(MainWindow->t_hwnd);
SetFocus(mhs->hwnd);
}
}
break;
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
Here's the code i put in the WM_ACTIVATE handler:
case WM_ACTIVATE:
{
unsigned long state = (unsigned long) wParam & 0x0000FFFF;
unsigned long mState = (unsigned long) wParam & 0xFFFF0000;
if(state != 0)
{
...[some code here]...
FocusChildWindow(hwnd);
}
...[some code here]...
}
break;
And here's the FocusChildWindow() function:
void FocusChildWindow(HWND hwnd)
{
POINT mpos;
GetCursorPos(&mpos);
RECT wr;
GetWindowRect(hwnd, &wr);
mpos.x -= wr.left;
mpos.y -= wr.top;
HWND cw = ChildWindowFromPoint(hwnd, mpos);
if(cw == NULL || cw == hwnd)
{
SetFocus(hwnd);
} else {
GetCursorPos(&mpos);
HWND cw2;
while(1)
{
POINT sc = mpos;
MapWindowPoints(HWND_DESKTOP, cw, &sc, 1);
cw2 = ChildWindowFromPoint(cw, sc);
if(cw2 == NULL || cw2 == cw)
{
SetFocus(cw);
break;
} else {
cw = cw2;
}
}
}
}
The following worked for me when SetFocus() had no effect setting the keyboard focus to a child control window on a property sheet page window:
::SendMessage(m_hPropPageWnd, WM_UPDATEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0);
I'm developing an application targeted to a POCKET PC 2003 (Windows CE 4.2) device using C++ and native WINAPI (i.e. no MFC or the like). In it I have a single-line edit control which part of the main window (not a dialog); hence the normal behaviour of Windows when pressing ENTER is to do nothing but beep.
I've subclassed the window procedure for the edit control to override the default behaviour using the following code:
LRESULT CALLBACK Gui::ItemIdInputProc( HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam ) {
switch ( message ) {
case WM_KEYDOWN :
switch ( wParam ) {
case VK_RETURN :
addNewItem();
return 0;
}
}
return CallWindowProc( oldItemIdInputProc_, hwnd, message, wParam, lParam );
}
This causes the equivalent behaviour as pressing the 'OK' button.
Now to the problem at hand: this window procedure does not override the default behaviour of making a beep. I suspect that there must be some other message or messages which are triggered as ENTER is pressed that I fail to capture; I just can't figure out which. I really want to stop the device from beeping as it messes up other sounds that are played in certain circumstances when an item collision occurs, and it is crucial that the user is alerted about that.
Thanks in advance.
After spewing all messages to a log file, I finally managed to figure out which message was causing the beeping - WM_CHAR with wParam set to VK_RETURN. Stopping that message from being forwarded to the edit control stopped the beeping. ^^
The final code now reads:
LRESULT CALLBACK Gui::ItemIdInputProc( HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam ) {
switch ( message ) {
case WM_CHAR :
switch ( wParam ) {
case VK_RETURN :
addNewItem();
return 0;
}
}
return CallWindowProc( oldItemIdInputProc_, hwnd, message, wParam, lParam );
}
Had the same issue but thanks to you, I finally managed to turn the beep off.
// Run the message loop. It will run until GetMessage() returns 0
while(GetMessage (&messages, NULL, 0, 0)) {
if(messages.message == WM_KEYDOWN && messages.wParam == VK_RETURN) {
sendChatMessage("sample text");
continue;
}
// Translate virtual-key messages into character messages
TranslateMessage(&messages);
// Send message to WindowProcedure
DispatchMessage(&messages);
}
I guess the trick was to not let execute those two statements
I had the same problem but with my Rich Edit (using also subclassed callback). This side helped me lot but sadly the solution from gablin didn't work for me. Somehow I couldn't get the VK_RETURN from the WM_CHAR. But from the WM_KEYDOWN message I can:). I also found out that in my case the beep comes only if the rich edit use not the ES_MULTILINE style.
So finaly this is my working solution in the Callback to dissable the beep if return key is pressed. Maybe it can still help someone who has the same problem :)
switch (message){
case (WM_KEYDOWN) : {
switch (wParam) {
case VK_RETURN:
if ((GetWindowLong(this_editbox->getHandle(), GWL_STYLE) & ~ES_MULTILINE)){ //Only dissable return key if the rich edit is a single line rich edit
//Do something you want to do here if return key was pressed for ex. delete text with SetWindowTextA(hRichEdit, ""); after reading
return 0;// stop beep by blocking message
}
}
break;
}
default: break;
}
Try also handling the WM_KEYUP and return 0 for VK_RETURN there as well - Windows non-CE also beeps if you don't handle the key event in both down and up.
In a Windows desktop app, I was also getting annoying beeps when hitting the left arrow key when the insertion point was to the left of the first character, or hitting the right arrow key when the insertion point was positioned after the last character. This code handles the return key as well as the left and right arrow keys to stop the beep.
This is in a Windows desktop app, so I'm not hearing a beep for WM_CHAR + VK_RETURN; you'll have to try this code yourself on CE to see if it works well for you.
bool processKeystroke = true;
if (message == WM_CHAR || message == WM_KEYDOWN || message == WM_KEYUP) {
DWORD start = 0;
DWORD end = 0;
switch (wParam) {
case VK_RETURN:
if ((GetWindowLong(hwnd, GWL_STYLE) & ~ES_MULTILINE)) {
processKeystroke = false;
}
break;
case VK_LEFT:
{
::SendMessage(hwnd, EM_GETSEL, (WPARAM) &start, (LPARAM) &end);
if (start == 0 && end == 0) {
processKeystroke = false;
}
}
break;
case VK_RIGHT:
{
LPARAM charCount = ::SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
::SendMessage(hwnd, EM_GETSEL, (WPARAM) &start, (LPARAM) &end);
if (wParam == VK_RIGHT && start == charCount && end == charCount) {
processKeystroke = false;
}
}
break;
}
if (processKeystroke) {
lResult = DefSubclassProc(hwnd, message, wParam, lParam);
}
}
}
In a Windows desktop app, I got the same problem while handling VK_TAB in WM_GETDLGCODE.
so I found the following solution.
SystemParametersInfo(SPI_SETBEEP, FALSE, NULL, 0); // turn of the beep
// do somthing ... //
SystemParametersInfo(SPI_SETBEEP, TRUE, NULL, 0); // turn on the beep
I am trying to subclass the currently focused window on a Windows system using a global CBT hook. This is related to what happens in this question, but the bug is different.
What happens when this subclassing is in effect, is that Opera's (version 10.50) main window is prevented from displaying. Opera has a "splash screen" where you are required to click "Start" for the main window to show that appears after Opera has not shut down properly. Whenever this window pops up, Opera's main window won't show. If Opera was shut down properly, and this splash screen does not show, the main window displays as it should.
HHOOK hHook;
HWND hWndSubclass = 0;
void SubclassWindow(HWND hWnd)
{
Unsubclass();
FARPROC lpfnOldWndProc = (FARPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LPARAM)SubClassFunc);
SetProp(hWnd, L"PROP_OLDWNDPROC", lpfnOldWndProc);
hWndSubclass = hWnd;
}
void Unsubclass()
{
if (hWndSubclass != 0 && IsWindow(hWndSubclass))
{
FARPROC lpfnOldWndProc = (FARPROC)GetProp(hWndSubclass, L"PROP_OLDWNDPROC");
RemoveProp(hWndSubclass, L"PROP_OLDWNDPROC");
SetWindowLongPtr(hWndSubclass, GWLP_WNDPROC, (LPARAM)lpfnOldWndProc);
hWndSubclass = 0;
}
}
static LRESULT CALLBACK SubClassFunc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_MOVING)
{
// do something irrelevant
}
else if (message == WM_DESTROY)
{
Unsubclass();
}
FARPROC lpfnOldWndProc = (FARPROC)GetProp(hWndSubclass, L"PROP_OLDWNDPROC");
return CallWindowProc((WNDPROC)lpfnOldWndProc, hWndSubclass, message, wParam, lParam);
}
static LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_SETFOCUS && hWndServer != NULL)
{
SubclassWindow((HWND)wParam);
}
if (nCode < 0)
{
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
return 0;
}
BOOL APIENTRY DllMain( HINSTANCE hInstance,
DWORD Reason,
LPVOID Reserved
)
{
switch(Reason)
{
case DLL_PROCESS_ATTACH:
hInst = hInstance;
return TRUE;
case DLL_PROCESS_DETACH:
Unsubclass();
return TRUE;
}
return TRUE;
}
My suspicion is that Opera's main window is somehow already subclassed. I imagine the following is happening:
The window is created with it's own basic WndProc, and is given focus
My application subclasses the window, storing the original WndProc
Opera subclasses its own window
When the window loses focus, I restore the original WndProc, thus ignoring the second WndProc
Can this really be the case? Are there any other explanations?
This can happen, as Raymond Chen writes:
Consider what would happen if somebody else had subclassed the window during the "... do stuff ..." section. When we unsubclassed the window, we would have removed two subclasses, the one we installed, and the one that was installed after us. If the other subclass allocated memory (which is very common), then that memory got leaked, in addition to the subclass failing to do whatever it was trying to do.
He continues with a solution:
This is quite a cumbersome process, so the shell team wrote some helper functions to do all this for you. The SetWindowSubclass function does all the grunt work of installing a subclass procedure, remembering the previous one, and passing reference data to the subclass procedure you provide. You use the DefSubclassProc function to forward the message to the previous subclass procedure, and when you're done, you use the RemoveWindowSubclass function to remove yourself from the chain. RemoveWindowSubclass does all the work to do the right thing if you are not the window procerure at the top of the chain.