How to use a handle as a function parameter? - c++

I was writing code for a win32 application when I came across a problem, how to use a handle as a function parameter. For instance whit this function:
void refreshWindow (HWND myWNDhandle)
{
InvalidateRect(myWNDhandle, NULL, FALSE);
}
If I would pass in "hwnd" as the parameter and run the code, like this:
refreshWindow (hwnd);
I would assume my window will be painted again, unfortunately my window won't.
What did i do wrong?

Mechanically your call is perfect. So either the HWND itself is invalid and, as other commenters suggest, you should assert on IsWindow() to validate that, or you are falling victim to the asynchronous nature of window repainting:
Calling InvalidateRect will merely mark the window as in need of painting, and a subsequent call to GetMessage will generate a paint message to paint the window if there are no other higher priority events or messages to process.
Typically then, methods that want to refresh the contents of a window immediately, follow the call to InvalidateRect with a call to UpdateWindow - which will ensure the window is repainted before returning.

Related

Purpose of WM_CREATE message?

What's the point of having the WM_CREATE message when you can create windows without it.
Calling void CreateWindowA outside of WM_CREATE works so what's the deal?
WM_CREATE message is received by window procedure when window is created and not shown yet. You can prepare initial state. For example, you can create controls (child windows), set default values for controls, etc. If something is wrong, you can cancel creation of window and it will not be shown. In other words, in WM_CREATE you can add custom extension to CreateWindow API.
There are many reasons why an application could want/need to intercept the WM_CREATE message. For example, you may want to check a for a particular condition, and prevent the actual creation if that condition is wrong: you can do this by returning -1 from the WndProc that handles the message (see the documentation):
If an application processes this message, it should return zero to
continue creation of the window. If the application returns –1, the
window is destroyed and the CreateWindowEx or CreateWindow function
returns a NULL handle.
What's the point of having the WM_CREATE message when you can create
windows without it.
If you don't handle WM_CREATE message explicitly, it is actually handled by system via DefWindowProc(hwnd, uMsg, wParam, lParam); implicitly. So you see the window visible.
WM_CREATE message is sent before the CreateWindowEx or CreateWindow function returns, that give you an opportunity to intervene the result of mentioned function. You can allow (return zero to continue creation of the window) or prevent (returns –1, the window is destroyed) the window to be visible, and how it will looks like.
The WM_NCCREATE and WM_CREATE message are sent before the window
becomes visible. That makes them a good place to initialize your
UI—for example, to determine the initial layout of the window.
Refer to "Managing Application State", "WM_CREATE message".

::PostMessage doesn't work when I am tabbed in to another program

In our Program we have a Dialog from a separate dll open to display infomation. I need to close this dialog when our system timer causes the system to lock.
I send information to the dll by registering a system message in both my MainFrm and EditDisplayDll
SYSTEMLOCK = RegisterWindowMessage("SystemLock");
When I sent the message via
::PostMessage(GetActiveWindow()->m_hWnd,SYSTEMLOCK,0,0);
The message correctly sends to my EditDisplayDll and closes the dialog when the system locks; however, if I alt tab while waiting for the timeout and use another program(firefox, outlook, etc.) the message never correctly calls to the EditDisplayDll. The MainFrm and other windows inside of the MainFrm correctly lockout and hide themselves in either case.
I have tried also using HWND_BROADCAST with PostMessage and SendNotifyMessage. I have also tried to use FindWindow() and FindWindowEx() to specifically call the EditDisplayDll.
I cannot use something like GetDlgItem() because my MainFrm.cpp doesn't have access to this dll.
My decision to use GetActiveWindow() was because I believe it looks to windows specific to my program no matter what window I am in as seen in the imagery in Foreground Vs Active window
Finally, my question is, is there a way to call all Windows in my program no matter what program I am currently in or is there another way I could get access to the specific IDD of the EditDisplayDll in order to send the SYSTEMLOCK message to it?
CWnd *cWndED = FindWindow(_T("EditDisplay"),_T("EditDisplay")); HWND
hwnd = (HWND)cWndED;
You should use win32 API ::FindWindow with proper class, window name. And do not cast CWnd pointer to HWND. Your code should look like:
HWND hWnd = ::FindWindow(_T("ProperClass"), _T("ProperNmae"));
if (hWnd != NULL)
{
::PostMessage(hWnd, YOUR_MESSAGE, ....);
}
I will suggest you to find your Dll window class and name using Spy++ and then try to find that using above method. Remember it's always better to use native API for this kind of tasks.
FindWindow is a good solution if you know both, name of the window and the element.
If you want to get the HWND of your window - no element inside the window -, you can pass as first parameter NULL.
::FindWindow(NULL, _T("WindowName"));
Back to your code: If you are lucky your PostMessage does nothing, otherwise the active window may catch your message. Who knows how/if it is handled in the active window ? Use the PostMessage if you have a valid IsWindow(HWND) from FindWindow or FindWindowEx.
In case you want a CWnd from your HWND take a look at this. (The call may be slow)
HWND hWnd = ::FindWindow(_T("ClassName"), _T("WindowName"));
if (hWnd && IsWindow(hWnd))
{
::PostMessage(hWnd, MESSAGE_TO_BE_SEND, lParam_or_Flags);
}

