PostMessage(), SendMessage not working in ATL dll (event handling) - c++

sorry, my english skill is very low.
i make a ATL(C++) dll. and handled by VB.
i make under base code.
WaitAndReadData, Thread_WaitAndReadData is working.
but, ::SendMessage, ::PostMessage is not working in Thread_WaitAndReadData or WaitAndReadData.
and breakpoint not working in Get_Data_Messagehandler.
(+ another function call.)
#define WM_SERVERTHREADFIREEVENT (WM_USER+2)
BEGIN_MSG_MAP(CHello)
CHAIN_MSG_MAP(CComControl<CHello>)
MESSAGE_HANDLER(WM_SERVERTHREADFIREEVENT, GetData_Messagehandler)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
-
static DWORD WINAPI Thread_WaitAndReadData(LPVOID pParam)
-
STDMETHODIMP CHello::WaitAndReadData(BSTR* ret_Result)
{
// TODO: Add your implementation code here
DWORD dwThreadID;
thread = CreateThread(NULL, 0, Thread_WaitAndReadData, (LPVOID)this, 0, &dwThreadID);
return S_OK;
}
-
DWORD WINAPI CHello::Thread_WaitAndReadData(LPVOID pParam)
{
CHello* hello = (CHello*)pParam;
::SendMessage(hello->m_hWnd, WM_SERVERTHREADFIREEVENT, (WPARAM)NULL, (LPARAM)NULL);
return S_OK;
}
-
LRESULT CHello::GetData_Messagehandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
MessageBox(L"GetData_Messagehandler", L"asd", MB_OK);
return 0;
}

Even though MSDN states that there is no marshaling of WM_USER + x messages in cross-process sending, if my memory serves me right you might have troubles with cross-thread sending as well. In this case use RegisterWindowMessage API to obtain "sendable" WM_xxx identifier rather than harcoding it using a #define
Don't use bare CreateThread, use AtlCreateThread instead (or, _beginthreadex). See why.
Another reason to not receive messages on window thread is thread deadlock or window creation on thread that does not have a message pump later on, in both cases a message might be sent but there is no dispatching it to window. You can also use Spy++ tool (spyxx.exe in Visual Studio Comment\Tools directory) to make sure that the message in question is indeed being sent to the window.

Related

SetWindowsHookEx ignoring PostMessage from message loop

I am trying to mod an older game, more specifically I want to emulate keyboard input via Xbox controller input. I already have the gamepad input working, but the game ignores my fake input I create with PostMessage (I tried PostThreadMessage as well with worse outcome.)
So here is the core piece of my code, a detour of PeekMessage :
BOOL WINAPI MyPeekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
{
BOOL ret = RealPeekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
if (lpMsg->message == WM_KEYDOWN)
{
cout << "Key press";
}
if (!ret)
{
if (joypadButtonDown)
{
LPARAM lparam = 0x00000001 | (LPARAM)(EnterScanCode << 16); // Scan code, repeat=1
BOOL res = PostMessage(mainHwnd, WM_KEYDOWN, VK_RETURN, lparam);
}
}
return ret;
}
Now the problem is that the game doesn't use its message loop to read keyboard input, but instead uses SetWindowsHookEx with WH_KEYBOARD on its own main window thread.
So on a real key press what happens is :
The game's main loop calls my detour which calls the real PeekMessage which calls the hook procedure. But if I send my fake message (with identical parameters) the game again calls my detour but the real PeekMessage doesn't call the hook procedure and therefore misses the input.
Some additional Info :
- I've checked that everything happens on the same thread (Main window creation, setting the hook and the main loop)
- I tried sending PostMessage directly from IDirectInputDevice8->GetDeviceState with the same result
- Invoking the hook procedure directly causes a crash (which makes sense).
I found a somewhat dirty workaround. I call the game's SetWindowsHookEx KeyboardProc callback directly and avoid the crash I mentioned in the OP by detouring CallNextHookEx to ignore my fake hook calls.

SetWindowsHookEx(WH_KEYBOARD) not working with thread ID

