Using the Win32 APIs, is it possible to create a Window or Dialog in one thread then collect events for it from another thread?
Are HWNDs tied to threads?
Trying the contrived example below I never see GetMessage() fire.
HWND g_hWnd;
DWORD WINAPI myThreadProc(LPVOID lpParam)
{
while(GetMessage(&msg, hWnd, 0, 0) > 0)
{
...
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MYDIALOG), 0, myDlgProc);
CreateThread(NULL, 0 myThreadProc, NULL, 0, NULL);
...
}
But here, I do.
HWND g_hWnd;
HINSTANCE g_hInstance;
DWORD WINAPI myThreadProc(LPVOID lpParam)
{
hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MYDIALOG), 0, myDlgProc);
while(GetMessage(&msg, hWnd, 0, 0) > 0)
{
...
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
g_hInstance = hInstance;
CreateThread(NULL, 0 myThreadProc, NULL, 0, NULL);
...
}
Can somebody explain what I'm seeing?
No.
GetMessage returns messages on the current thread's input queue. The HWND parameter is a filter, so that GetMessage only returns messages in the current thread's input queue intended for that window.
Windows have thread affinity - messages intended for a window get handled on the thread that created and therefore owns the window.
From the MSDN:
The GetMessage function retrieves a
message from the calling thread's
message queue
So no, what you describe is not directly possible.
In your first example the Dialog and GetMessage are in separate threads. And the documentation says:
The GetMessage function retrieves a message from the calling thread's message queue.
The second example works since the calling thread (for GetMessage) also owns the Dialog.
Use AttachThreadInput.
In your example programm finish after create window.
But anyway in win32 all threads have own message queue.
And all message queues get messages for windows created in this thread.
see:
http://msdn.microsoft.com/en-us/library/ms644928(VS.85).aspx (Using Messages and Message Queues)
http://msdn.microsoft.com/en-us/library/ms644936(VS.85).aspx (GetMessage Function)
You can of course change the window procedure that handles messages for any window. Check the SetWindowLong function - http://msdn.microsoft.com/en-us/library/ms633591(VS.85).aspx - there are some rules as to what address space the new proc is. I suggest using a dll. Another way is to sub class the window message queue.
Of course you can !
Just use remote code injection ! (very classic !)
Related
When I create a window in C using the CreateWindow() function, it works fine it just disappears instantly, so I used the getch() function to try to resolve the issue but it does not work. The window does not display the button, and crashes.
But when I used MessageBox() instead of getch(), it stays and functions normally. I am trying to figure out why this happens.
I tried many things, like using MessageBox() and getch() together, using getch() before and after ShowWindow(), but every time it gives me some interesting result but not the normal functionality of the window.
Code that works:
#include <windows.h>
int _stdcall WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
HWND h;
HINSTANCE i;
h = CreateWindow("Button", "XYZ", WS_OVERLAPPEDWINDOW, 15, 20, 250, 200, 0, 0, i, 0);
ShowWindow(h, nCmdShow);
MessageBox(0, "Stop", "Wait", MB_OK);
return 0;
}
Code that does not work:
#include <windows.h>
int _stdcall WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
HWND h;
HINSTANCE i;
h = CreateWindow("Button", "XYZ", WS_OVERLAPPEDWINDOW, 15, 20, 250, 200, 0, 0, i, 0);
ShowWindow(h, nCmdShow);
getch();
return 0;
}
I want to know the reason for this error. I think it is because getch() is a DOS function, but still the compiler should at least show a warning.
There is no crash in this code.
Your getch() example simply lacks a message loop needed to service the window, and also getch() is meaningless in a non-console app. So your WinMain() exits immediately after showing the button window.
Whereas your MessageBox() example has a message loop (inside of MessageBox() itself) which keeps WinMain() running, and the button window processong UI messages, until the MessageBox dialog is closed.
Also, it doesn't make sense to try to display a button as its own overlapped window. You should be registering and creating a separate overlapped window that then creates the button as a child. User actions on the button are sent to the button's parent window, so you need to create a parent window for it.
Using the Win32 APIs, is it possible to create a Window or Dialog in one thread then collect events for it from another thread?
Are HWNDs tied to threads?
Trying the contrived example below I never see GetMessage() fire.
HWND g_hWnd;
DWORD WINAPI myThreadProc(LPVOID lpParam)
{
while(GetMessage(&msg, hWnd, 0, 0) > 0)
{
...
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MYDIALOG), 0, myDlgProc);
CreateThread(NULL, 0 myThreadProc, NULL, 0, NULL);
...
}
But here, I do.
HWND g_hWnd;
HINSTANCE g_hInstance;
DWORD WINAPI myThreadProc(LPVOID lpParam)
{
hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MYDIALOG), 0, myDlgProc);
while(GetMessage(&msg, hWnd, 0, 0) > 0)
{
...
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
g_hInstance = hInstance;
CreateThread(NULL, 0 myThreadProc, NULL, 0, NULL);
...
}
Can somebody explain what I'm seeing?
No.
GetMessage returns messages on the current thread's input queue. The HWND parameter is a filter, so that GetMessage only returns messages in the current thread's input queue intended for that window.
Windows have thread affinity - messages intended for a window get handled on the thread that created and therefore owns the window.
From the MSDN:
The GetMessage function retrieves a
message from the calling thread's
message queue
So no, what you describe is not directly possible.
In your first example the Dialog and GetMessage are in separate threads. And the documentation says:
The GetMessage function retrieves a message from the calling thread's message queue.
The second example works since the calling thread (for GetMessage) also owns the Dialog.
Use AttachThreadInput.
In your example programm finish after create window.
But anyway in win32 all threads have own message queue.
And all message queues get messages for windows created in this thread.
see:
http://msdn.microsoft.com/en-us/library/ms644928(VS.85).aspx (Using Messages and Message Queues)
http://msdn.microsoft.com/en-us/library/ms644936(VS.85).aspx (GetMessage Function)
You can of course change the window procedure that handles messages for any window. Check the SetWindowLong function - http://msdn.microsoft.com/en-us/library/ms633591(VS.85).aspx - there are some rules as to what address space the new proc is. I suggest using a dll. Another way is to sub class the window message queue.
Of course you can !
Just use remote code injection ! (very classic !)
I have been working on a project which needs to detect current active window and get the active window title continuously.
Can anyone explain me how to use SetWinEventHook() function to get Active Window changed message.
[ i used GetForegroundWindow() function with a timer to get the active window. That approach is not very accurate because of the timer. So i need to use it with SetWinEventHook() function. can someone explain me how to do that? ]
hEvent = SetWinEventHook(EVENT_SYSTEM_FOREGROUND , EVENT_SYSTEM_FOREGROUND ,NULL,
WinEventProcCallback, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
VOID CALLBACK WinEventProcCallback ( HWINEVENTHOOK hWinEventHook, DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
/* how to get active window message */
}
I have found the solution. EVENT_SYSTEM_FOREGROUND Event is the missing piece. The system sends this event even if the foreground window has changed to another window. We can use this event to get the current active window.
VOID CALLBACK WinEventProcCallback ( HWINEVENTHOOK hWinEventHook, DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
if (dwEvent == EVENT_SYSTEM_FOREGROUND)
{
/* do something */
}
}
Disclaimer: I'm somewhat of a noob when it comes to multi-threading. I've read stuff online, have done some simple multi-threading examples.
I've got a Win32 app that wants to draw the stuff in one thread and handle the Win32 messages in another thread. However, after the windows is created and the threads start, it hangs. I have a hunch that it may have to do with WaitForMultipleObjects(), but I don't know how to make it right. Does anyone have any idea why this is happening? Should I suspend and resume threads?
Here's my code:
WinAPI:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nCmdShow)
{
/* initialization blah blah */
zgE->startThreads(); // <--- starts the 2 threads
WaitForMultipleObjects(zgE->getThreadsNo(), zgE->getThreads(), TRUE, INFINITE);
return TRUE;
}
This is how I start the threads:
void zgEngine::startThreads()
{
/* allocation and stuff, blah blah blah */
m_arrThreads[m_nThreads++] = CreateThread(NULL, 0, &zgEngine::handleMsg, (void*)this, NULL, NULL);
m_arrThreads[m_nThreads++] = CreateThread(NULL, 0, &zgEngine::drawObjects, (void*)this, NULL, NULL);
assert(m_nThreads <= THREADS_NO);
}
And the 2 functions that draw & handle messages are quite simplist. A while loop in each of them.
// draw function
DWORD WINAPI zgEngine::drawObjects(LPVOID lpParam)
{
while (true)
{
/* draw stuff - valid code that if called outside this function
works as intended */
}
return TRUE;
}
// message handler function
DWORD WINAPI zgEngine::handleMsg(LPVOID lpParam)
{
MSG msg;
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// Process the message
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return TRUE;
}
When I don't use threads and remove the "while (true)" in drawObjects(), but leave the code (to be executed only once), don't call handleMsg() and make WinMain like in the example below, it works like a charm.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nCmdShow)
{
/* initialization blah blah */
MSG msg;
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// Process the message
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
zgEngine::DrawObjects(zgE);
}
}
return TRUE;
}
Later edit: from what I've seen, PeekMessage() always returns 0 :(
Quote from PeekMessage on Microsofts website:
A handle to the window whose messages are to be retrieved. The window
must belong to the current thread.
If hWnd is NULL, PeekMessage retrieves messages for any window that
belongs to the current thread, and any messages on the current
thread's message queue whose hwnd value is NULL (see the MSG
structure). Therefore if hWnd is NULL, both window messages and thread
messages are processed.
If hWnd is -1, PeekMessage retrieves only messages on the current
thread's message queue whose hwnd value is NULL, that is, thread
messages as posted by PostMessage (when the hWnd parameter is NULL) or
PostThreadMessage.
I suspect the thread doesn't have a "current window", and the "current threads message queue" isn't the one that Windows actually posts the messages onto as the default thread. This is only an assumption, since it is entirely possible that there are other problems (as well?) with your approach. But I believe this is a main portion of where the problem lies.
The following code works fine. It gives out the message when the user presses a key. But there are certain things I am not aware of. What is the role of Message Loop here ? I read that calling SetWindowsHookEx(...) registers a function with the windows and windows calls the appropriate function automatically when a event of registered type happens. No doubt that i don't see the output if don't give the message loop it's space.
#include<iostream>
#include <windows.h>
using namespace std;
HINSTANCE hinst = NULL;
static HHOOK handleKeyboardHook = NULL;
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
void setWinHook() {
handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc,NULL, 0);
if(handleKeyboardHook == NULL) {
cout << "is NULL";
} else {
cout << "is not NULL";
}
cout<<("Inside function setWinHook !");
}
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
cout << ("You pressed a key !\n");
return CallNextHookEx(handleKeyboardHook, nCode, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, 0);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
EDIT
Does exiting the program (closing the console window) unregister the hook ?
EDIT 2
what role does Dispatch Message play here ? According to doc it dispatches a message to window procedure,but here even if i exclude that,it doesn't effect the output.
All events in Windows, even the low-level keyboard event used in your example, is sent using the normal message events. So for the program to be able to sense keyboard events, it has to use an event loop processing messages.
Without a loop, the program would exit immediately, and the hook would be removed at once too. You cannot register a hook and exit — the system would become a mess if buggy programs were leaving too many forgotten hooks after them. Once your process dies, the hook is scheduled for removal.
I don't remember about low-level keyboard hook, but callbacks of many other hooks are only called inside GetMessage/PeekMessage, and not on some other thread, so just an infinite loop won't suffice — it has to be a message loop.
"what role does Dispatch Message play here ? According to doc it dispatches a message to window procedure,but here even if i exclude that,it doesn't effect the output."
DispatchMessage is pretty useless cos console window doesnt receive much messages.
Only message received is when window loses focus.