How to capture WM_SHOWWINDOW command in MFC - winapi

I am trying to do some action whenever dialog box is Shown. Its like we have modalless dialog, and we are hinding/showing the dialog on some button click. But we we need to perfomr some action whenever dialog is shown. I have added the WM_SHOWWINDOW message but control is not coming inside of OnShowWindow(BOOL bShow, UINT nStatus) function.
We are using ShowWindow(SW_HIDE) and ShowWindow(SW_SHOW) function to hide/show dialog box
Please suggest some pointer how to achieve that.
Thanks in advance
Mukesh

I tested this with notepad and Spy++ with the following code:
#include <Windows.h>
int CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) {
HWND hwnd = FindWindow(NULL, L"Untitled - Notepad");
ShowWindow( hwnd, SW_HIDE );
Sleep(4000);
ShowWindow( hwnd, SW_SHOW );
return ERROR_SUCCESS;
}
For hiding the window, you should be getting WM_SHOWWINDOW, WM_WINDOWPOSCHANGING, then finally WM_WINDOWPOSCHANGED.
For showing the window, the target did not receive WM_SHOWWINDOW, but still got WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED.
You could handle WM_WINDOWPOSCHANGED and check the flags in WINDOWPOS for SWP_HIDEWINDOW/SWP_SHOWWINDOW.

Related

Trouble catching WM_INPUT message for lParam, to collect Raw Mouse Input

For my college project I am developing a solution to distinguish between mouse user data from a person with Parkinson's compared to a healthy person. For which I need mouse data, ideally raw.
I presume I have misunderstood how to collect raw mouse input from the WM_INPUT message but I cannot figure it out.
I have been looking at the following thread: How to accurately measure mouse movement in inches or centimetres for a mouse with a known DPI
and Mouse input libraries on github all of which seem to easily catch a WM_INPUT message whose lParam is a handle to some RawInputData with something like this:
GetMessage(&msg, GetActiveWindow(), WM_INPUT, 0);
if (msg.message == WM_INPUT){ .....
And then retreiving the lParam from the message and collecting the data associated with that handle with:
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));
However when I call GetMessage in my main loop, the function never exits!
Consequently there is no way (that i know of) for me to get a handle to the RawInputData. Especially since the MSDN page just assumes you have the lParam already.
In summary I need a method of getting an lParam to pass to the GetRawInputData function which will remain active whether the program is running in the active window of not.
I'm running this code in a blank C++ CLR project in Visual Studio with the "winuser.h" library.
#include "stdafx.h"
#include "Windows.h"
#include "winuser.h"
#ifndef HID_USAGE_PAGE_GENERIC
#define HID_USAGE_PAGE_GENERIC ((USHORT) 0x01)
#endif
#ifndef HID_USAGE_GENERIC_MOUSE
#define HID_USAGE_GENERIC_MOUSE ((USHORT) 0x02)
#endif
int main(array<System::String ^> ^args)
{
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
Rid[0].dwFlags = 0; //ideally RIDEV_INPUTSINK but that prevents registration
Rid[0].hwndTarget = GetActiveWindow(); //ideally this would be Null to be independent of the active window
if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) {
//registration failed. Call GetLastError for the cause of the error
Console::WriteLine("Registration Error");
}
MSG msg;
while (true) {
while (GetMessage(&msg, GetActiveWindow(), WM_INPUT, 0) != 0) { //this command is never completed
DispatchMessage(&msg); //this line is never ran
}
if (msg.message == WM_INPUT) {
Console::WriteLine("caught a message!!!");
}
}
}
Issue solved after much more research I found the winAPI walk through which I followed fixing the issue above by adding an:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE unused, PSTR cmd, int show) {.....}
Function to register devices and create a window then call GetMessage which calls LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {....} with the parameters occupied by the message ID,WParam and LParam corresponding the message event.
For anyone stuck with a similar issue follow this MSDN guide: https://msdn.microsoft.com/en-us/library/bb384843.aspx

using hook on OPENFILEW dialog disables resize control

Using this code the resulting dialog box is drawn without ability to be able to be resized by mouse:
#include <windows.h>
static UINT_PTR CALLBACK OFNHookProc (HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
return 0;
}
int main() {
OPENFILENAMEW ofn;
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(OPENFILENAMEW);
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_ENABLEHOOK;
ofn.lpfnHook = OFNHookProc;
GetOpenFileNameW(&ofn);
return 0;
}
Removing OFN_ENABLEHOOK shows correct dialog window with resize indicator at bottom right corner. How to make dialog that is user-resizeable and with hook procedure ?
(of course that hook is mock here, only to illustrate the error, no matter what I put inside, of course if it is correct on other matters, result is the same)
You need to include the OFN_ENABLESIZING flag when using OFN_ENABLEHOOK. This is documented behavior:
OPENFILENAME structure
OFN_ENABLESIZING
0x00800000
Enables the Explorer-style dialog box to be resized using either the mouse or the keyboard. By default, the Explorer-style Open and Save As dialog boxes allow the dialog box to be resized regardless of whether this flag is set. This flag is necessary only if you provide a hook procedure or custom template. The old-style dialog box does not permit resizing.

