I am currently trying to grab all of the user input to the windows calculator app. It seems the way to do this is to use Win32 to intercept all of the keyboard and mouse inputs that are intended for the calculator window. I have read the MSDN page on subclassing a window at the link below and have done some research on subclassing.
I have the syntax for subclassing a window, but I am not sure how to tell the program which window I am looking to subclass.
the code that I have so far is listed below. My problem right now is that I am not sure how the variable "hWndEdit" is assigned. I am pretty new to Win32 programming so any help is appreciated.
(link)
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633570(v=vs.85).aspx
WNDPROC wpOrigEditProc;
wpOrigEditProc = (WNDPROC) SetWindowLong(hWndEdit,GWL_WNDPROC,(long) WndEditProc);
LRESULT CALLBACK WndEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CHAR:
case WM_KEYUP:
case WM_KEYDOWN:
if (hWnd == hWndEdit)
return 0;
break;
case WM_DESTROY:
// Remove the subclass from the edit control.
SetWindowLong(hWndEdit, GWL_WNDPROC, (LONG) wpOrigEditProc);
break;
default:
return CallWindowProc((WNDPROC ) wpOrigEditProc, hWnd, message, wParam, lParam);
}
return CallWindowProc((WNDPROC ) wpOrigEditProc, hWnd, message, wParam, lParam);
}
To find a window, first use Spy++ (A tool that gets installed with Visual Studio) to find the class name and the window name of the calculator main window. Then, in your application, use the FindWindow API:
hWndEdit = FindWindow(className, windowName);
Although, I'm not sure that subclassing is the right method here since the Calculator window is not owned by your application. You should do this with hooks.
Related
I've written a code that dynamically creates a POPUP style window when the user clicks inside my main app window. Now I'd like the POPUP window to be automatically destroyed when the mouse cursor goes out of the POPUP wnd region. I know that i have probably handle the WM_MOUSEMOVE message but how to do that? Please provide a simple code for that if You can...
Use the WM_MOUSELEAVE message instead. However, note that this message has to be explicitly requested via TrackMouseEvent(), which your window can call when it receives its first WM_MOUSEMOVE message.
As #Remy Lebeau said, the following is the code implementation.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL Tracing = FALSE;
switch (message)
{
case WM_MOUSELEAVE:
{
DestroyWindow(hWnd);
break;
}
case WM_MOUSEMOVE:
{
if (!Tracing)
{
Tracing = TRUE;
TRACKMOUSEEVENT tme{};
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hWnd;
TrackMouseEvent(&tme);
}
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
you can compare the event.target and event.currentTarget, if both are same then you are out side of popup window else in side the popup window.
my English is bad. sorry
HWND DIALOG_0 = CreateWindowEx(0, WC_DIALOG, "Security Alert", DS_SETFONT | WS_OVERLAPPEDWINDOW | WS_VISIBLE, 600,300,300,200,Win.hwnd_0,NULL,NULL,NULL);
(WNDPROC)SetWindowLongPtr(DIALOG_0 , GWLP_WNDPROC, (INT_PTR)dede);
ShowWindow (DIALOG_0, SW_SHOW);
UpdateWindow(DIALOG_0);
How do I do the shut down event.
How do I make HWND click events
I use it, but it gets locked up.
(WNDPROC)SetWindowLongPtr(DIALOG_0 , GWLP_WNDPROC, (INT_PTR)dede);
WC_DIALOG create dede function
LONG_PTR __stdcall Win32::dede(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CTLCOLORDLG:
return (INT_PTR)GetStockObject(HOLLOW_BRUSH);
break;
default:
DefWindowProc(hDlg, message, wParam, lParam);
break;
}
return (INT_PTR)FALSE;
}
You usually create dialogs with DialogBox or CreateDialog, not with CreateWindow. If you use CreateWindow then you cannot use the DS_ styles.
GWLP_WNDPROC replaces the original window procedure and you normally should call CallWindowProc, not DefWindowProc. If you don't do this then you don't get the default IDCANCEL handling and all the other things a dialog usually provides.
Catch WM_CLOSE and WM_COMMAND to handle close and click events.
MSDN has a dialog guide here.
I am having issues with creating a modeless dialog from a DLL file. My dialog has nothing special on it, just an OK button and an edit box. I have looked at this Microsoft KB Article (http://support.microsoft.com/kb/233263) and have implemented its solution to create a window hook to grab and process messages.
The method provided by Microsoft solves the tab key problem, however, it creates another problem. When I type into the edit box on the dialog, whatever I press is duplicated 4 times. For example, if I press 'a' on the keyboard, 'aaaa' will show up in the edit box.
If I disable the Window Hook, then the edit box works correctly and only displays one 'a'.
What do I need to do to the Window Hook procedure to solve this problem?
Any help is greatly appreciated.
- - EDIT - -
As per request, my Window Hook Procedure Code: (It's the same as the KB article)
LRESULT FAR PASCAL GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) {
LPMSG lpMsg = (LPMSG) lParam;
if (nCode >= 0 && PM_REMOVE == wParam) {
// Don't translate non-input events.
if ((lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST)) {
if (IsDialogMessage(hwndDllDlg, lpMsg)) {
// The value returned from this hookproc is ignored,
// and it cannot be used to tell Windows the message has been handled.
// To avoid further processing, convert the message to WM_NULL
// before returning.
lpMsg->message = WM_NULL;
lpMsg->lParam = 0;
lpMsg->wParam = 0;
}
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
My Dialog Callback Procedure:
BOOL CALLBACK DllDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_INITDIALOG:
hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, NULL, GetCurrentThreadId());
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
DestroyWindow(hwndDlg);
hwndDllDlg = NULL;
}
return TRUE;
case WM_DESTROY:
UnhookWindowsHookEx(hHook);
return FALSE;
}
return FALSE;
}
}
Both hHook and hwndDllDlg are defined as HHOOK and HWND respectively.
HHOOK hHook;
HWND hwndDllDlg = CreateDialog(0, MAKEINTRESOURCE(DLG_MAIN), 0, DllDlgProc);
I looked at the KB article. It sounds reasonable. There is some point where you was not enough accurate while following the instructions from KB. Post your code. This may help.
If you have control over the message pump of the executable and can add IsDialogMessage there, then you do not need any hook. Code from the dll is part of the code of the process. Window handles are in the common space either.
Other approach is starting your own UI thread. If you create your dialog on this thread, then you will have your own message pump. The hook will not be needed in this case either.
Well, this is more of a question to author of the post..
I have the tab key issue and am trying to understand the microsoft article better.
So my dialog is shipped out as Dll and the application which I don't have access to is launching dialog from my dll.
HWND hwndDllDlg = CreateDialog(0, MAKEINTRESOURCE(DLG_MAIN), 0, DllDlgProc);
I don't understand what dialog the code refers to when they said hwndDllDlg in the article. Should I point my dialog creation to this variable ?
I'm using Windows 7 and VC++. The business is to know how many seconds my system has been set into screen saver mode or monitor screen off. To achieve this, I'm trying to catch the events WM_SYSCOMMAND and SC_SCREENSAVE, SC_MONITORPOWER. So I have created a Win32 project in Visual Studio 2008 and I'm receiving the events in WndProc function:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_SYSCOMMAND:
{
switch (LOWORD(wParam))
{
case SC_SCREENSAVE:
{
FILE *fl = fopen("this_is_a_event_test.txt","a");
fputs("SC_SCREENSAVE\n",fl);
fclose(fl);
}
break;
case SC_MONITORPOWER:
{
FILE *fl = fopen("this_is_a_event_test.txt","a");
fputs("SC_MONITORPOWER\n",fl);
fclose(fl);
}
break;
default:
{
}
}
}
break;
}
}
It works fine when dialog is in foreground, but in background (or if I comment ShowWindow function) it only works if I manually send the events:
SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_SCREENSAVE, (LPARAM)2);
or
SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)2);
So, it is not working when system power configuration sets the screen saver after 2 minutes of inactivity, and the same thing with automatic monitor screen off. Thats the real thing I want, know when the system is turning off the screen or setting the screen saver, with a background monitoring program.
I have also tried to use hook events with extern dll. I have followed this example http://www.codeproject.com/Articles/1037/Hooks-and-DLLs adding in the CALLBACK msghook() function the same switch code above in WndProc. It doesn't work even using the SendMessage.
After several days stuck with this issue, searching in the Internet, forums... I don't know what else I can do. Can anyone help me?
I were not using hooks properly, but it has been rare. Firstly, about setWindowsHookEx function, I have read WH_CALLWNDPROC or WH_SYSMSGFILTER must be used to get WM_SYSCOMMAND sent messages, and then get SC_SCREENSAVE wParam. In this case, I don't know why and maybe I'm wrong, but thats seems not to be true.
After use every possible message to SetWindowsHookEx, I realised WH_GETMESSAGE is the only one who sends SC_SCREENSAVE wParam, at least in this hook example in Windows 7.
HHOOK hook;
HHOOK hook = SetWindowsHookEx(WH_GETMESSAGE,
(HOOKPROC)msghook,
hInst,
0);
Secondly, listening for every message catched in hook function, WM_SYSCOMMAND were appeared with LPMSG. I have read also that wParam must to be combined to 0xFFF0 to be compared. But wParam & 0xFFF0 == SC_SCREENSAVE didn't work and wParam == SC_SCREENSAVE neither. In this case the only way is using LPMSG for both WM_SYSCOMMAND and SC_SCREENSAVE.
static LRESULT CALLBACK msghook(UINT code, WPARAM wParam, LPARAM lParam)
{
if(code > 0)
{
CallNextHookEx(hook, code, wParam, lParam);
return 0;
}
LPMSG msg = (LPMSG)lParam;
if(msg->message == WM_SYSCOMMAND)
{
if (msg->wParam == SC_SCREENSAVE)
{
MessageBoxA(NULL,L"SC_SCREENSAVE",L"SC_SCREENSAVE",MB_OK);
}
if (msg->wParam == SC_MONITORPOWER)
{
MessageBoxA(NULL,L"SC_MONITORPOWER",L"SC_MONITORPOWER",MB_OK);
}
}
return CallNextHookEx(hook, nCode, wParam, lParam);
}
And using FILE to test the events was a very bad idea, I think using MessageBox is not much better but I don't know how to test ir correctly.
I'm trying to fix SHBrowseForFolder dialog, as it doesn't react on folder renaming (BFFM_SELCHANGED isn't being sent and there is no way to determine is the path now correct or not). I googled a solution, which said like I have to subclass dlg's wndproc and catch TVN_ENDLABELEDIT to send BFFM_SELCHANGED myself.
Here is how I set new wndproc when I get BFFM_INITIALIZED:
for (HWND hChild = GetWindow(hWnd, GW_CHILD); hChild != 0; hChild = GetWindow(hChild, GW_HWNDNEXT)) {
szClassName[256];
GetClassName(hChild, szClassName, sizeof(szClassName));
if (!stricmp(szClassName, "SHBROWSEFORFOLDER SHELLNAMESPACE CONTROL")) {
oldWndProc = reinterpret_cast<WNDPROC>(SetWindowLongPtr(hChild, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(_SubclassWndProc)));
break;
}
}
Here is _SubclassWndProc:
static LRESULT _SubclassWndProc(HWND hWnd, UINT uMsg, WPARAM lParam, LPARAM lpData) {
switch (uMsg) {
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code) {
case TVN_ENDLABELEDIT:
break;
}
break;
}
return CallWindowProc(oldWndProc, hWnd, uMsg, lParam, lpData);
}
It works only if I comment WM_NOTIFY block. Even an access to lParam breaks dialog (it contains corrupted treee with empty labels). If I call oldWndProc before switch, then it works, but in WM_NOTIFY case lParam obviously doesn't contain a pointer to NMHDR, it contains a small integer value like 1,2,100 etc.
Edit: The question can be shortened to "Why does WM_NOTIFY come without a pointer to NMHDR?"
The error was due to my negligence: I copied wndproc signature from some example, which has agrument names confused. The lParam usually comes last and has a type LPARAM. So I was trying to cast arg usually called wParam, which contains a control id not LPNMHDR.