WinAPI - message loop with own callback

The usual WinAPI message loop looks something like this:
MSG msg;
while (GetMessage(&msg, hwnd, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Is it allowed not to call DispatchMessage() but to handle the message on your own? If not, how could I nicely approach this behavior while avoiding global variables and thread problems?
Edit:
I basically want to use my own callback function, which hasn't the WndProc signature. But I can't think of a way to call that function out of a WndProc without using static or global variables.
[Which would require locking, which I think isn't the best thing you can do with a callback function which probably gets called very frequently.]
Thanks for your help.
Is it allowed not to call DispatchMessage() but to handle the message on your own? If not, how could I nicely approach this behavior while avoiding global variables and thread problems?
If you are planning to use multiple threads in your GUI then each thread that creates a window will need to manage it's own message queue.
From this page: http://msdn.microsoft.com/en-us/library/ms810439.aspx
Changes to the Message Loop
Applications with multiple threads must include a message loop in each
thread that creates a window. The message loop and window procedure
for a window must be processed by the thread that created the window.
If the message loop does not reside in the same thread that created
the window, the DispatchMessage function will not get messages for the
window. As a result, the window will appear but won't show activation
and won't repaint, be moved, receive mouse messages, or generally work
as you expect it to.
You can react to a message there, but you still need/want to call DispatchMessage and actually handle the message in your normal wndproc. I'd be happy to say more about avoiding globals and/or threading problems, but it's hard to comment without more details about what you want to avoid.
Yes, you can handle the message yourself, if you wish. I usually set the result field to 0, but Windows only make use of this field for a few messages.

Is there any function called after the OnInitDialog function in MFC?

I want to create a thread after the creation of a dialog box in MFC. Is there any function that Windows has provided and is automatically called after OnInitDialog so that I can create my thread inside it?
You can simply create your thread in the OnInitDialog function. There's no reason to overcomplicate things by going and searching for a different function, or splitting your initialization code up in two pieces. (There also isn't any such function, because there's no corresponding Windows message that is sent.)
If you want to get your dialog box on the screen before you create the thread, you can just show it manually using the ShowWindow function. For example:
ShowWindow(SW_SHOW);
RedrawWindow();
Also see this post by Raymond Chen: Waiting until the dialog box is displayed before doing something
OnInitDialog() is the main function called upon initialization (in reaction to WM_CREATE).
Why can't you create your thread in there?
I have changed the thread priority to below normal and when the thread executes for the first time I set the thread to normal priory. This works fine. Thanks for your response.
After many years of feeling unsatisifed with the OnTimer solution to draw first view graphics in an MFC dialog app (a favorite playground), this seemed like a nice simple solution:-
Add a WM_HSCROLL handler with class wizard.
At the end of OnInitDialog post a hscroll message with a NULL LPARAM
In handler detect the NULL, draw graphics.
a timer meant that the app was alive for some time before graphics happened, and apparently hscroll is prioritized to happen just after the WM_PAINT message which would erase a picture element to its blank state, deleting anything that was drawn during initdialog.
BOOL CSpecDlg::OnInitDialog()
{
...
PostMessage(WM_HSCROLL,0, (LPARAM)NULL);
return TRUE; // return TRUE unless you set the focus to a control
}
void CSpecDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
if (pScrollBar==NULL)
{
plot();
}
CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}

How to get HWND in win32?

Is there way to get the HWND handler of my window?
I'm using win32.
You could call GetActiveWindow to get the active control in your application, then repeatedly call GetParent on the returned handle until it returns NULL. The last valid handle you get should be the handle of your main window.
The easier way as someone else said is to store the returned value from CreateWindow somewhere.
It's probably good to understand why there is no simple way. It all boils down to "which window?". You'll likely have multiple windows visible on your screen, right now. For instance, the taskbar at the bottom of your screen is a window. even your own app typically has more than one. For instance, the "File Save" dialog is a window. Even the simple MessageBox is a window.
So, how do you identify which window you're talking about? The common answer is that you identify them by their HWND. So, to get the position of the "File Save" dialog window, you ask for the position associated with that HWND. Obviously, you can get any property that way, except the HWND itself ! It makes sense to ask the X/Y position of HWND(0x5e21), but it's stupid to ask which HWND belongs to HWND(0x5e21).
Now, it may happen that you have another more-or-less unique property and you want to get the HWND from that. For instance, you may have an X/Y position. In that case, WindowFromPoint(xy) will return the HWND at that position.
But the most common case is that you need to react to a Windows message for your window. In that case, you get the HWND of your window as the first argument of your WindowProc().
So, unless you tell us what unique information you do have, we can't tell you how to find the matching HWND.
Didn't you create your window via CreateWindow() or CreateWindowEx()? The CreateWindowEx() function and the CreateWindow() function both return the HWND of the newly created window.
Also, the operating system passes you the HWND of your window(s) via your window procedure. It's not a function that you call; it's a function that the operating system calls to let your application do any processing that's needed.