The keyboad hook dll can't work well - winapi

The code of keyhook.cpp in dll:
// KeyHook.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
#include "stdio.h"
#include "Windows.h"
#pragma comment(linker, "/SECTION:.SHARED,RWS")
#pragma data_seg(".SHARED")
#define DEF_PROCESS_NAME "notepad.exe"
HINSTANCE g_hInstance = NULL;
HHOOK g_hHook = NULL;
HWND g_hWnd = NULL;
#pragma data_seg()
BOOL APIENTRY DllMain(HINSTANCE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
printf("main function in dll\n");
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_hInstance = hModule;
printf("max=%d\n", MAX_PATH);
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
//OutputDebugString("what the hell\n");
char szPath[MAX_PATH] = { 0, };
char *p = NULL;
//printf("the callback function");
int shift = nCode;
if (shift = 0)
{
if (!(lParam & 0x80000000))
{
GetModuleFileNameA(NULL, szPath, MAX_PATH);
p = strrchr(szPath, '\\');
//printf("szPath=%s\n", szPath);
OutputDebugString("what the hell\n");
if (!_stricmp(p + 1, DEF_PROCESS_NAME))
return 1;
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
#ifdef __cplusplus
extern "C" {
#endif // DEBUG
__declspec(dllexport) void HookStart()
{
printf("hookstart function\n");
g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0);
if (g_hHook == NULL)
printf("failed to install the keyboard hook");
else
{
printf("Succeed in installing the keyboard hook");
}
}
__declspec(dllexport) void HookStop()
{
if (g_hHook)
{
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
}
printf("hookstop function\n");
}
#ifdef __cplusplus
}
#endif // DEBUG
The calling application code:
// hkeybi.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include<stdio.h>
#include<conio.h>
#include<Windows.h>
#define DEF_DLL_NAME "KeyHook.dll"
#define DEF_HOOKSTART "HookStart"
#define DEF_HOOKSTOP "HookStop"
typedef void(*PFN_HOOKSTART)();
typedef void(*PFN_HOOKSTOP)();
int main()
{
int ch = -1;
HMODULE hDll = NULL;
PFN_HOOKSTART HookStart = NULL;
PFN_HOOKSTOP HookStop = NULL;
hDll = LoadLibraryA(DEF_DLL_NAME);
HookStart = (PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART);
HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP);
if ((HookStart != NULL) && (HookStop != NULL))
printf("hello start\n");
HookStart();
printf("press q to exit!\n");
while (_getch() != 'q');
HookStop();
FreeLibrary(hDll);
return 0;
}
When I run the app,after I input several words,it will go down. I spent long time in solving the problem.

There are several problems in your KeyboardProc function. The first one being that your shift variable is assigned instead of tested:
if (shift = 0)
The variable is assigned 0, the condition is therefore always false. Effectively, the only code executed after the test is the return CallNextHookEx(...). If the condition would be true, you may run into problems because the GetModuleFileNameA result is not tested. In case of an error, the following strrchr will likely fail and the p pointer will be NULL. This will result in a crash at the _stricmp. And why do you specifically use the ANSI version of GetModuleFileName, are you sure you're not using Unicode? Finally, returning the hook proc without calling CallNextHookEx is a bad idea. Here's what the documentation says:
If code is greater than or equal to zero, and the hook procedure did
not process the message, it is highly recommended that you call
CallNextHookEx and return the value it returns

Related

Is it possible to subclass a web browser using winapi c++?

The main goal is to block maximalize web browser window using subclassing and dll.
I have 2 apps: injector and the dll.
In injector app I load that dll, find window by title, get functions from dll and execute that functions ( their names are hook and unhook ) from dll. So this is standard injector. Of course I check is something NULL and I don't get any errors.
In dll I have 5 functions:
dllMain (here I only set global hInstance variable, which is in shared memory ):
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
{
if (hInstance == NULL)
{
hInstance = hinstDLL;
}
break;
}
...
}
return TRUE;
}
Hook ( HandleofTarget is the HWND, which I get from FindWindow ; I use this function in injector ):
extern "C" __declspec(dllexport) bool hook( HWND HandleofTarget)
{
hTarget=HandleofTarget;
hhook=SetWindowsHookEx(WH_CBT,cbtHookProc,hInstance, GetWindowThreadProcessId(hTarget,NULL));
if(hhook==NULL)
return 0;
else
return 1;
}
Unhook ( here I unhook hooks - I use this function in injector):
extern "C" __declspec(dllexport) void unhook(void)
{
if(hhook != NULL)
UnhookWindowsHookEx( hhook );
}
cbtHookProc ( hook callback, where I change window procedure ):
LRESULT CALLBACK cbtHookProc( int code, WPARAM wParam, LPARAM lParam )
{
if( code < 0 ) return CallNextHookEx( 0, code, wParam, lParam );
if (code == HCBT_ACTIVATE)
{
if((HWND)(wParam)==hTarget)
{
if(done == FALSE)
{
g_OldWndProc =(WNDPROC)(SetWindowLongPtr ( (HWND)(wParam), GWLP_WNDPROC,reinterpret_cast<LONG_PTR>( NewWndProc )));
done = TRUE;
}
}
}
return CallNextHookEx( 0, code, wParam, lParam );
}
NewWndProc ( new Window procedure, where I would like to block maximalize ):
LRESULT CALLBACK NewWndProc( HWND hwnd, UINT mesg, WPARAM wParam, LPARAM lParam )
{
switch( mesg )
{
case WM_SYSCOMMAND:
{
if(wParam == SC_MAXIMIZE)
{
return 1;
}
}
break;
}
return CallWindowProc( g_OldWndProc, hwnd, mesg, wParam, lParam );
}
When I test this dll with other apps - it works. When I use this dll with web browser like Internet Edge and Google Chrome - it doesn't works. That web browser, which I try injected works slower, but I can still maximalize that window. When I debuq dll, in web browser after SetWindowsHookEx I see that hook is not NULL, but my code doesn't go to cbtHookProc. What is going on with web browser?
UPDATE:
One more time - thank you Strive Sun - MSFT for helping me.
I change the lines in cbtHookProc, but it still doesn't work. My cbtHookProc is don't called by webBrowser - that is problem.
When I looked at your gif I see something what I don't have and I think that is the problem. My injector app looks like this:
hDll = LoadLibrary( L"dllka10" );
hHookedWindow=FindWindow(TEXT("Chrome_WidgetWin_1"),TEXT("Nowa karta - Google Chrome"));
if( hDll && hHookedWindow)
{
qDebug()<<"hDll and hHookedWindow are not NULL!";
funHook =( MYPROC2 ) GetProcAddress( hDll, (LPCSTR) "hook" );
funUnhook = ( MYPROC ) GetProcAddress( hDll, (LPCSTR) "unhook" );
if( funHook )
{
qDebug()<<funHook(hHookedWindow);
}
}
I don't use CreateThread(). Is it important here?
UPDATED 2
LRESULT CALLBACK cbtHookProc( int code, WPARAM wParam, LPARAM lParam )
{
if( code < 0 ) return CallNextHookEx( 0, code, wParam, lParam );
std::fstream file;
file.open("C:\\Users\\tom\\Desktop\\logs.txt",std::ios::out|std::ios::app);
file<<"In cbtHook function!"<<std::endl;
file.close();
if (code == HCBT_MINMAX)
{
if (LOWORD(lParam) == SW_SHOWMAXIMIZED)
{
return 1;
}
}
return CallNextHookEx( 0, code, wParam, lParam );
}
When I run chrome application - my logs.txt is empty. When I run other app - I have logs.
UPDATED 3
In my dll I have:
#ifdef __GNUC__
HWND hTarget __attribute__((section (".shared"), shared)) =NULL;
HWND hApp __attribute__((section (".shared"), shared)) = NULL;
bool done __attribute__((section (".shared"), shared)) =FALSE;
HINSTANCE hInstance __attribute__((section (".shared"), shared)) =NULL;
HHOOK hhook __attribute__((section (".shared"), shared)) = NULL;
WNDPROC g_OldWndProc __attribute__((section (".shared"), shared)) = NULL;
#endif
#ifdef _MSC_VER
#pragma data_seg(".shared")
HWND hTarget=NULL;
HWND hApp = NULL;
bool done=FALSE;
HINSTANCE hInstance=NULL;
HHOOK hhook = NULL;
WNDPROC g_OldWndProc = NULL;
#pragma data_seg()
#pragma comment(linker, "/section:.shared,RWS")
#endif
in my injector I don't have any pragma - I have only ( QT ):
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <iostream>
#include "string.h"
#include "windows.h"
I can't reproduce your problem, but you can try another easier method.
HCBT_MINMAX : Specifies, in the low-order word, a show-window value
(SW_) specifying the operation. For a list of show-window values, see
the ShowWindow. The high-order word is undefined.
if (code == HCBT_MINMAX)
{
if (LOWORD(lParam) == SW_SHOWMAXIMIZED)
{
return 1;
}
}
No need to use HCBT_ACTIVATE to obtain window handles and compare their handles.
Updated:
Code works fine.
My code sample:
DLL:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include "stdio.h"
#include <windows.h>
HHOOK hCBT = NULL;
HWND hTarget;
HMODULE thisModule;
LRESULT CALLBACK _cbtProc(int code, WPARAM wParam, LPARAM lParam)
{
if (code < 0) return CallNextHookEx(0, code, wParam, lParam);
if (code == HCBT_MINMAX)
{
if (LOWORD(lParam) == SW_SHOWMAXIMIZED)
{
return 1;
}
}
return CallNextHookEx(0, code, wParam, lParam);
}
#ifdef __cplusplus //If used by C++ code.
extern "C" { //we need to export the C interface
#endif
__declspec(dllexport) BOOL WINAPI InstallHooks(HWND HandleofTarget)
{
hTarget = HandleofTarget;
DWORD tid = GetWindowThreadProcessId(hTarget, NULL);
hCBT = SetWindowsHookEx(WH_CBT, _cbtProc, thisModule, tid);
return (hCBT) ? TRUE : FALSE;
}
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus //If used by C++ code.
extern "C" { //we need to export the C interface
#endif
__declspec(dllexport) void WINAPI RemoveHooks()
{
UnhookWindowsHookEx(hCBT);
MessageBox(NULL, L"unhook", L" ", MB_OK);
hCBT = NULL;
}
#ifdef __cplusplus
}
#endif
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
thisModule = hModule;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
main.cpp
#include <Windows.h>
#include <stdio.h>
#include <psapi.h>
#include <shlwapi.h>
#include <tchar.h>
#pragma comment(lib,"Kernel32.lib")
#pragma comment(lib,"shlwapi.lib")
#pragma comment(linker, "/SECTION:.shared,RWS")
using namespace std;
HINSTANCE hinstDLL;
typedef void (*RemoveHooks)();
DWORD __stdcall CreateThreadFunc(LPVOID)
{
while (1)
{
if (GetAsyncKeyState(0x50) & 0x0001)
{
RemoveHooks removeHooks = (RemoveHooks)GetProcAddress(hinstDLL, "RemoveHooks");
removeHooks();
}
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == WM_DESTROY) {
PostQuitMessage(0);
}
return DefWindowProc(hwnd, message, wParam, lParam);
};
int main()
{
HWND hwnd = FindWindow(L"Chrome_WidgetWin_1", L"Google Translate - Google Chrome");
CreateThread(NULL, 0, CreateThreadFunc, 0, 0, 0);
hinstDLL = LoadLibrary(TEXT("D:\\Start from 11.2\\WM_CBT_DLL\\x64\\Debug\\WM_CBT_DLL.dll"));
BOOL(*InstallHooks)(HWND);
InstallHooks = (BOOL(*)(HWND)) GetProcAddress(hinstDLL, "InstallHooks");
BOOL l = InstallHooks(hwnd);
int err = GetLastError();
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

Getting error 127 when calling GetProcAddress

I am writing a global hook for WH_GETMESSAGE. But I am getting the error code 127 i.e.,ERROR_PROC_NOT_FOUND, when calling the GetProcAddress function from the dll. Its unable to find the GetMsgProc. Any idea why?
Also, I am new to this kind of programming, so apologies for any mistake that's not expected.
DLL File:
#include "windows.h"
#include <stdio.h>
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
return TRUE;
}
__declspec(dllexport) LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MessageBox(NULL, TEXT("I am in"),TEXT("In a DLL"), MB_OK);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
Program Loading the DLL file:
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
typedef LRESULT(CALLBACK *LPGetMsgProc)(int nCode, WPARAM wParam, LPARAM lParam);
int main()
{
HMODULE hDll = LoadLibrary(_T("../../dllTouchInputHook/x64/Debug/dllTouchInputHook.dll"));
LPGetMsgProc proc = (LPGetMsgProc)GetProcAddress(hDll, "GetMsgProc");
if (proc == NULL) {
printf("The error code is %d", GetLastError());
}
HHOOK hMsgHook = SetWindowsHookEx(WH_GETMESSAGE, proc, hDll, 0);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hMsgHook);
return 0;
}
The function is not being found because it is not being exported as "GetMsgProc" like you are expecting. It is actually being exported more like "_GetMsgProc#12" (32bit) or "_GetMsgProc#20" (64bit) instead. If you want it exported as "GetMsgProc" then you need to use a .DEF file when compiling the DLL.
You shouldn't be implementing the hook in this manner to begin with. You should move the call to SetWindowsHookEx() inside the DLL itself, and then export a function to call it, eg:
#include "windows.h"
#include <stdio.h>
HINSTANCE hThisDLL;
HHOOK hMsgHook;
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
hThisDLL = hinstDLL;
return TRUE;
}
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MessageBox(NULL, TEXT("I am in"), TEXT("In a DLL"), MB_OK);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
__declspec(dllexport) BOOL WINAPI InstallHook()
{
if (!hMsgHook)
hMsgHook = SetWindowsHookEx(WH_GETMESSAGE, &GetMsgProc, hThisDll, 0);
return (hMsgHook != NULL);
}
__declspec(dllexport) VOID WINAPI UninstallHook()
{
if (hMsgHook)
{
UnhookWindowsHookEx(hMsgHook);
hMsgHook = NULL;
}
}
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
typedef BOOL (WINAPI *LPInstallHook)();
typedef VOID (WINAPI *LPUninstallHook)();
int main()
{
HMODULE hDll = LoadLibrary(_T("../../dllTouchInputHook/x64/Debug/dllTouchInputHook.dll"));
if (!hDll)
{
printf("The error code is %d", GetLastError());
return -1;
}
LPInstallHook installProc = (LPInstallHook) GetProcAddress(hDll, "InstallHook"); // or "_InstallHook"
LPUninstallHook uninstallProc = (installProc) ? (LPUninstallHook) GetProcAddress(hDll, "UninstallHook") : NULL; // or "_UninstallHook"
if (!(installProc && uninstallProc))
{
printf("The error code is %d", GetLastError());
FreeLibrary(hDll);
return -1;
}
if (!installProc())
{
printf("The error code is %d", GetLastError());
FreeLibrary(hDll);
return -1;
}
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
uninstallProc();
FreeLibrary(hDll);
return 0;
}