WINAPI keyboards detect other application hotkeys

Goal : I want to know that the user did or did't press on some hotkeys that i want to know it, like i want to know he/she press Ctrl + N on chrome
i try to detect the application hotkeys, like maybe chrome Ctrl + N is open new tab.
How winapi can detect this?
i have seen some article that said WM_KEYUP + WM_KEYDOWN, but the wParam one times can get one WM_KEYUP or WM_KEYDOWN, how implement it ?
int main(int argc, char *argv[])
{
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardHookProc, hInstance, 0);
hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, hInstance, 0);
while (GetMessage(&message,NULL,0,0)) {
TranslateMessage( &message );
DispatchMessage( &message );
}
UnhookWindowsHookEx(hHook);
UnhookWindowsHookEx(hMouseHook);}
KeyBoardHookProc(int nCode, WPARAM wParam, LPARAM lParam){
KBDLLHOOKSTRUCT cKey = *((KBDLLHOOKSTRUCT*)lParam);
.................
if(wParam == WM_KEYUP)
{
kp.HandlekeyboardInfo(lpszName, buffer);
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
Thanks for helping!!
There are a few different ways you can do this. The easiest is probably to register a hotkey within your application and let windows notify you when the key combination is pressed.
RegisterHotKey
Another method would be to register a keyboard hook. All keypresses will be passed to your application, but you'll have to determine what keys were pressed. If you go this route, make sure to call CallNextHookEx().
SetWindowsHookEx

GetDlgCtrlID for top-level window with menu bar - return value

MSDN -> "GetDlgCtrlID function" -> Remarks:
"... Although GetDlgCtrlID may return a value if hwndCtl is a handle to a top-level window, top-level windows cannot have identifiers and such a return value is never valid."
It seems it is wrong information - "never valid".
At least for Win2k...Win8 this return value is just kernel pointer to hmenu(bar).
And my question is (primarily to MS insiders): why MSDN so inaccurate here?
(Screenshot: http://files.rsdn.ru/42164/gwl(-1)_tagwnd.png)
Upd (tagWND):
Also demo: http://files.rsdn.ru/42164/gwl(-1)_tagwnd.zip
It is not inaccurate. You create a top-level window with CreateWindowEx(). Which looks like this:
HWND WINAPI CreateWindowEx(
_In_ DWORD dwExStyle,
_In_opt_ LPCTSTR lpClassName,
_In_opt_ LPCTSTR lpWindowName,
_In_ DWORD dwStyle,
_In_ int x,
_In_ int y,
_In_ int nWidth,
_In_ int nHeight,
_In_opt_ HWND hWndParent,
_In_opt_ HMENU hMenu,
_In_opt_ HINSTANCE hInstance,
_In_opt_ LPVOID lpParam
);
Note how you don't specify the ID anywhere. But the fine print is in the description for the hMenu argument:
A handle to a menu, or specifies a child-window identifier, depending on the window style. For an overlapped or pop-up window, hMenu identifies the menu to be used with the window; it can be NULL if the class menu is to be used. For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window.
So you can have a menu OR a child ID. Overloaded, pretty common in the winapi, a child control can't have a menu and a toplevel window can't have a child ID. If you forge ahead and ignore this and call GetDlgCtrlID() on a toplevel window anyway then you will get back the value of the hMenu argument you specified in the create call. Well, today, always follow the api or you might get a rude surprise some day, you'd of course use GetMenu() instead.

Hooking a window with SetWinEventHook sometimes doesn't work

I wrote some code to watch for window title changes. It works fine with different windows in my Windows 7. I use SetWinEventHook like that:
SetWinEventHook(EVENT_OBJECT_NAMECHANGE,
EVENT_OBJECT_NAMECHANGE,
0,
WinEventCallback,
processId,
threadId,
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS | WINEVENT_SKIPOWNTHREAD);
Callback:
void CALLBACK WinEventCallback(HWINEVENTHOOK hWinEventHook,
DWORD dwEvent,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime)
{
qDebug("Window %p", hwnd);
...
GetWindowText(hwnd, ...);
}
For one specific window I see the debug message "Window 0x0" all the time, e.g. I get the window handle set to zero in the callback. In this case GetWindowText fails. All other windows work fine. The question is why? I don't see anything extraordinary in Spy++:
Not all events generated may be associated with a window, especially for something as generic as a name change. The hook documentation specifically states that NULL windows are possible, so simply ignore them if your hook logic is window-oriented. If you are seeing a window change its title but you are getting a NULL window in your callback, then either it is not a real window, or there was an issue marshaling the window to your callback, or something like that.
The problem comes for the WinEventCallback's signature you are using.
Fix it by using this one: WinEventCallback(IntPtr hWinEventHook, uint iEvent, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)

Resources