I have a dll that gets called by a process and now I would like to implement an input check in the dll to react on certain inputs that occur in the application.
SetWindowsHookEx() with a KeyboardProc function seemed like a possible solution so I implemented it.
This is roughly how the code in the dll looks like:
static HHOOK hhk = NULL;
LRESULT CALLBACK keyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
if(code == HC_ACTION && ((DWORD)lParam & 0x80000000) == 0) // if there is an incoming action and a key was pressed
{
switch(wParam)
{
case VK_SPACE:
printf("Space was pressed\n");
break;
}
}
return CallNextHookEx(hhk, code, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if(ul_reason_for_call == DLL_PROCESS_ATTACH)
{
if(AllocConsole()){
freopen("CONOUT$", "w", stdout); // redirect output to console for debugging
}
printf("Dll loaded, lastError = %i\n", GetLastError());
printf("lastError = %i\n", GetLastError());
// sidenote: for some reason the first GetLastError() returns 0 while the second one returns 6 (invalid handle)
hhk = SetWindowsHookEx(WH_KEYBOARD, keyboardProc, hModule, GetCurrentThreadId());
}
else if (ul_reason_for_call == DLL_PROCESS_DETACH)
{
printf("\nCleaning up...");
FreeConsole();
UnhookWindowsHookEx(hhk);
}
return TRUE;
}
However nothing happens (or gets printed) in the Console window when I press any key. It doesn't even seem like the keyboardProc function is accessed at any time.
It does work though when I pass NULL instead of GetCurrentThreadId() to SetWindowsHookEx().
But this causes the hook to work globally meaning that whenever I press a key in another application, a Console window pops up (because the dll gets called again) and he checks for key inputs there.
Obviously this is not desired and I would like to make this work with only the process that originally called the dll.
I already checked if GetCurrentThreadId() returns a valid ID and it seems to be indeed the main thread ID of the process that initially called the dll (checked with Process Explorer).
So now my question is what could be the problem and more importantly, what can I do to make it working?
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
uint process_id;
uint thread_id = GetWindowThreadProcessId(windowHandle, out process_id);
hhook = SetWindowsHookEx(WH_KEYBOARD, a_KeyboardProc, hInstance, 0);
I have used the code above to get the main thread_ID for a certain process. The good part is, the SetWindowsHookEx function gives a logical output. Unfortunately, the bad part is, if a key is pressed in the thread that has been hooked, the thread stops working.
In specific, the idHook parameter of SetWindowsHoookEx function was set to 2 (instead of 13) in my case for non-low-level keyboard events. It seems, at least to me, that LL corresponds to low-level, where keyboardProc should come with a WH_KEYBOARD instead of WH_KEYBOARD_LL.
I am not sure at this point how my response would be related to your question. Hopefully, we get what we need through discussion.

Sending a message to a window that belongs to another thread. Possible Deadlock?