Possible to capture unhandled exception in win32 user application ? (setunhandledexceptionfilter())

I spent much time to capture unhandled exceptions in my process (win32) using API so called setunhandledexceptionfilter().
But I haven't captured exception when WER(Windows Error Report - which is well know for DR.watson) is showed.
Is impossible to catch all of exceptions without third-party in my APP?
I think that there is method for handling, but I don't get it.
I am not accustomed to Windows DEV environment. that's why I lost my mental in googling.
Below is my test-case in vc110(Visual Studio 2012).
chat test[65];
int main() {
// after attaching unhandled exception call-back using setunhandledexceptionfilter()
// die point (ACCESS_VIOLATION c0000005)
for (int k=0; k<1000000; k++)
test[k]=65;
My callback isn't called after WER(windows Error Report) occurs. It doesn't work as my intend.
*But strcpy(NULL, "TEST") which is okay (SUCCESS)*
Below is my source code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/stat.h>
#include <assert.h>
#include <process.h>
#include <direct.h>
#include <conio.h>
#include <time.h>
#include <Windows.h>
#include <tchar.h>
#include <dbghelp.h>
#include <stdio.h>
#include <crtdbg.h>
#include <WinBase.h>
#pragma comment ( lib, "dbghelp.lib" )
void CreateMiniDump( EXCEPTION_POINTERS* pep );
BOOL CALLBACK MyMiniDumpCallback(
PVOID pParam,
const PMINIDUMP_CALLBACK_INPUT pInput,
PMINIDUMP_CALLBACK_OUTPUT pOutput
);
///////////////////////////////////////////////////////////////////////////////
// Minidump creation function
//
#if 0
LONG WINAPI lpTopLevelExceptionFilter(EXCEPTION_POINTERS* ExceptionInfo);
#endif
void CreateMiniDump( EXCEPTION_POINTERS* pep )
{
time_t t;
struct tm *tinfo;
wchar_t dump_name[128];
HANDLE hFile;
time(&t);
tinfo = localtime(&t);
wcsftime(dump_name, 128, L"MiniDump[%Y%m%d][%H_%M_%S].dmp", tinfo);
// file format MiniDump[YYYYMMDD][HH_MM_SEC]
hFile = CreateFile(dump_name, GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) )
{
// Create the minidump
MINIDUMP_EXCEPTION_INFORMATION mdei;
MINIDUMP_CALLBACK_INFORMATION mci;
MINIDUMP_TYPE mdt;
BOOL rv;
mdei.ThreadId = GetCurrentThreadId();
mdei.ExceptionPointers = pep;
mdei.ClientPointers = FALSE;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback;
mci.CallbackParam = 0;
mdt = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory| MiniDumpWithThreadInfo);
rv = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
hFile, mdt, (pep != 0) ? &mdei : 0, 0, &mci );
if( !rv )
_tprintf( _T("MiniDumpWriteDump failed. Error: %u \n"), GetLastError() );
else
_tprintf( _T("Minidump created.\n") );
// Close the file
CloseHandle( hFile );
}
else
{
_tprintf( _T("CreateFile failed. Error: %u \n"), GetLastError() );
}
}
///////////////////////////////////////////////////////////////////////////////
// Custom minidump callback
//
BOOL CALLBACK MyMiniDumpCallback(
PVOID pParam,
const PMINIDUMP_CALLBACK_INPUT pInput,
PMINIDUMP_CALLBACK_OUTPUT pOutput
)
{
BOOL bRet = FALSE;
// Check parameters
if( pInput == 0 )
return FALSE;
if( pOutput == 0 )
return FALSE;
// Process the callbacks
switch( pInput->CallbackType )
{
case IncludeModuleCallback:
{
// Include the module into the dump
bRet = TRUE;
}
break;
case IncludeThreadCallback:
{
// Include the thread into the dump
bRet = TRUE;
}
break;
case ModuleCallback:
{
// Does the module have ModuleReferencedByMemory flag set ?
if( !(pOutput->ModuleWriteFlags & ModuleReferencedByMemory) )
{
// No, it does not - exclude it
wprintf( L"Excluding module: %s \n", pInput->Module.FullPath );
pOutput->ModuleWriteFlags &= (~ModuleWriteModule);
}
bRet = TRUE;
}
break;
case ThreadCallback:
{
// Include all thread information into the minidump
bRet = TRUE;
}
break;
case ThreadExCallback:
{
// Include this information
bRet = TRUE;
}
break;
case MemoryCallback:
{
// We do not include any information here -> return FALSE
bRet = FALSE;
}
break;
case CancelCallback:
break;
}
return bRet;
}
LONG WINAPI exception_filter_func(EXCEPTION_POINTERS* pep)
{
if (pep == NULL) {
return EXCEPTION_EXECUTE_HANDLER;
}
if (pep->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CreateMiniDump, pep, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
} else {
CreateMiniDump(pep);
}
return EXCEPTION_EXECUTE_HANDLER;
}
char test[65];
int main(int argc, char **argv)
{
int k;
SetUnhandledExceptionFilter(exception_filter_func);
// exception occured (ACCESS_VIOLATION)
for (k=0; k<1000000; k++)
test[k]=65;
}

