I want to use SetWindowsHookEx to call a function every time a user presses a key
the closest thing to what I'm trying to do is a keylogger
I've been inspiring from these projects GiacomoLaw/Keylogger and timsneath/win32/blob/master/example/tetris
I have little to no experience with winapi or c++ in general and I'm in the process of learning dart
sorry in advance for my messy code, the important filles are main.dart, lib/native_functions/SetWindowsHookEx.dart, lib/native_functions/GetModuleHandle.dart, lib/native_functions/CallNextHookEx.dart
here's the zip file
i just added this
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, lpfn, hmod, 0);
// more code above ^
// i added this
final MSG msg = MSG.allocate();
while (GetMessage(msg.addressOf, 0, 0, 0) != 0) {
TranslateMessage(msg.addressOf);
DispatchMessage(msg.addressOf);
}
don't forget to write bindings for GetMessage, TranslateMessage, DispatchMessage
Related
Given a valid hwnd, how can we verify if it is indeed the alt-tab window?
One of my previous methods was to get the class of the window that the hwnd belongs to, then compare it to these values: MultitaskingViewFrame, ForegroundStaging, TaskSwitcherWnd and TaskSwitcherOverlayWnd.
However, I've come to realise that class names are not unique across the system, and indeed one can RegisterClassEx a class with the same name as the above names, which means my method above would give false positives.
I found a working solution to the problem: additionally, filter by process path using GetWindowModuleFileNameW.
rough pseudocode:
if window.class() in [..] && GetWindowModuleFileNameW(window.hwnd) == "C:\Windows\explorer.exe" {
ignore()
}
Processes cannot fake their path, so this works.
I recommend using the SetWinEventHook function to get the active display information correctly.
HWINEVENTHOOK SetWinEventHook(
DWORD eventMin,
DWORD eventMax,
HMODULE hmodWinEventProc,
WINEVENTPROC pfnWinEventProc,
DWORD idProcess,
DWORD idThread,
DWORD dwFlags
);
DWORD eventMin,
DWORD eventMax,
It is sufficient to give the constants EVENT_SYSTEM_FOREGROUND as arguments.
If I press alt-tab, the window switches fast but the callback is fired
for the the Task Switcher window and some other invisible window with
class ForegroundStaging.
For invisible windows, you can use IsWindowVisible to filter.
For the the Task Switcher window, you can compare their title names to filter.
Some code:
void __stdcall Wineventproc(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD idEventThread, DWORD dwmsEventTime)
{
if (event == EVENT_SYSTEM_FOREGROUND)
{
if (IsWindowVisible(hwnd))
{
TCHAR title[512] = {};
int index = GetWindowText(hwnd, title, 512);
if (_tcsncmp(title, TEXT("Task Switching"), 14))
{
title[index] = L'\n';
title[index + 1] = L'\0';
OutputDebugString(title);
}
}
}
}
but I also need to account for rogue processes that try to masquerade
as ForegroundStaging etc.
This is a complicated question. No antivirus or protection technology is perfect. It takes time to identify and block malicious sites and applications, or trust newly released programs and certificates. With almost 2 billion websites on the internet and software continuously updated and released, it's impossible to have information about every single site and program.
In other words, it is not easy to efficiently identify the true identity of each unknown application.
Refer: Unknown – Unrecognized software
In our application that we've had for 15+ years, we have a type of progress bar.
This progress bar is for long lasting C++ operations and there is also the case for when we make a COM call and it takes a long time for the COM call to return.
In general, we want the user to know that something is taking a long time to complete and give him a chance to cancel if he thinks it is taking too much time.
For COM operations, many years ago we implemented a custom IMessageFilter for COM calls that take too long. We would like the user to be able to cancel but also for the prompt to cancel go away on its own when the operation completes. It has been working fine for years. Most of our customers are conservative and are still running Windows 7. Recently a customer using Windows 10 has found an issue where a COM call on Windows 10 never seems to never finish.
Our progress bar comes up and the progress control cycles and recycles, but the operation never seems to finish. After investigating it, it seems that the ICancelMethodCalls::TestCancel() method always returns RPC_S_CALLPENDING, it never returns RPC_E_CALL_COMPLETE. On Windows 7, previous versions of Windows, and Windows 8.1, it works fine, but not on Windows 10.
I created a minimal test solution in Visual Studio 2013 that demonstrates the problem. One project is an ATL server, and the other project is an MFC client application. A link to a zip file of a sample solution is here: https://www.dropbox.com/s/1dkchplsi7d6tda/MyTimeOutServer.zip?dl=0
Basically the ATL server has a property that sets a delay, and a method that just waits the delay length. The purpose is to simulate a COM operation that is taking too long.
interface IMyTimoutServer : IDispatch{
[propget, id(1), helpstring("Timeout value in milliseconds")] HRESULT TimeOut([out, retval] LONG* pVal);
[propput, id(1), helpstring("Timeout value in milliseconds")] HRESULT TimeOut([in] LONG newVal);
[id(2)] HRESULT DoTimeOut([out, retval] VARIANT_BOOL* Result);
};
The next important thing is the IMessageFilter in the client application. At some point, someone decided it was good to derive from COleMessageFilter, the default MFC implementation. (Let's not argue whether that is a good idea.)
The important methods of the the class are the MessagePending() and MyNotResponding().
DWORD CMyMessageFilter::XMyMessageFilter::MessagePending(HTASK htaskCallee, DWORD dwTickCount, DWORD dwPendingType)
{
METHOD_PROLOGUE_EX(CMyMessageFilter, MyMessageFilter);
ASSERT_VALID(pThis);
MSG msg;
if (dwTickCount > pThis->m_nTimeout && !pThis->m_bUnblocking && pThis->IsSignificantMessage(&msg))
{
if (pThis->m_bEnableNotResponding)
{
pThis->m_bUnblocking = TRUE; // avoid reentrant calls
// eat all mouse and keyboard messages in our queue
while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, AFX_WM_MOUSELAST, PM_REMOVE | PM_NOYIELD));
while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE | PM_NOYIELD));
// show not responding dialog
pThis->m_dwTickCount = dwTickCount;
bool bCancel = pThis->MyNotResponding(htaskCallee) == RPC_E_CALL_CANCELED;
pThis->m_bUnblocking = FALSE;
return bCancel ? PENDINGMSG_CANCELCALL : PENDINGMSG_WAITNOPROCESS; // if canceled, the COM call will return RPC_E_CALL_CANCELED
}
}
// don't process re-entrant messages
if (pThis->m_bUnblocking)
return PENDINGMSG_WAITDEFPROCESS;
// allow application to process pending message
if (::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE | PM_NOYIELD))
pThis->OnMessagePending(&msg); // IK: could also return a value from extended OnMessagePending() to cancel the call
// by default we return pending MSG wait
return PENDINGMSG_WAITNOPROCESS;
}
After a timeout, we display a status type window that updates in the NotMyResponding() method.
int CMyMessageFilter::MyNotResponding(HTASK hTaskBusy)
{
TRY
{
CComPtr<ICancelMethodCalls> pCancel;
HRESULT hRes = ::CoGetCancelObject(0, IID_ICancelMethodCalls, (void**)&pCancel);
ATLASSERT(SUCCEEDED(hRes)); // COM should automatically create Cancel objects for pending calls [both on client and server]
if (pCancel == NULL)
{
return COleBusyDialog::retry;
}
m_pFrame->EnableWindow(FALSE);
CMyCancelDlg dlg;
dlg.Create(CMyCancelDlg::IDD);
dlg.ShowWindow(SW_SHOWNORMAL);
HWND hWndDlg = dlg.GetSafeHwnd();
do
{
MSG msg;
for (int i = 0; i < 100 && PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD); ++i)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (dlg.StepAndCheckCancel())
{
dlg.DestroyWindow();
m_pFrame->EnableWindow(TRUE);
return RPC_E_CALL_CANCELED; // signals to MessagePending() that the COM call should be cancelled
}
Sleep(250); // this call has been pending for many seconds now... sleep for some time to avoid CPU utilization by this loop and yield if needed
hRes = pCancel->TestCancel();
} while (hRes == RPC_S_CALLPENDING);
ATLASSERT(hRes == RPC_E_CALL_COMPLETE);
dlg.DestroyWindow();
m_pFrame->EnableWindow(TRUE);
}
END_TRY
return RPC_E_CALL_COMPLETE;
}
Basically, in MyNotResponding(), we create a Cancel object, create a window with a cancel button, pump messsages, and look for either a press on the cancel button or if TestCancel() returns something other than RPC_S_CALLPENDING.
Well, on Windows 10, it stays in the loop and RPC_S_CALLPENDING is always returned from TestCancel().
Has anyone seen anything like this on Windows 10? Are we doing something wrong that we are really only getting lucky on Windows 7?
The default implementation of the MFC puts up an OLEUIBusy dialog which pumps messages. It just never tests the cancel object.
Here is the scenario:
I have 2 apps. One of them is my main app, and the second is a dialog based app, which is started from the first one. I'm trying to capture the main handle of the dialog based app from my main app. The problem is that I cannot find it with EnumWindows. The problem disappears if I put sleep for a second, just before start enumerating windows.
This is the code:
...
BOOL res = ::CreateProcess( NULL, _T("MyApp.exe"), NULL, NULL, FALSE, NULL, NULL, NULL, &siStartInfo, &piProcInfo );
ASSERT(res);
dwErr = WaitForInputIdle(piProcInfo.hProcess, iTimeout);
ASSERT(dwErr == 0);
//Sleep(1000); //<-- uncomment this will fix the problem
DWORD dwProcessId = piProcInfo.dwProcessId;
EnumWindows(EnumWindowsProc, (LPARAM)&dwProcessId);
....
BOOL IsMainWindow(HWND handle)
{
return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
}
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
DWORD* pParam = (DWORD*)lParam;
DWORD dwTargetProcessId = *pParam;
DWORD dwProcessId = 0;
::GetWindowThreadProcessId(hwnd, &dwProcessId);
if (dwProcessId == dwTargetProcessId )
{
TCHAR buffer[MAXTEXT];
::SendMessage(hwnd, WM_GETTEXT, (WPARAM)MAXTEXT,(LPARAM)buffer);
if( IsMainWindow(hwnd))
{
g_hDlg = hwnd;
return FALSE;
}
}
return TRUE;
}
There are exactly 2 windows which belongs to my process and tracing their text shows:
GDI+ Window
Default IME
I'm not quite sure what does this mean. These might be the default captions, assigned to the windows, before their initialization.... but I call EnumWindows after WaitForInputIdle ...
Any help will be appreciated.
CreateProcess returns, when the OS has created the process object including the object representing the primary thread. This does not imply, that the process has started execution.
If you need to query another process for information that is only available after that process has run to a certain point, you will need to install some sort of synchronization. An obvious option is a named event object (see CreateEvent), that is signaled, when the second process has finished its initialization, and the dialog is up and running. The first process would then simply WaitForSingleProcess, and only continue, once the event is signaled. (A more robust solution would call WaitForMultipleObjects on both the event and the process handle, to respond to unexpected process termination.)
Another option would be to have the second process send a user-defined message (WM_APP+x) to the first process, passing its HWND along.
WaitForInputIdle sounds like a viable solution. Except, it isn't. WaitForInputIdle was introduced to meet the requirements of DDE, and merely checks, if a thread in the target process can receive messages. And that really means any thread in that process. It is not strictly tied to a GUI being up and running.
Additional information on the topic can be found here:
WaitForInputIdle should really be called WaitForProcessStartupComplete
WaitForInputIdle waits for any thread, which might not be the thread you care about
I previously asked a question about something similar but I believe this time the circumstances are different.
I have a DLL that has standard hook, unhook and msgProc functions. I load this DLL in my main application and then call 'hook', that is below:
HOOKDLL_API BOOL setHook( HWND hWnd, DWORD threadID )
{
if( hWndServer != NULL )
return FALSE;
hook = SetWindowsHookEx( WH_GETMESSAGE, (HOOKPROC)msghook, hInstance, threadID );
if( hook != NULL )
{
hWndServer = hWnd;
ofstream logFile;
logFile.open( "LOG.txt" );
logFile << "Hooked for: " << hWndServer << endl;
logFile.close();
return TRUE;
}
return FALSE;
}
The problem is that if I make it global, with threadID = 0, then msgHook only and only captures the messages received by the window of the process that loaded the library and nothing else, even if it is supposed to be a global hook.
If I supply a threadID of some other window, then I don't receive messages at all.
What could perhaps be the reason for it?
Are you using 64-bit Windows? If so,
your hook process and DLL must match
the bitness of the process(es) you
wish to hook.
What is hInstance in your example?
The DLL or the EXE instance? It
should be the DLL that contains the
msgHook function.
What does your msgHook do? How do you
detect whether or not it is being
called? Note that it will be called
within the process(es) that you hook,
not within your own process. (So if
you've set a breakpoint on it, it
won't be triggered unless you attach
the debugger to the process you've
hooked, rather than the process that
installed the hook.)
I want to debug a windows C++ application I've written to see why it isn't responding to WM_QUERYENDSESSION how I expect it to. Clearly it's a little tricky to do this by just shutting the system down. Is there any utility or code which I can use to send a fake WM_QUERYENDSESSION to my application windows myself?
I've used the Win32::GuiTest Perl module to do this kind of thing in the past.
The Windows API SendMessage can be used to do this.
http://msdn.microsoft.com/en-us/library/ms644950(VS.85).aspx
IS ti possible it's not responding because some other running process has responded with a zero (making the system wait on it.)
Yes of course, it possible. I faced a similar issue some months ago where some (unknown, but probably mine) app was preventing shutdown, so I wrote some quick code that used EnumWindows to enumerate all the top level windows, sent each one a WM_QUERYENDSESSION message, noted what the return value from SendMessage was and stopped the enumeration if anyone returned FALSE. Took about ten minutes in C++/MFC. This was the guts of it:
void CQes_testDlg::OnBtnTest()
{
// enumerate all the top-level windows.
m_ctrl_ListMsgs.ResetContent();
EnumWindows (EnumProc, 0);
}
BOOL CALLBACK EnumProc (HWND hTarget, LPARAM lParam)
{
CString csTitle;
CString csMsg;
CWnd * pWnd = CWnd::FromHandle (hTarget);
BOOL bRetVal = TRUE;
DWORD dwPID;
if (pWnd)
{
pWnd->GetWindowText (csTitle);
if (csTitle.GetLength() == 0)
{
GetWindowThreadProcessId (hTarget, &dwPID);
csTitle.Format ("<PID=%d>", dwPID);
}
if (pWnd->SendMessage (WM_QUERYENDSESSION, 0, ENDSESSION_LOGOFF))
{
csMsg.Format ("window 0x%X (%s) returned TRUE", hTarget, csTitle);
}
else
{
csMsg.Format ("window 0x%X (%s) returned FALSE", hTarget, csTitle);
bRetVal = FALSE;
}
mg_pThis->m_ctrl_ListMsgs.AddString (csMsg);
}
else
{
csMsg.Format ("Unable to resolve HWND 0x%X to a CWnd", hTarget);
mg_pThis->m_ctrl_ListMsgs.AddString (csMsg);
}
return bRetVal;
}
mg_pThis was just a local copy of the dialog's this pointer, so the helper callback could access it. I told you it was quick and dirty :-)
Yes. If you can get the window handle (maybe using FindWindow()), you can send/post any message to it as long as the WPARAM & LPARAM aren't pointers.