I think i am ruining in to a deadlock, have been searching for the solution over hours. Any suggestions?
What i am trying to do is: ater startGame button click, create thread that send request to the server and then gets the answer, after the answer the thread must send a message to Initialize game window to the main proc...
Message Proc that belongs to WinMain:
LRESULT CALLBACK WndProc(HWND myWindow, UINT messg, WPARAM wParam, LPARAM lParam)
{
switch (messg) {
case WM_STARTGAME:
DestroyWindow(hStartGameButton);
DestroyWindow(hHistoryButton);
InitGameWindow(myWindow);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_STARTGAME_BUTTON:
{
parametros param;
param.myWindow = myWindow;
start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)&myWindow, 0, NULL);
}
}
}
And this is the thread:
DWORD WINAPI ThreadStartGame(LPVOID param){
HWND w = (HWND)param;
DWORD n;
BOOL ret;
mensagem resposta;
mensagem msg;
msg.tipo = COMECAR_JOGO;
msg.verifica = true;
if (!WriteFile(hPipe, &msg, (DWORD)sizeof(mensagem), &n, NULL)) {return 0;}
ret = ReadFile(hPipeN, &resposta, (DWORD)sizeof(mensagem), &n, NULL);
if (!ret || !n) {
return false;
}
PostMessage(w, WM_STARTGAME, NULL, NULL); // <- THIS GETS EXECUTED BUT NOTHINK HAPPENS AFTER
return 0;
}
I don't think there is any deadlock here.
start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)&myWindow, 0, NULL);
This line passes the address of the HWND to the thread (&myWindow)
HWND w = (HWND)param;
This line uses the adress itself as HWND and the SendMessage sends the message to this address which is not a HWND.
Try modifying to
start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)myWindow, 0, NULL);
W/o even looking at the code, I can tell you right away: do not use SendMessage between threads. I recommend reading Psychic debugging: The first step in diagnosing a deadlock is a simple matter of following the money and Preventing Hangs in Windows Applications:
Use asynchronous window message APIs in your UI thread, especially by replacing SendMessage with one of its non-blocking peers: PostMessage, SendNotifyMessage, or SendMessageCallback
...
Any blocking call that crosses thread boundaries has synchronization properties that can result in a deadlock. The calling thread performs an operation with 'acquire' semantics and cannot unblock until the target thread 'releases' that call. Quite a few User32 functions (for example SendMessage), as well as many blocking COM calls fall into this category.
For starters, you're unlikely supposed to do that in the first place. Quoting MSDN:
A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and _endthreadex functions for thread management rather than CreateThread and ExitThread; this requires the use of the multithreaded version of the CRT. If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions.
Second, your thread can be worker or UI thread, from the first type you must not call most of the window related functions, as it has no message pump. DestroyWindow is such. (So many times I tried to use MessageBox despite my own comment a few lines upper telling it's forbidden in that function ;).
From worker threads the usual method is to use PostThreadMessage and react on the UI thread. (If you have multiple UI threads, I don't know the rules, was never brave enough for that.)

MS Word COM addin can't receive messages in XP

From inside my COM addin I create a dialog, and I then send messages to it from an external process. I use HWND_BROADCAST and RegisterWindowMessage.
But those messages are never received by the dialog proc of the COM addin. I know this because I log all the messages received by the dialog proc, and also the value returned by RegisterWindowMessage.
From the external process:
static UINT nCloseMessage = 0;
if (!nCloseMessage)
nCloseMessage = RegisterWindowMessage(_T("MyCloseMessage"));
PostMessage(HWND_BROADCAST, nCloseMessage, 0, 0);
From the COM add-in:
INT_PTR CALLBACK ProgressDialogProc(__in HWND hwndDlg,__in UINT uMsg,__in WPARAM wParam,__in LPARAM lParam)
{
static UINT nCloseMessage = 0;
if (!nCloseMessage)
nCloseMessage = RegisterWindowMessage(_T("MyCloseMessage"));
if (uMsg == nCloseMessage)
MessageBox(0,_T("Caught"),0,0);
return FALSE;
}
I found why I get this error, HWND_BROADCAST doesn't work when the dialog has a parent window.
Passing NULL to CreateDialog for the parent fixed the error.

C++ Console app, SetWindowsHookEx, Callback is never called

I have a little console application that has an embedded v8 engine, and I would like to add a hook to register key events. This all worked before when I was using Qt and QtScript, but I am porting it all over to straight C++ in VC++ 2008. The application compiles and runs, but the hook is never called, here is the relevant code:
In main()
HWND hwndC = GetConsoleWindow() ;
HINSTANCE hInst = (HINSTANCE)GetWindowLong( hwndC, GWL_HINSTANCE );
if (SetWindowsHookEx(WH_KEYBOARD_LL, HookProc, hInst, NULL) == 0) {
printf("Failed to set hook\n");
} else {
printf("Hook established\n");
}
g->RunScript(argc,argv);
And the proc:
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
printf("HookProc called\n");
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) (lParam);
if (wParam == WM_KEYDOWN) {
keyDown(p,g);
} else if (wParam == WM_KEYUP) {
keyUp(p,g);
}
fflush(stdout);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
This is essentially an expansion on shell.cc from the v8 sample code. I wonder if it is somehow blocking? I admit to not really knowing what I am doing here, just playing around and learning but this one has me stumped.
Inside of keyDown say, I have something like this:
v8::Handle<v8::String> callback_name = v8::String::New("onKeyDown");
v8::Handle<v8::Value> callback_val = g->_context->Global()->Get(callback_name);
if (!callback_val->IsFunction()) {
printf("No onKeyDown handler found\n");
return;
}
v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(callback_val);
const int argc = 1;
v8::Handle<v8::Value> argv[argc] = { v8::Int32::New(char(p->vkCode)) };
printf("Calling onKeyDown\n");
v8::Handle<v8::Value> result = callback->Call(g->_context->Global(), argc, argv);
Some of this may actually not work in the end, but it just never gets called, when I run the program, and define: onKeyDown = function(key) {...}; I can see that onKeyDown is working just fine, I can use all of my bound c++ method etc from JS, so this thing is just driving me batty.
Any help, maybe pointers to some educational materials would be much appreciated.
Just to be clear, this function in c: LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) is never getting called, or never seeing a printf, and the output at the start says: Hook established, so windows is reporting the hook is established.
/Jason
A low-level hook, like WH_KEYBOARD_LL requires that your application pumps a message loop. That's the only way that Windows can break into your thread and make the call to the HookProc callback you registered.
A console mode app doesn't pump a message loop like regular Windows GUI apps do. Judging from your snippet, it isn't going to be easy to add one either. You'll need to create a thread.
Maybe this function will be of help to you?
GetAsyncKeyState