How to inject a DLL into Adobe Reader X

I need to inject a DLL into Adobe Reader X that reads the events sent to the scrollbar (even if it is hidden). I need to do this to be able to find out what page of the document i am on.
I have tried hooking a dll using the win32 hooking API, i give a CBT hook to all processes on the desktop and listen for the creation of the Adobe Reader X window, then hooking this window with my scrollbar hook.
The problem is that i never get the scrollbar hook placed on Adobe Reader X, i dont get the create window or window activate messages for these windows when they are created. How do i get these messages and how do i hook into Adobe Reader X?
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "pdfviewlib.h"
#include <sstream>
#pragma data_seg(".PDFVIEWLIB")
PDFVIEWOBJ pdfviewobj[MAX_PDFOBJS] = {NULL};
HHOOK globalhook = NULL;
BOOL debug = TRUE;
INT sSlide = 0;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.PDFVIEWLIB,RWS")
#define DEBUG(...) if(debug) printf(__VA_ARGS__)
HINSTANCE hInstance = NULL;
static int tAttach = 0;
static int tDetach = 0;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
hInstance = (HINSTANCE)hModule;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DEBUG("PROCESS_ATTACH\n");
break;
case DLL_THREAD_ATTACH:
DEBUG("THREAD_ATTACH %i\n",tAttach++);
break;
case DLL_THREAD_DETACH:
DEBUG("THREAD_DETACH %i\n", tDetach++);
break;
case DLL_PROCESS_DETACH:
// Clean up... hopefully there is only the one process attached?
DEBUG("PROCESS_DETACH\n");
for(int i = 0; i<MAX_PDFOBJS; i++)
ClosePDF(i);
break;
}
return TRUE;
}
DllExport void SetDebug(BOOL onoff)
{
printf("SetDebug\n");
debug = onoff;
DEBUG("enabled\n");
}
//Check if Acrobat Reader is installed
DllExport BOOL CheckInstalled()
{
DEBUG("CheckInstalled\n");
char cmdline[MAX_PATH * 2];
return GetPDFViewerPath(cmdline, sizeof(cmdline));
}
// Open the PDF
DllExport int OpenPDF(char *filename, HWND hParentWnd, int startSlide)
{
STARTUPINFO * si = (STARTUPINFO *) malloc(sizeof(STARTUPINFO));
PROCESS_INFORMATION * pi = (PROCESS_INFORMATION*) malloc(sizeof(PROCESS_INFORMATION));
char cmdline[MAX_PATH * 2];
int id;
sSlide = startSlide;
DEBUG("OpenPDF start: %u", hParentWnd);
//First check if Acrobat Reader is installed before continuing
if(GetPDFViewerPath(cmdline, sizeof(cmdline))==FALSE)
{
DEBUG("OpenPDF: GetPDFTViewerPath failed\n");
return -1;
}
id = -1;
for(int i = 0; i<MAX_PDFOBJS; i++)
{
if(pdfviewobj[i].state==PDF_CLOSED)
{
id=i;
break;
}
}
if(id<0)
{
DEBUG("OpenPDF: Too many PDFs\n");
return -1;
}
if (pdfviewobj[id].state == PDF_STARTED)
{
DEBUG("RERUN WHEN PDF_STARTED\n");
return -1;
}
memset(&pdfviewobj[id], 0, sizeof(PDFVIEWOBJ));
strcpy_s(pdfviewobj[id].filename, MAX_PATH, filename);
pdfviewobj[id].state = PDF_CLOSED;
pdfviewobj[id].currentSlide = 0;
pdfviewobj[id].hParentWnd = hParentWnd;
pdfviewobj[id].hWnd = NULL;
pdfviewobj[id].hWnd2 = NULL;
strcat_s(cmdline, MAX_PATH * 2, "\\AcroRd32.exe /n /s /o");
strcat_s(cmdline, MAX_PATH * 2, " \"");
strcat_s(cmdline, MAX_PATH * 2, filename);
strcat_s(cmdline, MAX_PATH * 2, "\"");
si = (STARTUPINFO *)memset(si, 0, sizeof(STARTUPINFO));
pi = (PROCESS_INFORMATION *)memset(pi, 0, sizeof(PROCESS_INFORMATION));
if(globalhook!=NULL){
UnhookWindowsHookEx(globalhook);
DEBUG("Global unhooked\n");
globalhook = NULL;
}
//Set the global hook listening for Window Create/Window Activate messages
globalhook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,NULL);
if(globalhook==NULL)
{
DEBUG("OpenPDF: Global SetWindowsHookEx failed\n");
DEBUG("ERROR: %X\n", GetLastError());
globalhook = NULL;
ClosePDF(id);
return -1;
}
else DEBUG("GLOBAL HOOKED %X\n", globalhook);
pdfviewobj[id].state = PDF_STARTED;
Sleep(10);
DEBUG(cmdline);
//Run Acrobat Reader, PDF STATE SET TO STARTED
if(!CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, 0, NULL, si, pi))
{
DEBUG("OpenPDF: CreateProcess failed\n");
ClosePDF(id);
return -1;
}
pdfviewobj[id].dwProcessId = pi->dwProcessId;
pdfviewobj[id].dwThreadId = pi->dwThreadId;
pdfviewobj[id].hThread = pi->hThread;
pdfviewobj[id].hProcess = pi->hProcess;
//WAIT FOR GLOBAL HOOK TO DETECT Acrobat Windows and set PDF STATE TO PDF_OPENED
//For some reason the loops exits and PDFSTATE is PDF_CLOSED...
while(pdfviewobj[id].state==PDF_STARTED)
Sleep(50);
DEBUG("PDFSTATE == CLOSED = %i \n", pdfviewobj[id].state==PDF_CLOSED);
DEBUG("PDFSTATE == STARTED = %i \n", pdfviewobj[id].state==PDF_STARTED);
DEBUG("PDFSTATE == OPENED = %i \n", pdfviewobj[id].state==PDF_OPENED);
DEBUG("PDFSTATE == LOADED = %i \n", pdfviewobj[id].state==PDF_LOADED);
if (sSlide > 0){
GotoSlide(id, sSlide+1);
}
pdfviewobj[id].state = PDF_LOADED;
DEBUG("OpenPDF Done: id=%i\n", id);
return id;
}
// Get the path of Acrobat Reader X from the registry
BOOL GetPDFViewerPath(char *pdfviewerpath, int strsize)
{
HKEY hkey;
DWORD dwtype, dwsize;
LRESULT lresult;
DEBUG("GetPDFViewerPath: start\n");
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Adobe\\Acrobat Reader\\9.0\\InstallPath", 0, KEY_READ, &hkey)!=ERROR_SUCCESS)
return FALSE;
dwtype = REG_SZ;
dwsize = (DWORD)strsize;
lresult = RegQueryValueEx(hkey, NULL, NULL, &dwtype, (LPBYTE)pdfviewerpath, &dwsize );
RegCloseKey(hkey);
if(lresult!=ERROR_SUCCESS)
return FALSE;
DEBUG("GetPDFViewerPath: exit ok \n");
return TRUE;
}
// Unhook the Windows hook
void Unhook(int id)
{
DEBUG("Unhook: start %i\n", id);
if(pdfviewobj[id].hook!=NULL)
UnhookWindowsHookEx(pdfviewobj[id].hook);
pdfviewobj[id].hook = NULL;
DEBUG("Unhook: exit ok\n");
}
// Close the Acrobat Reader, release resources
DllExport void ClosePDF(int id)
{
DEBUG("ClosePDF: start %i\n", id);
if (globalhook != NULL) {
DEBUG("GLOBAL UNHOOKED %X\n", globalhook);
UnhookWindowsHookEx(globalhook);
globalhook = NULL;
}
else DEBUG("GLOBAL NOT UNHOOKED\n");
pdfviewobj[id].state = PDF_CLOSED;
Unhook(id);
if(pdfviewobj[id].hWnd==0)
TerminateThread(pdfviewobj[id].hThread, 0);
else
PostMessage(pdfviewobj[id].hWnd, WM_CLOSE, 0, 0);
CloseHandle(pdfviewobj[id].hThread);
CloseHandle(pdfviewobj[id].hProcess);
memset(&pdfviewobj[id], 0, sizeof(PDFVIEWOBJ));
DEBUG("ClosePDF: exit ok\n");
return;
}
// Return the number of the slide currently viewing
DllExport int GetCurrentSlide(int id)
{
DEBUG("GetCurrentSlide:%d\n", id);
if(pdfviewobj[id].state==0)
return -1;
else
return pdfviewobj[id].currentSlide;
}
// Take a step forwards through the show
DllExport void NextStep(int id)
{
DEBUG("NextStep:%d\n", id);
SetForegroundWindow(pdfviewobj[id].hWnd);
SetFocus(pdfviewobj[id].hWnd);
PostMessage(pdfviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, -WHEEL_DELTA), 0);
}
// Take a step backwards through the show
DllExport void PrevStep(int id)
{
DEBUG("PrevStep:%d\n", id);
SetForegroundWindow(pdfviewobj[id].hWnd);
SetFocus(pdfviewobj[id].hWnd);
PostMessage(pdfviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA), 0);
}
// Go directly to a slide
DllExport void GotoSlide(int id, int slideno)
{
//TODO: USE SETSCROLLINFO
}
// This hook is started with the AcroRd32.EXE process and waits for the WM_CREATEWND message.
// Release the hook as soon as we're complete to free up resources
LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam)
{
HHOOK hook = globalhook;
DEBUG("HOOK: %X\n", hook);
if (nCode < 0) {
return CallNextHookEx(hook, nCode, wParam, lParam);
}
else if(nCode==HCBT_CREATEWND)
{
DEBUG("CREATE WINDOW \n");
char csClassName[16];
char csCaptionName[16];
HWND hCurrWnd = (HWND)wParam;
DWORD retProcId = NULL;
GetClassName(hCurrWnd, csClassName, sizeof(csClassName));
GetWindowText(hCurrWnd, csCaptionName, sizeof(csCaptionName));
if((strcmp(csClassName, "AcrobatSDIWindow")==0)
||(strcmp(csClassName, "AVL_AVView")==0))
{
DEBUG("%s found \n", csClassName);
int id=-1;
DWORD windowthread = GetWindowThreadProcessId(hCurrWnd,NULL);
for(int i=0; i<MAX_PDFOBJS; i++)
{
if(pdfviewobj[i].dwThreadId==windowthread)
{
id=i;
break;
}
}
if(id>=0)
{
DEBUG("Matched threadid!\n");
if(strcmp(csClassName, "AVL_AVView")==0){
if (strcmp(csCaptionName, "AVPageView")==0){
pdfviewobj[id].hWnd2=hCurrWnd;
}
}
else
{
pdfviewobj[id].hWnd=hCurrWnd;
CBT_CREATEWND* cw = (CBT_CREATEWND*)lParam;
if(pdfviewobj[id].hParentWnd!=NULL)
cw->lpcs->hwndParent = pdfviewobj[id].hParentWnd;
}
if((pdfviewobj[id].hWnd!=NULL)&&(pdfviewobj[id].hWnd2!=NULL))
{
pdfviewobj[id].hook = SetWindowsHookEx(WH_CALLWNDPROC,CwpProc,hInstance,pdfviewobj[id].dwThreadId);
if (pdfviewobj[id].hook != NULL) {
DEBUG("Global UNHOOKED %X\n", globalhook);
UnhookWindowsHookEx(globalhook);
globalhook=NULL;
pdfviewobj[id].state = PDF_OPENED;
}
Sleep(10);
}
}
}
}
return CallNextHookEx(hook,nCode,wParam,lParam);
}
LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam){
CWPSTRUCT *cwp;
cwp = (CWPSTRUCT *)lParam;
HHOOK hook = NULL;
DWORD windowthread = GetWindowThreadProcessId(cwp->hwnd,NULL);
int id=-1;
for(int i=0; i<MAX_PDFOBJS; i++)
{
if(pdfviewobj[i].dwThreadId==windowthread)
{
id=i;
hook = pdfviewobj[id].hook;
break;
}
}
if((id>=0)&&(nCode==HC_ACTION))
{
DEBUG("CBT HC_ACTION\n");
if(cwp->message==SBM_SETSCROLLINFO)
{
DEBUG("CBT SBM_SETSCROLLINFO\n");
SCROLLINFO *scrInf;
scrInf = (SCROLLINFO *)cwp->lParam;
pdfviewobj[id].currentSlide = scrInf->nPos;
}
if((pdfviewobj[id].state != PDF_CLOSED)&&(cwp->message==WM_CLOSE||cwp->message==WM_QUIT)){
pdfviewobj[id].state = PDF_CLOSING;
}
}
return CallNextHookEx(hook,nCode,wParam,lParam);
}
heres the header if you need it
#define DllExport extern "C" __declspec( dllexport )
enum PDFVIEWSTATE { PDF_CLOSED, PDF_STARTED, PDF_OPENED, PDF_LOADED, PDF_CLOSING};
DllExport int OpenPDF(char *filename, HWND hParentWnd, int startSlide);
DllExport BOOL CheckInstalled();
DllExport void ClosePDF(int id);
DllExport int GetCurrentSlide(int id);
DllExport void NextStep(int id);
DllExport void PrevStep(int id);
DllExport void GotoSlide(int id, int slideno);
DllExport void SetDebug(BOOL onoff);
LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam);
BOOL GetPDFViewerPath(char *pdfviewerpath, int strsize);
void Unhook(int id);
//MAXUMUM NUMBER OF PDF-PROCESSES CURRENTLY SET TO ONE
#define MAX_PDFOBJS 1
struct PDFVIEWOBJ
{
HHOOK hook;
HWND hWnd;
HWND hWnd2;
HWND hParentWnd;
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
int currentSlide;
char filename[MAX_PATH];
PDFVIEWSTATE state;
};
Adobe Reader typically runs in protected mode. (See Edit/Preferences/Security (Enhanced). Un-check the "Enable Protected Mode at startup" checkbox.
Relaunch reader and see if you get your messages. You should. The issue is that the User Interface Privilege Isolation (UIPI) disallows many windows messages from crossing process boundaries between processes running at a different integrity level (low/medium/high). You are supposed to be able to change the windows message filter via ChangeWindowMessageFilterEx().
I am currently experiencing issues with Adobe Reader Xi where the ChangeWindowsMessageFilter and ChangeWindowMessageFilterEx do not seem to change the behavior of Adobe reader sending messages to the global hook receiver in the hooking process. I have copied noteapad.exe to notepad2.exe and lowered its integrity level to low via: icacls notepad2.exe /setintegritylevel low
(run from an elevated cmd prompt (i.e. run as admin)). When I do this my hooking works fine (using ChangeWindowMessageFilterEx()) but still does not get hooked messages from Adobe.
Also, Reader is 32-bit so make sure you are hooking it from a 32-bit hooking process otherwise you won't see messages either).

How can I be notified when a new window is created on Win32?

Is there a way using Win32, to register for notifications when a new window is created. I'm trying to keep a list of current open windows, but am now just polling the list of current windows using EnumWindows().
Anyone done something similar?
Thanks
I'm not sure if I'm doing this right, but I'm not able to get the SetWindowsHookEx method to fire.
anything come to mind?
here is my snip
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(HookType hook, HookProc callback, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll")]
private static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
const int HSHELL_WINDOWCREATED = 1;
private static HookProc winDelegate = ShellHookProcDelegate;
internal static void RegisterWindowCreatedEvent()
{
SetWindowsHookEx(HookType.WH_SHELL, winDelegate, IntPtr.Zero, 0);
}
private static int ShellHookProcDelegate(int code, IntPtr wParam, IntPtr lParam)
{
if (code != HSHELL_WINDOWCREATED)
{
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
//App specific code here
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
Use SetWindowsHookEx to set up a WH_SHELL hook and look for the HSHELL_WINDOWCREATED event.
Here is some code based on UI automation events. It gives window opened, closed, and focused events.
C#
[STAThread]
public static void Main(string[] args)
{
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Children, (sender, e) =>
{
var element = (AutomationElement)sender;
var name = element.Current.Name;
Console.WriteLine("open: " + name + " hwnd:" + element.Current.NativeWindowHandle);
Automation.AddAutomationEventHandler(WindowPattern.WindowClosedEvent, element, TreeScope.Element, (s, e2) =>
{
Console.WriteLine("close: " + name + " hwnd:" + element.Current.NativeWindowHandle);
});
});
Automation.AddAutomationFocusChangedEventHandler((sender, e) =>
{
var element = (AutomationElement)sender;
var name = element.Current.Name;
Console.WriteLine("focused: " + name + " hwnd:" + element.Current.NativeWindowHandle);
});
Console.ReadLine();
Automation.RemoveAllEventHandlers();
}
C++ equivalent:
#include <windows.h>
#include <stdio.h>
#include <uiautomation.h>
// some useful macros
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WFILE__ WIDEN(__FILE__)
#define MYTRACE wprintf
#define CHECKHR(expr) {hr=(expr);if(FAILED(hr)){ MYTRACE(L"HR FAILED line:%u file:%s\n", __LINE__, __WFILE__); goto cleanup; } }
#define CHECKWIN32(expr) {if(!(expr)){hr = HRESULT_FROM_WIN32(GetLastError()); MYTRACE(L"WIN32 FAILED line:%u file:%s\n", __LINE__, __WFILE__); goto cleanup; } }
#define CHECKARG(expr) {if(!(expr)){ MYTRACE(L"ARG FAILED line:%u file:%s\n", __LINE__, __WFILE__); hr = E_INVALIDARG; goto cleanup; } }
#define CHECKMEM(expr) {if(!(expr)){ MYTRACE(L"MEM FAILED line:%u file:%s\n", __LINE__, __WFILE__); hr = E_OUTOFMEMORY; goto cleanup; } }
#define CORELEASE(expr) {if(expr){ expr->Release(); expr = NULL; } }
#define HR HRESULT hr=S_OK;
class EventHandler :
public IUIAutomationEventHandler,
public IUIAutomationFocusChangedEventHandler
{
private:
LONG _ref;
IUIAutomation* _automation;
HWND _hwnd;
IUIAutomationElement* _sender;
public:
EventHandler(IUIAutomation* automation, IUIAutomationElement* sender, HWND hwnd) :
_ref(1),
_automation(automation),
_sender(sender),
_hwnd(hwnd)
{
if (sender)
{
sender->AddRef();
}
}
~EventHandler()
{
CORELEASE(_sender);
}
// IUnknown
ULONG STDMETHODCALLTYPE AddRef() { ULONG ret = InterlockedIncrement(&_ref); return ret; }
ULONG STDMETHODCALLTYPE Release() { ULONG ret = InterlockedDecrement(&_ref); if (!ret) { delete this; return 0; } return ret; }
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppInterface)
{
if (riid == __uuidof(IUnknown))
{
*ppInterface = (IUIAutomationEventHandler*)this;
}
else if (riid == __uuidof(IUIAutomationEventHandler))
{
*ppInterface = (IUIAutomationEventHandler*)this;
}
else if (riid == __uuidof(IUIAutomationFocusChangedEventHandler))
{
*ppInterface = (IUIAutomationFocusChangedEventHandler*)this;
}
else
{
*ppInterface = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
// IUIAutomationFocusChangedEventHandler
HRESULT STDMETHODCALLTYPE HandleFocusChangedEvent(IUIAutomationElement* sender)
{
HWND hwnd = NULL;
sender->get_CurrentNativeWindowHandle((UIA_HWND*)&hwnd);
wprintf(L"Window focused hwnd:%p'\n", hwnd);
return S_OK;
}
// IUIAutomationEventHandler
HRESULT STDMETHODCALLTYPE HandleAutomationEvent(IUIAutomationElement* sender, EVENTID eventID)
{
HR;
HWND hwnd = NULL;
EventHandler* windowHandler;
switch (eventID)
{
case UIA_Window_WindowOpenedEventId:
sender->get_CurrentNativeWindowHandle((UIA_HWND*)&hwnd);
wprintf(L"Window opened hwnd:%p\n", hwnd);
// register for close on this window
// we build a new handler, this is the only way to remember the hwnd (the close event doesn't have anything)
windowHandler = new EventHandler(_automation, sender, hwnd); // implicit addref
CHECKMEM(windowHandler);
CHECKHR(_automation->AddAutomationEventHandler(UIA_Window_WindowClosedEventId, sender, TreeScope_Element, NULL, windowHandler));
break;
case UIA_Window_WindowClosedEventId:
wprintf(L"Window closed hwnd:%p\n", _hwnd);
CHECKHR(_automation->RemoveAutomationEventHandler(UIA_Window_WindowClosedEventId, _sender, this));
Release(); // we release our own reference, 'this' we be deleted sometime when all COM references are gone. don't do 'delete this'!
break;
}
cleanup:
return hr;
}
};
int main()
{
HR;
IUIAutomationElement* root = NULL;
EventHandler* handler = NULL;
IUIAutomation* automation = NULL;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
CHECKHR(CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation), (void**)&automation));
CHECKHR(automation->GetRootElement(&root));
handler = new EventHandler(automation, NULL, NULL);
CHECKMEM(handler);
CHECKHR(automation->AddAutomationEventHandler(UIA_Window_WindowOpenedEventId, root, TreeScope_Subtree, NULL, handler));
CHECKHR(automation->AddFocusChangedEventHandler(NULL, handler));
wprintf(L"Press any key to stop listening for events.\n");
getchar();
cleanup:
if (automation != NULL)
{
automation->RemoveAllEventHandlers();
CORELEASE(automation);
}
CORELEASE(handler);
CORELEASE(root);
CoUninitialize();
return hr;
}
Sure - you can write a CBT hook and watch for HCBT_CREATEWND. See also SetWindowsHookEx().
Note that this will allow you to be notified of all window creation, before the windows being created are even fully initialized. If all you need are unowned, top-level windows, RichieHindle's suggestion may work better...
Detours will permit you to attach hooks to arbitrary Win32 functions. However, polling is probably a more reliable way to approach the problem: you don't have to worry about whether you've missed a particular window-creation method (how many are there in Win32? I bet more than one!), and, of course, you won't be rewriting the machine code for windows functions at runtime.
But, you know, your call.
You could try WinEventHook library for autohotkey.
Try modifying the notepad popup blocker example with the following:
HookProc( hWinEventHook, Event, hWnd, idObject, idChild, dwEventThread, dwmsEventTime )
{
if Event ; EVENT_SYSTEM_FOREGROUND = 0x3
{
WinGetTitle, title, ahk_id %hWnd%
If (title = "your_window_name"
msgbox, your window has been created
}
}

Resources