I have gone through msdn to know GetMessage and DispatchMessage(&msg); function.
I had created a button application using visual c++ (x64).
The problem was when I used GetMessage my program was going in infinite loop. Suddenly I commented the GetMessage part and my buttons working fine (I just have two buttons that just two show different dialog box on different button click events).
I have two questions:
First, any ideas why on removing the GetMessage solved my problem (for your knowledge I have used CreateDialogParam and DialogProc for my button controls).
Second, as I understand (please correct me if I am wrong), GetMessage receives the message (if there are so many messages at once) and after that DispatchMessage(&msg); dispatches those messages one by one to let them finish their work. If the first finished then the second message is dispatched and so on, until all the messages have been processed.
My code is below:
m_hwndPreview = CreateDialogParam( g_hInst,MAKEINTRESOURCE(IDD_MAINDIALOG), m_hwndParent,(DLGPROC)DialogProc, (LPARAM)this);
if (m_hwndPreview == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
BOOL bRet;
MSG msg;
while ( (bRet=GetMessage (& msg, 0, 0, 0)) != 0)
{
if (bRet == -1)
{
bRet = HRESULT_FROM_WIN32(GetLastError());
MessageBox(NULL, L"Hurr i am the error",L"Error", MB_ICONERROR | MB_OK);
}
else if (!IsDialogMessage (m_hwndPreview, & msg))
{
TranslateMessage ( & msg );
DispatchMessage ( & msg );
MessageBox(NULL, L"there is no error in receivung the message", L"Error", MB_ICONERROR | MB_OK);
}
}
int refMsg= (int)msg.wParam;
refMsg;
Related
I'm trying to post message from one thread to a window in another thread via PostThreadMessage:
auto result = PostThreadMessage(mainThreadId, UserMessage::DestroyWindowRequest, 0, 0);
The MSDN says that
Messages sent by PostThreadMessage are not associated with a window. As a general rule, messages that are not associated with a window cannot be dispatched by the DispatchMessage function.
So I cann't just receive my message. Is it safe to handle a message manually in a message loop as in code below?
INT_PTR AbstractWindow::TranslateMessageLoop()
{
MSG msg{0};
BOOL gotMessage = FALSE;
static const BOOL hasError = -1;
PostMessage(windowHandle, UserMessage::MessageLoopTranslated, 0, 0);
while ((gotMessage = GetMessage(&msg, (HWND)NULL, 0, 0)) != 0 && gotMessage != hasError) {
// Here I process a message. I assume that the message is always destined for my main window,
// so I use it's handle - windowHandle.
if (!msg.hwnd && msg.message == UserMessage::DestroyWindowRequest) {
DestroyWindow(windowHandle);
}
else {
if (PreTranslateMessage(&msg) == FALSE) {
if (IsDialogMessage(windowHandle, &msg) == FALSE) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
return msg.wParam;
}
I know, MSDN suggest to use custom hooks, but it's a little bit overkill for me now.
I have a function export OpenUI() in a DLL for UI view which creates the modeless main dialog and also has a modeless child dialog.
I am calling the function export OpenUI() from a separate DLL which is my controller.
How can I possibly execute more code after the function call if the message loop in OpenUI() prevents the function to return unless the dialog is closed?
I cannot remove the message loop because tab stop will not work without it.
I need the function export to return immediately after execution therefore I cannot use a modal dialog. Creating a subthread is also not an option because it caused issues in my application.
Any help is highly appreciated.
Thank you.
Pseudocode for my controller dll
typedef int(*DLL_OPENUI)();
int func()
{
HINSTANCE hinst_dll = LoadLibrary(dll_path);
DLL_OPENUI DllOpenUI = (DLL_OPENUI)GetProcAddress(hinst_dll, "OpenUI");
int ret = DllOpenUI();
//...execute more code here
return ret;
}
Pseudocode for my UI view dll
__declspec(dllexport) OpenUI()
{
hwnd_main = CreateDialog(hinst, IDD_MAIN, MainDlgProc);
ShowWindow(hwnd_main, SW_SHOW);
MSG msg;
while ((GetMessage(&msg, NULL, 0, 0) > 0))
{
if (!IsDialogMessage(hwnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
LRESULT CALLBACK MainDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
OnInitDialog();
break;
}
}
void OnInitDialog()
{
CreateDialog(hinst, IDD_NAV_PANE, hwnd_main, NavPaneProc);
CreateDialog(hinst, IDD_NAV_TABS, hwnd_main, NavTabsProc);
CreateDialog(hinst, IDD_TAB_1, hwnd_main, TabOneProc);
CreateDialog(hinst, IDD_TAB_2, hwnd_main, TabTwoProc);
CreateDialog(hinst, IDD_TAB_3, hwnd_main, TabThreeProc);
CreateDialog(hinst, IDD_DETAILS_PANE_BG, hwnd_main, BackgroundProc);
CreateDialog(hinst, IDD_DETAILS_PANE, hwnd_main, DetailsPaneProc);
//...execute more code below
}
You have to have an active message loop, there's no way around that. One way to do it is to have one new function that would PeekMessage and execute the loop code only once. PeekMessage returns non-zero value if subsequent call to GetMessage would actually get a message and not block instead. ProcessOneMessage may look something like this:
BOOL ProcessOneMessage(HWND hwnd)
{
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
return TRUE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return FALSE;
}
So, in your main code you have to call this function often (once every 10 ms should be fine). Whatever the code does it must call the function once in 10 ms. You will have a live window and run your code at the same time. But once the function returns TRUE the window was closed and you must not call the function again. For more info search for PeekMessage. The code is taken from this link: https://jeffpar.github.io/kbarchive/kb/074/Q74042/
I have a weird problem over here. I created a DLL proxy for Spotify so I can "overlay" a button onto it. Basicially, thats how it works:
DllMain
-> Creates CMain class
-> Creates CToggleButton class
-> Hooks the button onto the Spotify window
It has two methods, one static one which I use for the thread since threads can't call member functions, and one non-static function which gets called by the member function.
With this, I create the thread and pass an instance of the CToggleButton class via lpParam:
CreateThread(0, NULL, WindowThreadStatic, (void*)this, NULL, NULL);
Then, the WindowThreadStatic function:
DWORD WINAPI CToggleButton::WindowThreadStatic(void* lpParam)
{
return ((CToggleButton*)lpParam)->WindowThread();
}
And the main window thread function inside the class:
DWORD CToggleButton::WindowThread()
{
MSG msg;
hButton = CreateWindowA("BUTTON", "Test", (WS_VISIBLE | WS_CHILD), 0, 0, 100, 20, parenthWnd, NULL, hInst, NULL);
bool bQueueRunning = true;
while (bQueueRunning)
{
if (PeekMessage(&msg, parenthWnd, 0, 0, PM_REMOVE))
{
switch (msg.message)
{
case WM_QUIT:
bQueueRunning = false;
break;
case WM_LBUTTONDOWN:
if (msg.hwnd == hButton)
{
MessageBoxA(parenthWnd, "Button!", "Button", MB_OK);
continue;
}
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Sleep(10);
}
return 0;
}
As you can see, this also contains the message loop for the button (I didn't use GetMessage() here because it was very unresponsive so I decided to use PeekMessage() together with a 10ms delay, which works fine.)
Little picture to show how it looks like:
All great, but if I maximize the window, the button disappears. When I minimize and maximize the window a few times, the button can be seen again, but with very weird coordinates (not the original 0,0 I gave him).
So what is my problem here? Why do the coordinates get offset?
Thanks for reading my long post :)
I have a basic window program, the problem is when i try to create a window in a new thread after the message loop has already started the window displays for a second and disappears. does anyone no the reason for this? can a window be created in a separate thread?
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
::hInstance =hInstance; // initialize global variables
::nCmdShow =nCmdShow;
// start thread
HANDLE threadHandle = startThread(StartUp);
MSG msg;
while(GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
::CloseHandle(threadHandle);
return static_cast<int>(msg.wParam);
}
DWORD WINAPI StartUp(LPVOID lpParam) // new thread runs here
{
//code to create a new window...
}
what i figured out so far is that the GetMessage(&msg, 0, 0, 0) returns false if there are no windows in the current thread that it is in... is there a way to get a round this?
GetMessage() does not return FALSE if there are no windows. It is only looking for messages in the calling thread's message queue. You are specifying NULL for its hWnd parameter, so it will not care how messages get queued, whether by PostMessage() to a window, or by PostThreadMessage() to the thread's ID.
Each thread has its own local message queue and thus requires its own message loop. You can most certainly create a new window in a worker thread after the main thread has started its message loop. They are independent of each other. So whatever problem you are having in the main thread is not related to creating a window in a worker thread. Something else is going on.
With that said, keep in mind that GetMessage() returns a BOOL, which is actually an int, not a true bool. GetMessage() can return one of 3 different return values:
-1 if an error occurs
0 if a WM_QUIT message is retrieved
>0 if any other message is retrieved
You are only checking for 0 and != 0, so if GetMessage() returns -1 on error, you are treating it as a success instead of a failure. Even MSDN says not to do that:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644936.aspx
Because the return value can be nonzero, zero, or -1, avoid code like this:
while (GetMessage( lpMsg, hWnd, 0, 0)) ...
The possibility of a -1 return value means that such code can lead to fatal application errors. Instead, use code like this:
BOOL bRet;
while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
How to get the handle HWND of the dialog which user open when clicking on a button.
I'm using Spy++ to find the window class and tittle, but it says that no such window is found. And how then to get the handle of that dialog in C++ using Win API ?
I hope that I will be able to do that using simple functions as FindWindow, GetParent, any WIN APi function. I do not like to inject something or load DLL. Thanks
UPDATE:
the folder browser dialog is opened by other program. I want to get it's handle from different program , my program. Thanks.
The closest to want i need is for now the function WindowFromPoint
Accessibility will let you capture window creation events from other processes without DLL injection. You can modify the example to accommodate for the browsing window specifically. Here's an example I made previously to test that is based on the one from the article. Modify it however you wish:
#include <iostream>
#include <windows.h>
void CALLBACK proc(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG obj, LONG child, DWORD thr, DWORD time) {
if (hwnd && obj == OBJID_WINDOW && child == CHILDID_SELF) {
switch (event) {
case EVENT_OBJECT_CREATE: {
std::cout << "Window created!\n";
break;
}
case EVENT_OBJECT_DESTROY: {
std::cout << "Window destroyed!\n";
break;
}
}
}
}
int main() {
HWINEVENTHOOK hook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_DESTROY, nullptr, proc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (hook) {
UnhookWinEvent(hook);
}
}