diff --git a/.gitignore b/.gitignore index 6c8318d..4f40838 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ native/uiabridge/x64 native/uiabridge/release native/uiabridge/Debug !native/uiabridge/bin +!native/MsgHook/bin +!native/MsgHookTest/bin diff --git a/native/MsgHook.sln b/native/MsgHook.sln new file mode 100644 index 0000000..58c03a6 --- /dev/null +++ b/native/MsgHook.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MsgHook", "MsgHook\MsgHook.vcxproj", "{8E038A94-7D02-49E9-B9F6-5224D9D11225}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MsgHookTest", "MsgHookTest\MsgHookTest.vcxproj", "{E8016236-E771-4BEC-8407-6BF37C68D174}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8E038A94-7D02-49E9-B9F6-5224D9D11225}.Debug|Win32.ActiveCfg = Debug|Win32 + {8E038A94-7D02-49E9-B9F6-5224D9D11225}.Debug|Win32.Build.0 = Debug|Win32 + {8E038A94-7D02-49E9-B9F6-5224D9D11225}.Debug|x64.ActiveCfg = Debug|x64 + {8E038A94-7D02-49E9-B9F6-5224D9D11225}.Debug|x64.Build.0 = Debug|x64 + {8E038A94-7D02-49E9-B9F6-5224D9D11225}.Release|Win32.ActiveCfg = Release|Win32 + {8E038A94-7D02-49E9-B9F6-5224D9D11225}.Release|Win32.Build.0 = Release|Win32 + {8E038A94-7D02-49E9-B9F6-5224D9D11225}.Release|x64.ActiveCfg = Release|x64 + {8E038A94-7D02-49E9-B9F6-5224D9D11225}.Release|x64.Build.0 = Release|x64 + {E8016236-E771-4BEC-8407-6BF37C68D174}.Debug|Win32.ActiveCfg = Debug|Win32 + {E8016236-E771-4BEC-8407-6BF37C68D174}.Debug|Win32.Build.0 = Debug|Win32 + {E8016236-E771-4BEC-8407-6BF37C68D174}.Debug|x64.ActiveCfg = Debug|x64 + {E8016236-E771-4BEC-8407-6BF37C68D174}.Debug|x64.Build.0 = Debug|x64 + {E8016236-E771-4BEC-8407-6BF37C68D174}.Release|Win32.ActiveCfg = Release|Win32 + {E8016236-E771-4BEC-8407-6BF37C68D174}.Release|Win32.Build.0 = Release|Win32 + {E8016236-E771-4BEC-8407-6BF37C68D174}.Release|x64.ActiveCfg = Release|x64 + {E8016236-E771-4BEC-8407-6BF37C68D174}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/native/MsgHook.suo b/native/MsgHook.suo new file mode 100644 index 0000000..ee98348 Binary files /dev/null and b/native/MsgHook.suo differ diff --git a/native/MsgHook/MsgHook.cpp b/native/MsgHook/MsgHook.cpp new file mode 100644 index 0000000..e2a7565 --- /dev/null +++ b/native/MsgHook/MsgHook.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2014, Synthuse.org + * Released under the Apache Version 2.0 License. + * + * last modified by ejakubowski7@gmail.com +*/ + + +// MsgHook.cpp : Defines the exported functions for the DLL application. +// + +#include "stdafx.h" + + +LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + COPYDATASTRUCT CDS; + HEVENT Event; + + CDS.dwData = 0; + CDS.cbData = sizeof(Event); + CDS.lpData = &Event; + + if (nCode == HC_ACTION) { + //For WH_CALLWNDPROC hook a pointer to a CWPSTRUCT structure that contains details about the message. + CWPSTRUCT *cwps = (CWPSTRUCT *)lParam; + + Event.lParam = cwps->lParam; + Event.wParam = cwps->wParam; + Event.nCode = cwps->message; + Event.dwHookType = WH_CALLWNDPROC; + + BOOL bRes = SendMessage(pData->g_hWnd, WM_COPYDATA, 0, (LPARAM)(VOID*)&CDS); // ask the controlling program if the hook should be passed + } + return CallNextHookEx(pData->g_hHook, nCode, wParam, lParam); // pass hook to next handler + //return bRes; // Don't tell the other hooks about this message. +} + +extern "C" __declspec(dllexport) BOOL SetHook(HWND callerHWnd, DWORD threadId) +{ + if(bStartingProcess) // if we're just starting the DLL for the first time, + { + pData->g_hWnd = callerHWnd; // remember the windows and hook handle for further instances + pData->g_hHook = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)HookProc, (HINSTANCE)pData->g_hInstance, threadId); + + return (pData->g_hHook != NULL); + } + else + return false; +} + +extern "C" __declspec(dllexport) BOOL RemoveHook() +{ + if (pData == NULL) + return false; + if(pData->g_hHook) // if the hook is defined + { + bool ret = UnhookWindowsHookEx(pData->g_hHook); + pData->g_hWnd = NULL; // reset data + pData->g_hHook = NULL; + return ret; + } + return false; +} \ No newline at end of file diff --git a/native/MsgHook/MsgHook.vcxproj b/native/MsgHook/MsgHook.vcxproj new file mode 100644 index 0000000..f613a06 --- /dev/null +++ b/native/MsgHook/MsgHook.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {8E038A94-7D02-49E9-B9F6-5224D9D11225} + Win32Proj + MsgHook + + + + DynamicLibrary + true + Unicode + + + DynamicLibrary + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MSGHOOK_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MSGHOOK_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MSGHOOK_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + mkdir "$(ProjectDir)bin" +copy /Y "$(TargetPath)" "$(ProjectDir)bin\MsgHook$(PlatformArchitecture)$(TargetExt)" + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MSGHOOK_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + mkdir "$(ProjectDir)bin" +copy /Y "$(TargetPath)" "$(ProjectDir)bin\MsgHook$(PlatformArchitecture)$(TargetExt)" + + + + + + + + + + + + false + false + + + + + false + false + + + + + + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/native/MsgHook/MsgHook.vcxproj.filters b/native/MsgHook/MsgHook.vcxproj.filters new file mode 100644 index 0000000..c8c6ca7 --- /dev/null +++ b/native/MsgHook/MsgHook.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/native/MsgHook/MsgHook.vcxproj.user b/native/MsgHook/MsgHook.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/native/MsgHook/MsgHook.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/native/MsgHook/ReadMe.txt b/native/MsgHook/ReadMe.txt new file mode 100644 index 0000000..4420318 --- /dev/null +++ b/native/MsgHook/ReadMe.txt @@ -0,0 +1,48 @@ +======================================================================== + DYNAMIC LINK LIBRARY : MsgHook Project Overview +======================================================================== + +AppWizard has created this MsgHook DLL for you. + +This file contains a summary of what you will find in each of the files that +make up your MsgHook application. + + +MsgHook.vcxproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +MsgHook.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +MsgHook.cpp + This is the main DLL source file. + + When created, this DLL does not export any symbols. As a result, it + will not produce a .lib file when it is built. If you wish this project + to be a project dependency of some other project, you will either need to + add code to export some symbols from the DLL so that an export library + will be produced, or you can set the Ignore Input Library property to Yes + on the General propert page of the Linker folder in the project's Property + Pages dialog box. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named MsgHook.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/native/MsgHook/bin/MsgHook32.dll b/native/MsgHook/bin/MsgHook32.dll new file mode 100644 index 0000000..7aa62dd Binary files /dev/null and b/native/MsgHook/bin/MsgHook32.dll differ diff --git a/native/MsgHook/bin/MsgHook64.dll b/native/MsgHook/bin/MsgHook64.dll new file mode 100644 index 0000000..845c912 Binary files /dev/null and b/native/MsgHook/bin/MsgHook64.dll differ diff --git a/native/MsgHook/build.bat b/native/MsgHook/build.bat new file mode 100644 index 0000000..626076c --- /dev/null +++ b/native/MsgHook/build.bat @@ -0,0 +1,6 @@ +REM set path=C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin;%path% + +%WinDir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe /p:configuration=release /p:platform=x64 %* +%WinDir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe /p:configuration=release /p:platform=win32 %* + +pause \ No newline at end of file diff --git a/native/MsgHook/dllmain.cpp b/native/MsgHook/dllmain.cpp new file mode 100644 index 0000000..d7866d3 --- /dev/null +++ b/native/MsgHook/dllmain.cpp @@ -0,0 +1,47 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" + +HANDLE hMappedFile; +GLOBALDATA* pData; +bool bStartingProcess = false; + + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + { + TCHAR szBaseName[_MAX_FNAME], szTmp[_MAX_FNAME]; + memset((void *)&szBaseName, '\0', sizeof(TCHAR) * _MAX_FNAME); + + if (GetModuleBaseName(GetCurrentProcess(), (HMODULE)hModule, szTmp, sizeof(szTmp)))// compute MMF-filename from current module base name, uses Psapi + _wsplitpath(szTmp, NULL, NULL, szBaseName, NULL); + + wcscat(szBaseName, TEXT("MsgHookSharedMem")); // add specifier string + + hMappedFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(GLOBALDATA), szBaseName); + pData = (GLOBALDATA*)MapViewOfFile(hMappedFile, FILE_MAP_WRITE, 0, 0, 0); + bStartingProcess = (hMappedFile != NULL) && (GetLastError() != ERROR_ALREADY_EXISTS); + + if(bStartingProcess) // if the MMF doesn't exist, we have the first instance + { + pData->g_hInstance = hModule; // so set the instance handle + pData->g_hWnd = NULL; // and initialize the other handles + pData->g_hHook = NULL; + } + DisableThreadLibraryCalls((HMODULE)hModule); + } + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + CloseHandle(hMappedFile); // on detaching the DLL, close the MMF + break; + } + return TRUE; +} + diff --git a/native/MsgHook/stdafx.cpp b/native/MsgHook/stdafx.cpp new file mode 100644 index 0000000..2d8db73 --- /dev/null +++ b/native/MsgHook/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// MsgHook.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file \ No newline at end of file diff --git a/native/MsgHook/stdafx.h b/native/MsgHook/stdafx.h new file mode 100644 index 0000000..bf473c9 --- /dev/null +++ b/native/MsgHook/stdafx.h @@ -0,0 +1,43 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include +#include +#include + +#pragma comment( lib, "psapi.lib" ) + +// TODO: reference additional headers your program requires here + +typedef struct +{ + int nCode; + DWORD dwHookType; + WPARAM wParam; + LPARAM lParam; +}HEVENT; + +typedef struct +{ + HHOOK g_hHook; + HWND g_hWnd; + HANDLE g_hInstance; +}GLOBALDATA; + +#ifndef GLOBAL_VARS_H // header guards +#define GLOBAL_VARS_H + +//Global variables , remember not to initialize here +extern HANDLE hMappedFile; +extern GLOBALDATA* pData; +extern bool bStartingProcess; + +#endif \ No newline at end of file diff --git a/native/MsgHook/targetver.h b/native/MsgHook/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/native/MsgHook/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/native/MsgHookTest/MsgHook.h b/native/MsgHookTest/MsgHook.h new file mode 100644 index 0000000..bc22199 --- /dev/null +++ b/native/MsgHookTest/MsgHook.h @@ -0,0 +1,300 @@ +#include + +#define MSGHOOKER_FILE TEXT("MsgHook.dll") + +HINSTANCE msgHookDll; + +//BOOL SetHook(HWND callerHWnd, DWORD threadId) +typedef BOOL (* SETHOOK)(HWND, DWORD); +SETHOOK SetHook; + +//BOOL RemoveHook() +typedef BOOL (* REMOVEHOOK)(VOID); +REMOVEHOOK RemoveHook; + +typedef struct +{ + int nCode; + DWORD dwHookType; + WPARAM wParam; + LPARAM lParam; +}HEVENT; + +/* +typedef struct { + DWORD vkCode; + DWORD scanCode; + DWORD flags; + DWORD time; + ULONG_PTR dwExtraInfo; +} KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT; +*/ + +BOOL InitHook(HWND hw, int threadId) +{ + msgHookDll = LoadLibrary(MSGHOOKER_FILE); + if (msgHookDll != NULL) + { + SetHook = (SETHOOK)GetProcAddress(msgHookDll, "SetHook"); + RemoveHook = (REMOVEHOOK)GetProcAddress(msgHookDll, "RemoveHook"); + if (SetHook) + { + return SetHook(hw, threadId); + } + } + return false; +} + +void KillHook() +{ + if (RemoveHook) + RemoveHook(); + + if (msgHookDll != NULL) + FreeLibrary(msgHookDll); +} + +// MSG Array LOOKUP +const int MAX_MSG_LOOKUP = 1024; +const int MAX_MSG_NAME = 21; +TCHAR MSG_LOOKUP[MAX_MSG_LOOKUP][MAX_MSG_NAME] = { +}; + + +//void InitializeMsgLookup() below +void InitializeMsgLookup(int allowList[], int allowSize) +{ + for (int i = 0 ; i < MAX_MSG_LOOKUP ; i++) + { + bool allowFlg = true; + if (allowSize > 0) + allowFlg = false; + for (int a = 0 ; a < allowSize ; a++) + if (allowList[a] == i) + allowFlg = true; + if (!allowFlg) + continue; + switch (i) + { + case WM_NULL: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NULL")); break; + case WM_CREATE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CREATE")); break; + case WM_DESTROY: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DESTROY")); break; + case WM_MOVE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MOVE")); break; + case WM_SIZE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SIZE")); break; + case WM_ACTIVATE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_ACTIVATE")); break; + case WM_SETFOCUS: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SETFOCUS")); break; + case WM_KILLFOCUS: _tcscpy_s(MSG_LOOKUP[i], _T("WM_KILLFOCUS")); break; + case WM_ENABLE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_ENABLE")); break; + case WM_SETREDRAW: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SETREDRAW")); break; + case WM_SETTEXT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SETTEXT")); break; + case WM_GETTEXT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_GETTEXT")); break; + case WM_GETTEXTLENGTH: _tcscpy_s(MSG_LOOKUP[i], _T("WM_GETTEXTLENGTH")); break; + case WM_PAINT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_PAINT")); break; + case WM_CLOSE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CLOSE")); break; + case WM_QUERYENDSESSION: _tcscpy_s(MSG_LOOKUP[i], _T("WM_QUERYENDSESSION")); break; + case WM_QUIT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_QUIT")); break; + case WM_QUERYOPEN: _tcscpy_s(MSG_LOOKUP[i], _T("WM_QUERYOPEN")); break; + case WM_ERASEBKGND: _tcscpy_s(MSG_LOOKUP[i], _T("WM_ERASEBKGND")); break; + case WM_SYSCOLORCHANGE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SYSCOLORCHANGE")); break; + case WM_ENDSESSION: _tcscpy_s(MSG_LOOKUP[i], _T("WM_ENDSESSION")); break; + case 0x17: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SYSTEMERROR")); break; + case WM_SHOWWINDOW: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SHOWWINDOW")); break; + case 0x19: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CTLCOLOR")); break; + case WM_WININICHANGE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_WININICHANGE")); break; + //case WM_SETTINGCHANGE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SETTINGCHANGE")); break; + case WM_DEVMODECHANGE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DEVMODECHANGE")); break; + case WM_ACTIVATEAPP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_ACTIVATEAPP")); break; + case WM_FONTCHANGE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_FONTCHANGE")); break; + case WM_TIMECHANGE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_TIMECHANGE")); break; + case WM_CANCELMODE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CANCELMODE")); break; + case WM_SETCURSOR: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SETCURSOR")); break; + case WM_MOUSEACTIVATE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MOUSEACTIVATE")); break; + case WM_CHILDACTIVATE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CHILDACTIVATE")); break; + case WM_QUEUESYNC: _tcscpy_s(MSG_LOOKUP[i], _T("WM_QUEUESYNC")); break; + case WM_GETMINMAXINFO: _tcscpy_s(MSG_LOOKUP[i], _T("WM_GETMINMAXINFO")); break; + case WM_PAINTICON: _tcscpy_s(MSG_LOOKUP[i], _T("WM_PAINTICON")); break; + case WM_ICONERASEBKGND: _tcscpy_s(MSG_LOOKUP[i], _T("WM_ICONERASEBKGND")); break; + case WM_NEXTDLGCTL: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NEXTDLGCTL")); break; + case WM_SPOOLERSTATUS: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SPOOLERSTATUS")); break; + case WM_DRAWITEM: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DRAWITEM")); break; + case WM_MEASUREITEM: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MEASUREITEM")); break; + case WM_DELETEITEM: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DELETEITEM")); break; + case WM_VKEYTOITEM: _tcscpy_s(MSG_LOOKUP[i], _T("WM_VKEYTOITEM")); break; + case WM_CHARTOITEM: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CHARTOITEM")); break; + case WM_SETFONT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SETFONT")); break; + case WM_GETFONT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_GETFONT")); break; + case WM_SETHOTKEY: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SETHOTKEY")); break; + case WM_GETHOTKEY: _tcscpy_s(MSG_LOOKUP[i], _T("WM_GETHOTKEY")); break; + case WM_QUERYDRAGICON: _tcscpy_s(MSG_LOOKUP[i], _T("WM_QUERYDRAGICON")); break; + case WM_COMPAREITEM: _tcscpy_s(MSG_LOOKUP[i], _T("WM_COMPAREITEM")); break; + case WM_COMPACTING: _tcscpy_s(MSG_LOOKUP[i], _T("WM_COMPACTING")); break; + case WM_WINDOWPOSCHANGING: _tcscpy_s(MSG_LOOKUP[i], _T("WM_WINDOWPOSCHANGING")); break; + case WM_WINDOWPOSCHANGED: _tcscpy_s(MSG_LOOKUP[i], _T("WM_WINDOWPOSCHANGED")); break; + case WM_POWER: _tcscpy_s(MSG_LOOKUP[i], _T("WM_POWER")); break; + case WM_COPYDATA: _tcscpy_s(MSG_LOOKUP[i], _T("WM_COPYDATA")); break; + case WM_CANCELJOURNAL: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CANCELJOURNAL")); break; + case WM_NOTIFY: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NOTIFY")); break; + case WM_INPUTLANGCHANGEREQUEST: _tcscpy_s(MSG_LOOKUP[i], _T("WM_INPUTLANGCHANGERE")); break; + case WM_INPUTLANGCHANGE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_INPUTLANGCHANGE")); break; + case WM_TCARD: _tcscpy_s(MSG_LOOKUP[i], _T("WM_TCARD")); break; + case WM_HELP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_HELP")); break; + case WM_USERCHANGED: _tcscpy_s(MSG_LOOKUP[i], _T("WM_USERCHANGED")); break; + case WM_NOTIFYFORMAT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NOTIFYFORMAT")); break; + case WM_CONTEXTMENU: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CONTEXTMENU")); break; + case WM_STYLECHANGING: _tcscpy_s(MSG_LOOKUP[i], _T("WM_STYLECHANGING")); break; + case WM_STYLECHANGED: _tcscpy_s(MSG_LOOKUP[i], _T("WM_STYLECHANGED")); break; + case WM_DISPLAYCHANGE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DISPLAYCHANGE")); break; + case WM_GETICON: _tcscpy_s(MSG_LOOKUP[i], _T("WM_GETICON")); break; + case WM_SETICON: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SETICON")); break; + case WM_NCCREATE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCCREATE")); break; + case WM_NCDESTROY: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCDESTROY")); break; + case WM_NCCALCSIZE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCCALCSIZE")); break; + case WM_NCHITTEST: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCHITTEST")); break; + case WM_NCPAINT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCPAINT")); break; + case WM_NCACTIVATE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCACTIVATE")); break; + case WM_GETDLGCODE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_GETDLGCODE")); break; + case WM_NCMOUSEMOVE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCMOUSEMOVE")); break; + case WM_NCLBUTTONDOWN: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCLBUTTONDOWN")); break; + case WM_NCLBUTTONUP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCLBUTTONUP")); break; + case WM_NCLBUTTONDBLCLK: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCLBUTTONDBLCLK")); break; + case WM_NCRBUTTONDOWN: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCRBUTTONDOWN")); break; + case WM_NCRBUTTONUP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCRBUTTONUP")); break; + case WM_NCRBUTTONDBLCLK: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCRBUTTONDBLCLK")); break; + case WM_NCMBUTTONDOWN: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCMBUTTONDOWN")); break; + case WM_NCMBUTTONUP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCMBUTTONUP")); break; + case WM_NCMBUTTONDBLCLK: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCMBUTTONDBLCLK")); break; + //case WM_KEYFIRST: _tcscpy_s(MSG_LOOKUP[i], _T("WM_KEYFIRST")); break; + case WM_KEYDOWN: _tcscpy_s(MSG_LOOKUP[i], _T("WM_KEYDOWN")); break; + case WM_KEYUP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_KEYUP")); break; + case WM_CHAR: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CHAR")); break; + case WM_DEADCHAR: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DEADCHAR")); break; + case WM_SYSKEYDOWN: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SYSKEYDOWN")); break; + case WM_SYSKEYUP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SYSKEYUP")); break; + case WM_SYSCHAR: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SYSCHAR")); break; + case WM_SYSDEADCHAR: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SYSDEADCHAR")); break; + case WM_KEYLAST: _tcscpy_s(MSG_LOOKUP[i], _T("WM_KEYLAST")); break; + case WM_IME_STARTCOMPOSITION: _tcscpy_s(MSG_LOOKUP[i], _T("WM_IME_STARTCOMPOSIT")); break; + case WM_IME_ENDCOMPOSITION: _tcscpy_s(MSG_LOOKUP[i], _T("WM_IME_ENDCOMPOSITIO")); break; + case WM_IME_COMPOSITION: _tcscpy_s(MSG_LOOKUP[i], _T("WM_IME_COMPOSITION")); break; + //case WM_IME_KEYLAST: _tcscpy_s(MSG_LOOKUP[i], _T("WM_IME_KEYLAST")); break; + case WM_INITDIALOG: _tcscpy_s(MSG_LOOKUP[i], _T("WM_INITDIALOG")); break; + case WM_COMMAND: _tcscpy_s(MSG_LOOKUP[i], _T("WM_COMMAND")); break; + case WM_SYSCOMMAND: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SYSCOMMAND")); break; + case WM_TIMER: _tcscpy_s(MSG_LOOKUP[i], _T("WM_TIMER")); break; + case WM_HSCROLL: _tcscpy_s(MSG_LOOKUP[i], _T("WM_HSCROLL")); break; + case WM_VSCROLL: _tcscpy_s(MSG_LOOKUP[i], _T("WM_VSCROLL")); break; + case WM_INITMENU: _tcscpy_s(MSG_LOOKUP[i], _T("WM_INITMENU")); break; + case WM_INITMENUPOPUP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_INITMENUPOPUP")); break; + case WM_MENUSELECT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MENUSELECT")); break; + case WM_MENUCHAR: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MENUCHAR")); break; + case WM_ENTERIDLE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_ENTERIDLE")); break; + case WM_CTLCOLORMSGBOX: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CTLCOLORMSGBOX")); break; + case WM_CTLCOLOREDIT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CTLCOLOREDIT")); break; + case WM_CTLCOLORLISTBOX: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CTLCOLORLISTBOX")); break; + case WM_CTLCOLORBTN: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CTLCOLORBTN")); break; + case WM_CTLCOLORDLG: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CTLCOLORDLG")); break; + case WM_CTLCOLORSCROLLBAR: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CTLCOLORSCROLLBAR")); break; + case WM_CTLCOLORSTATIC: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CTLCOLORSTATIC")); break; + case WM_MOUSEFIRST: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MOUSEFIRST")); break; + //case WM_MOUSEMOVE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MOUSEMOVE")); break; + case WM_LBUTTONDOWN: _tcscpy_s(MSG_LOOKUP[i], _T("WM_LBUTTONDOWN")); break; + case WM_LBUTTONUP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_LBUTTONUP")); break; + case WM_LBUTTONDBLCLK: _tcscpy_s(MSG_LOOKUP[i], _T("WM_LBUTTONDBLCLK")); break; + case WM_RBUTTONDOWN: _tcscpy_s(MSG_LOOKUP[i], _T("WM_RBUTTONDOWN")); break; + case WM_RBUTTONUP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_RBUTTONUP")); break; + case WM_RBUTTONDBLCLK: _tcscpy_s(MSG_LOOKUP[i], _T("WM_RBUTTONDBLCLK")); break; + case WM_MBUTTONDOWN: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MBUTTONDOWN")); break; + case WM_MBUTTONUP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MBUTTONUP")); break; + case WM_MBUTTONDBLCLK: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MBUTTONDBLCLK")); break; + case WM_MOUSEWHEEL: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MOUSEWHEEL")); break; + case WM_MOUSEHWHEEL: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MOUSEHWHEEL")); break; + case WM_PARENTNOTIFY: _tcscpy_s(MSG_LOOKUP[i], _T("WM_PARENTNOTIFY")); break; + case WM_ENTERMENULOOP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_ENTERMENULOOP")); break; + case WM_EXITMENULOOP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_EXITMENULOOP")); break; + case WM_NEXTMENU: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NEXTMENU")); break; + case WM_SIZING: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SIZING")); break; + case WM_CAPTURECHANGED: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CAPTURECHANGED")); break; + case WM_MOVING: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MOVING")); break; + case WM_POWERBROADCAST: _tcscpy_s(MSG_LOOKUP[i], _T("WM_POWERBROADCAST")); break; + case WM_DEVICECHANGE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DEVICECHANGE")); break; + case WM_MDICREATE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MDICREATE")); break; + case WM_MDIDESTROY: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MDIDESTROY")); break; + case WM_MDIACTIVATE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MDIACTIVATE")); break; + case WM_MDIRESTORE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MDIRESTORE")); break; + case WM_MDINEXT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MDINEXT")); break; + case WM_MDIMAXIMIZE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MDIMAXIMIZE")); break; + case WM_MDITILE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MDITILE")); break; + case WM_MDICASCADE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MDICASCADE")); break; + case WM_MDIICONARRANGE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MDIICONARRANGE")); break; + case WM_MDIGETACTIVE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MDIGETACTIVE")); break; + case WM_MDISETMENU: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MDISETMENU")); break; + case WM_ENTERSIZEMOVE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_ENTERSIZEMOVE")); break; + case WM_EXITSIZEMOVE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_EXITSIZEMOVE")); break; + case WM_DROPFILES: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DROPFILES")); break; + case WM_MDIREFRESHMENU: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MDIREFRESHMENU")); break; + case WM_IME_SETCONTEXT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_IME_SETCONTEXT")); break; + case WM_IME_NOTIFY: _tcscpy_s(MSG_LOOKUP[i], _T("WM_IME_NOTIFY")); break; + case WM_IME_CONTROL: _tcscpy_s(MSG_LOOKUP[i], _T("WM_IME_CONTROL")); break; + case WM_IME_COMPOSITIONFULL: _tcscpy_s(MSG_LOOKUP[i], _T("WM_IME_COMPOSITIONFU")); break; + case WM_IME_SELECT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_IME_SELECT")); break; + case WM_IME_CHAR: _tcscpy_s(MSG_LOOKUP[i], _T("WM_IME_CHAR")); break; + case WM_IME_KEYDOWN: _tcscpy_s(MSG_LOOKUP[i], _T("WM_IME_KEYDOWN")); break; + case WM_IME_KEYUP: _tcscpy_s(MSG_LOOKUP[i], _T("WM_IME_KEYUP")); break; + case WM_MOUSEHOVER: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MOUSEHOVER")); break; + case WM_NCMOUSELEAVE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_NCMOUSELEAVE")); break; + case WM_MOUSELEAVE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_MOUSELEAVE")); break; + case WM_CUT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CUT")); break; + case WM_COPY: _tcscpy_s(MSG_LOOKUP[i], _T("WM_COPY")); break; + case WM_PASTE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_PASTE")); break; + case WM_CLEAR: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CLEAR")); break; + case WM_UNDO: _tcscpy_s(MSG_LOOKUP[i], _T("WM_UNDO")); break; + case WM_RENDERFORMAT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_RENDERFORMAT")); break; + case WM_RENDERALLFORMATS: _tcscpy_s(MSG_LOOKUP[i], _T("WM_RENDERALLFORMATS")); break; + case WM_DESTROYCLIPBOARD: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DESTROYCLIPBOARD")); break; + case WM_DRAWCLIPBOARD: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DRAWCLIPBOARD")); break; + case WM_PAINTCLIPBOARD: _tcscpy_s(MSG_LOOKUP[i], _T("WM_PAINTCLIPBOARD")); break; + case WM_VSCROLLCLIPBOARD: _tcscpy_s(MSG_LOOKUP[i], _T("WM_VSCROLLCLIPBOARD")); break; + case WM_SIZECLIPBOARD: _tcscpy_s(MSG_LOOKUP[i], _T("WM_SIZECLIPBOARD")); break; + case WM_ASKCBFORMATNAME: _tcscpy_s(MSG_LOOKUP[i], _T("WM_ASKCBFORMATNAME")); break; + case WM_CHANGECBCHAIN: _tcscpy_s(MSG_LOOKUP[i], _T("WM_CHANGECBCHAIN")); break; + case WM_HSCROLLCLIPBOARD: _tcscpy_s(MSG_LOOKUP[i], _T("WM_HSCROLLCLIPBOARD")); break; + case WM_QUERYNEWPALETTE: _tcscpy_s(MSG_LOOKUP[i], _T("WM_QUERYNEWPALETTE")); break; + case WM_PALETTEISCHANGING: _tcscpy_s(MSG_LOOKUP[i], _T("WM_PALETTEISCHANGING")); break; + case WM_PALETTECHANGED: _tcscpy_s(MSG_LOOKUP[i], _T("WM_PALETTECHANGED")); break; + case WM_HOTKEY: _tcscpy_s(MSG_LOOKUP[i], _T("WM_HOTKEY")); break; + case WM_PRINT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_PRINT")); break; + case WM_PRINTCLIENT: _tcscpy_s(MSG_LOOKUP[i], _T("WM_PRINTCLIENT")); break; + case WM_HANDHELDFIRST: _tcscpy_s(MSG_LOOKUP[i], _T("WM_HANDHELDFIRST")); break; + case WM_HANDHELDLAST: _tcscpy_s(MSG_LOOKUP[i], _T("WM_HANDHELDLAST")); break; + case WM_PENWINFIRST: _tcscpy_s(MSG_LOOKUP[i], _T("WM_PENWINFIRST")); break; + case WM_PENWINLAST: _tcscpy_s(MSG_LOOKUP[i], _T("WM_PENWINLAST")); break; + case 0x390: _tcscpy_s(MSG_LOOKUP[i], _T("WM_COALESCE_FIRST")); break; + case 0x39F: _tcscpy_s(MSG_LOOKUP[i], _T("WM_COALESCE_LAST")); break; + case 0x3E0: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DDE_FIRST")); break; + //case 0x3E0: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DDE_INITIATE")); break; + case 0x3E1: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DDE_TERMINATE")); break; + case 0x3E2: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DDE_ADVISE")); break; + case 0x3E3: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DDE_UNADVISE")); break; + case 0x3E4: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DDE_ACK")); break; + case 0x3E5: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DDE_DATA")); break; + case 0x3E6: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DDE_REQUEST")); break; + case 0x3E7: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DDE_POKE")); break; + case 0x3E8: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DDE_EXECUTE")); break; + //case 0x3E8: _tcscpy_s(MSG_LOOKUP[i], _T("WM_DDE_LAST")); break; + + //case : _tcscpy_s(MSG_LOOKUP[i], _T("")); break; + default: + memset((void *)&MSG_LOOKUP[i], '\0', sizeof(TCHAR) * MAX_MSG_NAME); + //_tcscpy_s(MSG_LOOKUP[i], 20, _T("")); + break; + } + } +} + +void InitializeMsgLookup() +{ + int allowList[1]; + allowList[0] = -1; + InitializeMsgLookup(allowList, 0); +} + diff --git a/native/MsgHookTest/MsgHookTest.aps b/native/MsgHookTest/MsgHookTest.aps new file mode 100644 index 0000000..af32054 Binary files /dev/null and b/native/MsgHookTest/MsgHookTest.aps differ diff --git a/native/MsgHookTest/MsgHookTest.cpp b/native/MsgHookTest/MsgHookTest.cpp new file mode 100644 index 0000000..a9c6580 --- /dev/null +++ b/native/MsgHookTest/MsgHookTest.cpp @@ -0,0 +1,388 @@ +// MsgHookTest.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "MsgHookTest.h" +#include "MsgHook.h" + +#define MAX_LOADSTRING 100 + +// Global Variables: +HINSTANCE hInst; // current instance +TCHAR szTitle[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name +HWND mainHwnd = NULL; +HWND txtbox = NULL; +HWND targetHwnd = NULL; +//TCHAR targetClassname[100] = _T("Notepad"); +TCHAR targetClassname[100] = _T("WordPadClass"); +bool filterWmCommand = true; +bool filterWmNotify = false; +bool filterAbove = false; + + +// Forward declarations of functions included in this code module: +ATOM MyRegisterClass(HINSTANCE hInstance); +BOOL InitInstance(HINSTANCE, int); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); + +int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) +{ + + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + + // TODO: Place code here. + MSG msg; + HACCEL hAccelTable; + + // Initialize global strings + LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); + LoadString(hInstance, IDC_MSGHOOKTEST, szWindowClass, MAX_LOADSTRING); + MyRegisterClass(hInstance); + + // Perform application initialization: + if (!InitInstance (hInstance, nCmdShow)) + { + return FALSE; + } + + hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MSGHOOKTEST)); + + // Main message loop: + while (GetMessage(&msg, NULL, 0, 0)) + { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + return (int) msg.wParam; +} + +void AppendText(HWND txtHwnd, LPCTSTR newText) +{ + + DWORD len = GetWindowTextLength(txtHwnd); + if (len > 25000) + {//need to truncate the beginning so the text doesn't go past it's limit + SendMessage(txtHwnd, EM_SETSEL, 0, 10000); + SendMessage(txtHwnd, EM_REPLACESEL, 0, (LPARAM)_T("")); + len = GetWindowTextLength(txtHwnd); + } + //DWORD l,r; + //SendMessage(txtHwnd, EM_GETSEL,(WPARAM)&l,(LPARAM)&r); + SendMessage(txtHwnd, EM_SETSEL, len, len); + SendMessage(txtHwnd, EM_REPLACESEL, 0, (LPARAM)newText); + len = GetWindowTextLength(txtHwnd); + SendMessage(txtHwnd, EM_SETSEL, len, len); + //SendMessage(txtHwnd, EM_SETSEL,l,r); +} + +void InitMsgFiltersAndLookup() +{ + if (!filterWmCommand && !filterAbove && !filterWmNotify) + InitializeMsgLookup(); + else + { + int allowList[3]; + for (int i = 0; i < 3; i ++) + allowList[i] = -1; + + if (filterWmCommand) { + AppendText(txtbox, _T("filtering on WM_COMMAND & WM_MENUCOMMAND\r\n")); + allowList[0] = WM_COMMAND; + allowList[1] = WM_MENUCOMMAND; + } + if (filterWmNotify) + { + AppendText(txtbox, _T("filtering on WM_NOTIFY\r\n")); + allowList[2] = WM_NOTIFY; + } + //if (filterAbove) + // allowList[0] = WM_COMMAND; + InitializeMsgLookup(allowList, 3); + } +} + +void StartMessageHook() +{ + AppendText(txtbox, _T("Starting Message Hook\r\n")); + targetHwnd = FindWindow(targetClassname, NULL); + DWORD tid = GetWindowThreadProcessId(targetHwnd, NULL); + + InitMsgFiltersAndLookup(); + //InitializeMsgLookup(); + + TCHAR tmp[50]; + _stprintf_s(tmp, _T("Targetting %ld, %ld\r\n"), targetHwnd, tid); + AppendText(txtbox, tmp); + + //block self/global msg hook + if (targetHwnd == NULL || tid == 0) { + AppendText(txtbox, _T("Target window not found\r\n")); + return; + } + + if (InitHook(mainHwnd, tid)) + { + AppendText(txtbox, _T("Hook successfully initialized\r\n")); + } + else + AppendText(txtbox, _T("Hook failed to initialize\r\n")); +} + +void StopMessageHook() +{ + AppendText(txtbox, TEXT("Stopping Message Hook\r\n")); + KillHook(); +} + +bool OnCopyData(COPYDATASTRUCT* pCopyDataStruct) // WM_COPYDATA lParam will have this struct +{ + if( pCopyDataStruct->cbData!=sizeof(HEVENT)) + return false; + HEVENT Event; + memcpy(&Event, (HEVENT*)pCopyDataStruct->lpData, sizeof(HEVENT)); // transfer data to internal variable + if (Event.dwHookType == WH_KEYBOARD) + { + //KBDLLHOOKSTRUCT* pkh = (KBDLLHOOKSTRUCT*) Event.lParam; + //char tmp[50]; + //return wkvn->KeyboardData(pkh->vkCode,Event.wParam); + } + else if (Event.dwHookType == WH_MOUSE) + { + //MSLLHOOKSTRUCT* pmh = (MSLLHOOKSTRUCT*) Event.lParam; + //char tmp[50]; + //if (Event.wParam == WM_LBUTTONDOWN) + // return wkvn->MouseClickData(1,true); + // else + // return wkvn->MouseMoveData(pmh->pt.x,pmh->pt.y); + } + else if (Event.dwHookType == WH_CALLWNDPROC) + { + TCHAR *msgName = _T("unknown"); + if (Event.nCode < MAX_MSG_LOOKUP) + msgName = MSG_LOOKUP[Event.nCode]; + else + { + if (!filterAbove) + return false; + } + if (_tcscmp(msgName, _T("")) != 0) + { + TCHAR tmp[200]; + _stprintf_s(tmp, _T("msg: %s (%ld), wparam: %ld, lparam: %ld\r\n"), msgName, Event.nCode, Event.wParam, Event.lParam); + AppendText(txtbox, tmp); + } + } + return false; +} + +void SendWmSettext() //ID_TESTMSGS_WM +{ + //SetWindowText(targetHwnd, _T("This is a test")); + TCHAR txt[] = _T("This is a test"); + SendMessage(targetHwnd, WM_SETTEXT, 0 , (LPARAM)txt); + //PostMessage(targetHwnd, WM_SETTEXT, 0 , (LPARAM)txt); +} + +// +// FUNCTION: MyRegisterClass() +// +// PURPOSE: Registers the window class. +// +// COMMENTS: +// +// This function and its usage are only necessary if you want this code +// to be compatible with Win32 systems prior to the 'RegisterClassEx' +// function that was added to Windows 95. It is important to call this function +// so that the application will get 'well formed' small icons associated +// with it. +// +ATOM MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MSGHOOKTEST)); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = MAKEINTRESOURCE(IDC_MSGHOOKTEST); + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); + + return RegisterClassEx(&wcex); +} + +// +// FUNCTION: InitInstance(HINSTANCE, int) +// +// PURPOSE: Saves instance handle and creates main window +// +// COMMENTS: +// +// In this function, we save the instance handle in a global variable and +// create and display the main program window. +// +BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hInst = hInstance; // Store instance handle in our global variable + + hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); + + if (!hWnd) + return FALSE; + mainHwnd = hWnd; + + RECT rect; + GetClientRect(hWnd, &rect); + // make the txtbox edit control almost the same size as the parent window + //WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL + txtbox = CreateWindow(TEXT("Edit"),TEXT(""), WS_CHILD | WS_VISIBLE | ES_MULTILINE | WS_VSCROLL | ES_AUTOVSCROLL | ES_READONLY, + 10, 10,rect.right - 20, rect.bottom - 20, hWnd, NULL, NULL, NULL); + + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + return TRUE; +} + +// +// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) +// +// PURPOSE: Processes messages for the main window. +// +// WM_COMMAND - process the application menu +// WM_PAINT - Paint the main window +// WM_DESTROY - post a quit message and return +// +// +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + PAINTSTRUCT ps; + HDC hdc; + + switch (message) + { + case WM_CREATE: + //appendText(txtbox, TEXT("test\r\n")); + break; + case WM_COPYDATA: + return (OnCopyData((COPYDATASTRUCT *) lParam)); + break; + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case ID_FILE_STARTHOOK: + StartMessageHook(); + break; + case ID_FILE_STOPHOOK: + StopMessageHook(); + break; + case ID_TESTMSGS_WM: + SendWmSettext(); + break; + case ID_FILE_SETTINGS: + DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, About); + break; + case IDM_ABOUT: + DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); + break; + case IDM_EXIT: + DestroyWindow(hWnd); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + break; + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + // TODO: Add any drawing code here... + EndPaint(hWnd, &ps); + break; + case WM_SIZE: + { //resize the txtbox when the parent window size changes + int nWidth = LOWORD(lParam); + int nHeight = HIWORD(lParam); + SetWindowPos(txtbox, HWND_NOTOPMOST, 10, 10, nWidth-20, nHeight-20, SWP_NOZORDER|SWP_NOMOVE); + } + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + +// Message handler for about box. +INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + UNREFERENCED_PARAMETER(lParam); + switch (message) + { + case WM_INITDIALOG: + { + //IDC_EDIT1 + HWND classnameHwnd = GetDlgItem(hDlg, IDC_EDIT1); + if (classnameHwnd != NULL) + SetWindowText(classnameHwnd, targetClassname); + + if (filterWmCommand) + SendDlgItemMessage(hDlg, IDC_CHECK_CMD, BM_SETCHECK, BST_CHECKED, 0); + if (filterWmNotify) + SendDlgItemMessage(hDlg, IDC_CHECK_NOT, BM_SETCHECK, BST_CHECKED, 0); + if (filterAbove) + SendDlgItemMessage(hDlg, IDC_CHECK_ABO, BM_SETCHECK, BST_CHECKED, 0); + + } + return (INT_PTR)TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) //only save on OK + { + HWND classnameHwnd = GetDlgItem(hDlg, IDC_EDIT1); + if (classnameHwnd != NULL) + GetWindowText(classnameHwnd, targetClassname, 100); + // check filter options + if (SendDlgItemMessage(hDlg, IDC_CHECK_CMD, BM_GETCHECK, 0, 0) == BST_CHECKED) // the hard way + filterWmCommand = true; + else + filterWmCommand = false; + if (IsDlgButtonChecked(hDlg, IDC_CHECK_NOT) == BST_CHECKED) // the easy way + filterWmNotify = true; + else + filterWmNotify = false; + if (IsDlgButtonChecked(hDlg, IDC_CHECK_ABO) == BST_CHECKED) + filterAbove = true; + else + filterAbove = false; + InitMsgFiltersAndLookup(); + } + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, LOWORD(wParam)); + return (INT_PTR)TRUE; + } + break; + } + return (INT_PTR)FALSE; +} diff --git a/native/MsgHookTest/MsgHookTest.h b/native/MsgHookTest/MsgHookTest.h new file mode 100644 index 0000000..d00d47e --- /dev/null +++ b/native/MsgHookTest/MsgHookTest.h @@ -0,0 +1,3 @@ +#pragma once + +#include "resource.h" diff --git a/native/MsgHookTest/MsgHookTest.ico b/native/MsgHookTest/MsgHookTest.ico new file mode 100644 index 0000000..d551aa3 Binary files /dev/null and b/native/MsgHookTest/MsgHookTest.ico differ diff --git a/native/MsgHookTest/MsgHookTest.rc b/native/MsgHookTest/MsgHookTest.rc new file mode 100644 index 0000000..aa28307 Binary files /dev/null and b/native/MsgHookTest/MsgHookTest.rc differ diff --git a/native/MsgHookTest/MsgHookTest.vcxproj b/native/MsgHookTest/MsgHookTest.vcxproj new file mode 100644 index 0000000..677680c --- /dev/null +++ b/native/MsgHookTest/MsgHookTest.vcxproj @@ -0,0 +1,166 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {E8016236-E771-4BEC-8407-6BF37C68D174} + Win32Proj + MsgHookTest + + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + false + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + {8e038a94-7d02-49e9-b9f6-5224d9d11225} + + + + + + \ No newline at end of file diff --git a/native/MsgHookTest/MsgHookTest.vcxproj.filters b/native/MsgHookTest/MsgHookTest.vcxproj.filters new file mode 100644 index 0000000..7343c35 --- /dev/null +++ b/native/MsgHookTest/MsgHookTest.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + Resource Files + + + Resource Files + + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/native/MsgHookTest/MsgHookTest.vcxproj.user b/native/MsgHookTest/MsgHookTest.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/native/MsgHookTest/MsgHookTest.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/native/MsgHookTest/ReadMe.txt b/native/MsgHookTest/ReadMe.txt new file mode 100644 index 0000000..6d81f3a --- /dev/null +++ b/native/MsgHookTest/ReadMe.txt @@ -0,0 +1,62 @@ +======================================================================== + WIN32 APPLICATION : MsgHookTest Project Overview +======================================================================== + +AppWizard has created this MsgHookTest application for you. + +This file contains a summary of what you will find in each of the files that +make up your MsgHookTest application. + + +MsgHookTest.vcxproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +MsgHookTest.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +MsgHookTest.cpp + This is the main application source file. + +///////////////////////////////////////////////////////////////////////////// +AppWizard has created the following resources: + +MsgHookTest.rc + This is a listing of all of the Microsoft Windows resources that the + program uses. It includes the icons, bitmaps, and cursors that are stored + in the RES subdirectory. This file can be directly edited in Microsoft + Visual C++. + +Resource.h + This is the standard header file, which defines new resource IDs. + Microsoft Visual C++ reads and updates this file. + +MsgHookTest.ico + This is an icon file, which is used as the application's icon (32x32). + This icon is included by the main resource file MsgHookTest.rc. + +small.ico + This is an icon file, which contains a smaller version (16x16) + of the application's icon. This icon is included by the main resource + file MsgHookTest.rc. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named MsgHookTest.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/native/MsgHookTest/WinMessages.txt b/native/MsgHookTest/WinMessages.txt new file mode 100644 index 0000000..e27e2f4 --- /dev/null +++ b/native/MsgHookTest/WinMessages.txt @@ -0,0 +1,416 @@ + +WM_NULL = 0x00 +WM_CREATE = 0x01 +WM_DESTROY = 0x02 +WM_MOVE = 0x03 +WM_SIZE = 0x05 +WM_ACTIVATE = 0x06 +WM_SETFOCUS = 0x07 +WM_KILLFOCUS = 0x08 +WM_ENABLE = 0x0A +WM_SETREDRAW = 0x0B +WM_SETTEXT = 0x0C +WM_GETTEXT = 0x0D +WM_GETTEXTLENGTH = 0x0E +WM_PAINT = 0x0F +WM_CLOSE = 0x10 +WM_QUERYENDSESSION = 0x11 +WM_QUIT = 0x12 +WM_QUERYOPEN = 0x13 +WM_ERASEBKGND = 0x14 +WM_SYSCOLORCHANGE = 0x15 +WM_ENDSESSION = 0x16 +WM_SYSTEMERROR = 0x17 +WM_SHOWWINDOW = 0x18 +WM_CTLCOLOR = 0x19 +WM_WININICHANGE = 0x1A +WM_SETTINGCHANGE = 0x1A +WM_DEVMODECHANGE = 0x1B +WM_ACTIVATEAPP = 0x1C +WM_FONTCHANGE = 0x1D +WM_TIMECHANGE = 0x1E +WM_CANCELMODE = 0x1F +WM_SETCURSOR = 0x20 +WM_MOUSEACTIVATE = 0x21 +WM_CHILDACTIVATE = 0x22 +WM_QUEUESYNC = 0x23 +WM_GETMINMAXINFO = 0x24 +WM_PAINTICON = 0x26 +WM_ICONERASEBKGND = 0x27 +WM_NEXTDLGCTL = 0x28 +WM_SPOOLERSTATUS = 0x2A +WM_DRAWITEM = 0x2B +WM_MEASUREITEM = 0x2C +WM_DELETEITEM = 0x2D +WM_VKEYTOITEM = 0x2E +WM_CHARTOITEM = 0x2F +WM_SETFONT = 0x30 +WM_GETFONT = 0x31 +WM_SETHOTKEY = 0x32 +WM_GETHOTKEY = 0x33 +WM_QUERYDRAGICON = 0x37 +WM_COMPAREITEM = 0x39 +WM_COMPACTING = 0x41 +WM_WINDOWPOSCHANGING = 0x46 +WM_WINDOWPOSCHANGED = 0x47 +WM_POWER = 0x48 +WM_COPYDATA = 0x4A +WM_CANCELJOURNAL = 0x4B +WM_NOTIFY = 0x4E +WM_INPUTLANGCHANGEREQUEST = 0x50 +WM_INPUTLANGCHANGE = 0x51 +WM_TCARD = 0x52 +WM_HELP = 0x53 +WM_USERCHANGED = 0x54 +WM_NOTIFYFORMAT = 0x55 +WM_CONTEXTMENU = 0x7B +WM_STYLECHANGING = 0x7C +WM_STYLECHANGED = 0x7D +WM_DISPLAYCHANGE = 0x7E +WM_GETICON = 0x7F +WM_SETICON = 0x80 +WM_NCCREATE = 0x81 +WM_NCDESTROY = 0x82 +WM_NCCALCSIZE = 0x83 +WM_NCHITTEST = 0x84 +WM_NCPAINT = 0x85 +WM_NCACTIVATE = 0x86 +WM_GETDLGCODE = 0x87 +WM_NCMOUSEMOVE = 0xA0 +WM_NCLBUTTONDOWN = 0xA1 +WM_NCLBUTTONUP = 0xA2 +WM_NCLBUTTONDBLCLK = 0xA3 +WM_NCRBUTTONDOWN = 0xA4 +WM_NCRBUTTONUP = 0xA5 +WM_NCRBUTTONDBLCLK = 0xA6 +WM_NCMBUTTONDOWN = 0xA7 +WM_NCMBUTTONUP = 0xA8 +WM_NCMBUTTONDBLCLK = 0xA9 +WM_KEYFIRST = 0x100 +WM_KEYDOWN = 0x100 +WM_KEYUP = 0x101 +WM_CHAR = 0x102 +WM_DEADCHAR = 0x103 +WM_SYSKEYDOWN = 0x104 +WM_SYSKEYUP = 0x105 +WM_SYSCHAR = 0x106 +WM_SYSDEADCHAR = 0x107 +WM_KEYLAST = 0x108 +WM_IME_STARTCOMPOSITION = 0x10D +WM_IME_ENDCOMPOSITION = 0x10E +WM_IME_COMPOSITION = 0x10F +WM_IME_KEYLAST = 0x10F +WM_INITDIALOG = 0x110 +WM_COMMAND = 0x111 +WM_SYSCOMMAND = 0x112 +WM_TIMER = 0x113 +WM_HSCROLL = 0x114 +WM_VSCROLL = 0x115 +WM_INITMENU = 0x116 +WM_INITMENUPOPUP = 0x117 +WM_MENUSELECT = 0x11F +WM_MENUCHAR = 0x120 +WM_ENTERIDLE = 0x121 +WM_CTLCOLORMSGBOX = 0x132 +WM_CTLCOLOREDIT = 0x133 +WM_CTLCOLORLISTBOX = 0x134 +WM_CTLCOLORBTN = 0x135 +WM_CTLCOLORDLG = 0x136 +WM_CTLCOLORSCROLLBAR = 0x137 +WM_CTLCOLORSTATIC = 0x138 +WM_MOUSEFIRST = 0x200 +WM_MOUSEMOVE = 0x200 +WM_LBUTTONDOWN = 0x201 +WM_LBUTTONUP = 0x202 +WM_LBUTTONDBLCLK = 0x203 +WM_RBUTTONDOWN = 0x204 +WM_RBUTTONUP = 0x205 +WM_RBUTTONDBLCLK = 0x206 +WM_MBUTTONDOWN = 0x207 +WM_MBUTTONUP = 0x208 +WM_MBUTTONDBLCLK = 0x209 +WM_MOUSEWHEEL = 0x20A +WM_MOUSEHWHEEL = 0x20E +WM_PARENTNOTIFY = 0x210 +WM_ENTERMENULOOP = 0x211 +WM_EXITMENULOOP = 0x212 +WM_NEXTMENU = 0x213 +WM_SIZING = 0x214 +WM_CAPTURECHANGED = 0x215 +WM_MOVING = 0x216 +WM_POWERBROADCAST = 0x218 +WM_DEVICECHANGE = 0x219 +WM_MDICREATE = 0x220 +WM_MDIDESTROY = 0x221 +WM_MDIACTIVATE = 0x222 +WM_MDIRESTORE = 0x223 +WM_MDINEXT = 0x224 +WM_MDIMAXIMIZE = 0x225 +WM_MDITILE = 0x226 +WM_MDICASCADE = 0x227 +WM_MDIICONARRANGE = 0x228 +WM_MDIGETACTIVE = 0x229 +WM_MDISETMENU = 0x230 +WM_ENTERSIZEMOVE = 0x231 +WM_EXITSIZEMOVE = 0x232 +WM_DROPFILES = 0x233 +WM_MDIREFRESHMENU = 0x234 +WM_IME_SETCONTEXT = 0x281 +WM_IME_NOTIFY = 0x282 +WM_IME_CONTROL = 0x283 +WM_IME_COMPOSITIONFULL = 0x284 +WM_IME_SELECT = 0x285 +WM_IME_CHAR = 0x286 +WM_IME_KEYDOWN = 0x290 +WM_IME_KEYUP = 0x291 +WM_MOUSEHOVER = 0x2A1 +WM_NCMOUSELEAVE = 0x2A2 +WM_MOUSELEAVE = 0x2A3 +WM_CUT = 0x300 +WM_COPY = 0x301 +WM_PASTE = 0x302 +WM_CLEAR = 0x303 +WM_UNDO = 0x304 +WM_RENDERFORMAT = 0x305 +WM_RENDERALLFORMATS = 0x306 +WM_DESTROYCLIPBOARD = 0x307 +WM_DRAWCLIPBOARD = 0x308 +WM_PAINTCLIPBOARD = 0x309 +WM_VSCROLLCLIPBOARD = 0x30A +WM_SIZECLIPBOARD = 0x30B +WM_ASKCBFORMATNAME = 0x30C +WM_CHANGECBCHAIN = 0x30D +WM_HSCROLLCLIPBOARD = 0x30E +WM_QUERYNEWPALETTE = 0x30F +WM_PALETTEISCHANGING = 0x310 +WM_PALETTECHANGED = 0x311 +WM_HOTKEY = 0x312 +WM_PRINT = 0x317 +WM_PRINTCLIENT = 0x318 +WM_HANDHELDFIRST = 0x358 +WM_HANDHELDLAST = 0x35F +WM_PENWINFIRST = 0x380 +WM_PENWINLAST = 0x38F +WM_COALESCE_FIRST = 0x390 +WM_COALESCE_LAST = 0x39F +WM_DDE_FIRST = 0x3E0 +WM_DDE_INITIATE = 0x3E0 +WM_DDE_TERMINATE = 0x3E1 +WM_DDE_ADVISE = 0x3E2 +WM_DDE_UNADVISE = 0x3E3 +WM_DDE_ACK = 0x3E4 +WM_DDE_DATA = 0x3E5 +WM_DDE_REQUEST = 0x3E6 +WM_DDE_POKE = 0x3E7 +WM_DDE_EXECUTE = 0x3E8 +WM_DDE_LAST = 0x3E8 + + + + + +WM_NULL +WM_CREATE +WM_DESTROY +WM_MOVE +WM_SIZE +WM_ACTIVATE +WM_SETFOCUS +WM_KILLFOCUS +WM_ENABLE +WM_SETREDRAW +WM_SETTEXT +WM_GETTEXT +WM_GETTEXTLENGTH +WM_PAINT +WM_CLOSE +WM_QUERYENDSESSION +WM_QUIT +WM_QUERYOPEN +WM_ERASEBKGND +WM_SYSCOLORCHANGE +WM_ENDSESSION +WM_SYSTEMERROR +WM_SHOWWINDOW +WM_CTLCOLOR +WM_WININICHANGE +WM_SETTINGCHANGE +WM_DEVMODECHANGE +WM_ACTIVATEAPP +WM_FONTCHANGE +WM_TIMECHANGE +WM_CANCELMODE +WM_SETCURSOR +WM_MOUSEACTIVATE +WM_CHILDACTIVATE +WM_QUEUESYNC +WM_GETMINMAXINFO +WM_PAINTICON +WM_ICONERASEBKGND +WM_NEXTDLGCTL +WM_SPOOLERSTATUS +WM_DRAWITEM +WM_MEASUREITEM +WM_DELETEITEM +WM_VKEYTOITEM +WM_CHARTOITEM +WM_SETFONT +WM_GETFONT +WM_SETHOTKEY +WM_GETHOTKEY +WM_QUERYDRAGICON +WM_COMPAREITEM +WM_COMPACTING +WM_WINDOWPOSCHANGING +WM_WINDOWPOSCHANGED +WM_POWER +WM_COPYDATA +WM_CANCELJOURNAL +WM_NOTIFY +WM_INPUTLANGCHANGEREQUEST +WM_INPUTLANGCHANGE +WM_TCARD +WM_HELP +WM_USERCHANGED +WM_NOTIFYFORMAT +WM_CONTEXTMENU +WM_STYLECHANGING +WM_STYLECHANGED +WM_DISPLAYCHANGE +WM_GETICON +WM_SETICON +WM_NCCREATE +WM_NCDESTROY +WM_NCCALCSIZE +WM_NCHITTEST +WM_NCPAINT +WM_NCACTIVATE +WM_GETDLGCODE +WM_NCMOUSEMOVE +WM_NCLBUTTONDOWN +WM_NCLBUTTONUP +WM_NCLBUTTONDBLCLK +WM_NCRBUTTONDOWN +WM_NCRBUTTONUP +WM_NCRBUTTONDBLCLK +WM_NCMBUTTONDOWN +WM_NCMBUTTONUP +WM_NCMBUTTONDBLCLK +WM_KEYFIRST +WM_KEYDOWN +WM_KEYUP +WM_CHAR +WM_DEADCHAR +WM_SYSKEYDOWN +WM_SYSKEYUP +WM_SYSCHAR +WM_SYSDEADCHAR +WM_KEYLAST +WM_IME_STARTCOMPOSITION +WM_IME_ENDCOMPOSITION +WM_IME_COMPOSITION +WM_IME_KEYLAST +WM_INITDIALOG +WM_COMMAND +WM_SYSCOMMAND +WM_TIMER +WM_HSCROLL +WM_VSCROLL +WM_INITMENU +WM_INITMENUPOPUP +WM_MENUSELECT +WM_MENUCHAR +WM_ENTERIDLE +WM_CTLCOLORMSGBOX +WM_CTLCOLOREDIT +WM_CTLCOLORLISTBOX +WM_CTLCOLORBTN +WM_CTLCOLORDLG +WM_CTLCOLORSCROLLBAR +WM_CTLCOLORSTATIC +WM_MOUSEFIRST +WM_MOUSEMOVE +WM_LBUTTONDOWN +WM_LBUTTONUP +WM_LBUTTONDBLCLK +WM_RBUTTONDOWN +WM_RBUTTONUP +WM_RBUTTONDBLCLK +WM_MBUTTONDOWN +WM_MBUTTONUP +WM_MBUTTONDBLCLK +WM_MOUSEWHEEL +WM_MOUSEHWHEEL +WM_PARENTNOTIFY +WM_ENTERMENULOOP +WM_EXITMENULOOP +WM_NEXTMENU +WM_SIZING +WM_CAPTURECHANGED +WM_MOVING +WM_POWERBROADCAST +WM_DEVICECHANGE +WM_MDICREATE +WM_MDIDESTROY +WM_MDIACTIVATE +WM_MDIRESTORE +WM_MDINEXT +WM_MDIMAXIMIZE +WM_MDITILE +WM_MDICASCADE +WM_MDIICONARRANGE +WM_MDIGETACTIVE +WM_MDISETMENU +WM_ENTERSIZEMOVE +WM_EXITSIZEMOVE +WM_DROPFILES +WM_MDIREFRESHMENU +WM_IME_SETCONTEXT +WM_IME_NOTIFY +WM_IME_CONTROL +WM_IME_COMPOSITIONFULL +WM_IME_SELECT +WM_IME_CHAR +WM_IME_KEYDOWN +WM_IME_KEYUP +WM_MOUSEHOVER +WM_NCMOUSELEAVE +WM_MOUSELEAVE +WM_CUT +WM_COPY +WM_PASTE +WM_CLEAR +WM_UNDO +WM_RENDERFORMAT +WM_RENDERALLFORMATS +WM_DESTROYCLIPBOARD +WM_DRAWCLIPBOARD +WM_PAINTCLIPBOARD +WM_VSCROLLCLIPBOARD +WM_SIZECLIPBOARD +WM_ASKCBFORMATNAME +WM_CHANGECBCHAIN +WM_HSCROLLCLIPBOARD +WM_QUERYNEWPALETTE +WM_PALETTEISCHANGING +WM_PALETTECHANGED +WM_HOTKEY +WM_PRINT +WM_PRINTCLIENT +WM_HANDHELDFIRST +WM_HANDHELDLAST +WM_PENWINFIRST +WM_PENWINLAST +WM_COALESCE_FIRST +WM_COALESCE_LAST +WM_DDE_FIRST +WM_DDE_INITIATE +WM_DDE_TERMINATE +WM_DDE_ADVISE +WM_DDE_UNADVISE +WM_DDE_ACK +WM_DDE_DATA +WM_DDE_REQUEST +WM_DDE_POKE +WM_DDE_EXECUTE +WM_DDE_LAST \ No newline at end of file diff --git a/native/MsgHookTest/bin/x32/MsgHook.dll b/native/MsgHookTest/bin/x32/MsgHook.dll new file mode 100644 index 0000000..c618653 Binary files /dev/null and b/native/MsgHookTest/bin/x32/MsgHook.dll differ diff --git a/native/MsgHookTest/bin/x32/MsgHook.exp b/native/MsgHookTest/bin/x32/MsgHook.exp new file mode 100644 index 0000000..1d8c88c Binary files /dev/null and b/native/MsgHookTest/bin/x32/MsgHook.exp differ diff --git a/native/MsgHookTest/bin/x32/MsgHook.lib b/native/MsgHookTest/bin/x32/MsgHook.lib new file mode 100644 index 0000000..c6192c3 Binary files /dev/null and b/native/MsgHookTest/bin/x32/MsgHook.lib differ diff --git a/native/MsgHookTest/bin/x32/MsgHookTest.exe b/native/MsgHookTest/bin/x32/MsgHookTest.exe new file mode 100644 index 0000000..773a387 Binary files /dev/null and b/native/MsgHookTest/bin/x32/MsgHookTest.exe differ diff --git a/native/MsgHookTest/bin/x64/MsgHook.dll b/native/MsgHookTest/bin/x64/MsgHook.dll new file mode 100644 index 0000000..b47b70c Binary files /dev/null and b/native/MsgHookTest/bin/x64/MsgHook.dll differ diff --git a/native/MsgHookTest/bin/x64/MsgHook.exp b/native/MsgHookTest/bin/x64/MsgHook.exp new file mode 100644 index 0000000..dfc8590 Binary files /dev/null and b/native/MsgHookTest/bin/x64/MsgHook.exp differ diff --git a/native/MsgHookTest/bin/x64/MsgHook.lib b/native/MsgHookTest/bin/x64/MsgHook.lib new file mode 100644 index 0000000..f9c2879 Binary files /dev/null and b/native/MsgHookTest/bin/x64/MsgHook.lib differ diff --git a/native/MsgHookTest/bin/x64/MsgHookTest.exe b/native/MsgHookTest/bin/x64/MsgHookTest.exe new file mode 100644 index 0000000..1787834 Binary files /dev/null and b/native/MsgHookTest/bin/x64/MsgHookTest.exe differ diff --git a/native/MsgHookTest/resource.h b/native/MsgHookTest/resource.h new file mode 100644 index 0000000..36293d5 Binary files /dev/null and b/native/MsgHookTest/resource.h differ diff --git a/native/MsgHookTest/small.ico b/native/MsgHookTest/small.ico new file mode 100644 index 0000000..d551aa3 Binary files /dev/null and b/native/MsgHookTest/small.ico differ diff --git a/native/MsgHookTest/stdafx.cpp b/native/MsgHookTest/stdafx.cpp new file mode 100644 index 0000000..56acf67 --- /dev/null +++ b/native/MsgHookTest/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// MsgHookTest.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/native/MsgHookTest/stdafx.h b/native/MsgHookTest/stdafx.h new file mode 100644 index 0000000..24919b6 --- /dev/null +++ b/native/MsgHookTest/stdafx.h @@ -0,0 +1,23 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + +// C RunTime Header Files +#include +#include +#include +#include +#include +#include + + +// TODO: reference additional headers your program requires here diff --git a/native/MsgHookTest/targetver.h b/native/MsgHookTest/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/native/MsgHookTest/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/src/org/synthuse/Api.java b/src/org/synthuse/Api.java index 3af52f2..8add96b 100644 --- a/src/org/synthuse/Api.java +++ b/src/org/synthuse/Api.java @@ -77,6 +77,13 @@ public class Api { public static int PROCESS_VM_READ = 0x0010; public static int PS_SOLID = 0x0; + public static int PS_DASH = 0x1; + public static int PS_DOT = 0x2; + public static int PS_DASHDOT = 0x3; + public static int PS_DASHDOTDOT = 0x4; + public static int PS_NULL = 0x5; + public static int PS_INSIDEFRAME = 0x6; + public static int HOLLOW_BRUSH = 0x5; public static int WM_PAINT = 0x0F; @@ -521,14 +528,19 @@ public class Api { String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i"); return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); } - - // creates highlight around selected window + public static void highlightWindow(HWND hwnd){ + RECT rect = new RECT(); + User32.instance.GetWindowRect(hwnd, rect); + //System.out.println("RECT: " + rect.left + "," + rect.top + "," + (rect.right - rect.left) + "," + (rect.bottom - rect.top)); + highlightWindow(hwnd, 0, 0, rect.right - rect.left, rect.bottom - rect.top); + } + + // creates highlight around selected window + public static void highlightWindow(HWND hwnd, int x, int y, int x2, int y2){ //COLORREF i.e. 0x00804070 Red = 0x70 green = 0x40 blue = 0x80 //g_hRectanglePen = CreatePen (PS_SOLID, 3, RGB(256, 0, 0)); HPEN rectPen = Gdi32.instance.CreatePen(PS_SOLID, 3, 0x00000099); //RGB(255, 0, 0) - RECT rect = new RECT(); - User32.instance.GetWindowRect(hwnd, rect); HDC dc = User32.instance.GetWindowDC(hwnd); if (dc != null) { // Select our created pen into the DC and backup the previous pen. @@ -538,7 +550,7 @@ public class Api { HANDLE prevBrush = Gdi32.instance.SelectObject(dc, Gdi32.instance.GetStockObject(HOLLOW_BRUSH)); // Draw a rectangle in the DC covering the entire window area of the found window. - Gdi32.instance.Rectangle (dc, 0, 0, rect.right - rect.left, rect.bottom - rect.top); + Gdi32.instance.Rectangle (dc, x, y, x2, y2); // Reinsert the previous pen and brush into the found window's DC. Gdi32.instance.SelectObject(dc, prevPen); diff --git a/src/org/synthuse/MessageHookFrame.java b/src/org/synthuse/MessageHookFrame.java new file mode 100644 index 0000000..7ce1751 --- /dev/null +++ b/src/org/synthuse/MessageHookFrame.java @@ -0,0 +1,142 @@ +package org.synthuse; + +import javax.swing.JFrame; +import javax.swing.JToolBar; +import java.awt.BorderLayout; +import javax.swing.JTextArea; +import javax.swing.JScrollPane; +import javax.swing.JButton; + + +import com.sun.jna.platform.win32.User32; +import com.sun.jna.platform.win32.WinDef.*; +import com.sun.jna.platform.win32.Kernel32; +import com.sun.jna.platform.win32.WinUser.HHOOK; +import com.sun.jna.platform.win32.WinUser.HOOKPROC; +import com.sun.jna.platform.win32.WinUser.MSG; + +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; + +public class MessageHookFrame extends JFrame { + + private static final long serialVersionUID = -5863279004595502801L; + + public static final int WH_CALLWNDPROC = 4; + public static final int WH_GETMESSAGE = 3; + public static final int WH_KEYBOARD_LL = 13; + + private JTextArea textArea; + private JButton btnSave; + private JButton btnStartMsgHook; + private JButton btnPause; + private JButton btnClear; + + public static HHOOK hHook = null; + //public static LowLevelKeyboardProc lpfn; + public static volatile boolean quit = false; + + public MessageHookFrame() { + setTitle("Message Hook"); + setBounds(100, 100, 700, 367); + + JToolBar toolBar = new JToolBar(); + getContentPane().add(toolBar, BorderLayout.NORTH); + + btnStartMsgHook = new JButton("Start Hook"); + btnStartMsgHook.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (btnStartMsgHook.getText().equals("Start Hook")) + { //start Message Hook + btnStartMsgHook.setText("Stop Hook"); + createMessageHook(); + } + else + { //stop message hook + btnStartMsgHook.setText("Start Hook"); + stopMessageHook(); + } + } + }); + toolBar.add(btnStartMsgHook); + + btnPause = new JButton("Pause"); + btnPause.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + } + }); + toolBar.add(btnPause); + + btnSave = new JButton("Save"); + btnSave.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + } + }); + toolBar.add(btnSave); + + btnClear = new JButton("Clear"); + btnClear.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + textArea.setText(""); + } + }); + toolBar.add(btnClear); + + JScrollPane scrollPane = new JScrollPane(); + getContentPane().add(scrollPane, BorderLayout.CENTER); + + textArea = new JTextArea(); + scrollPane.setViewportView(textArea); + super.setAlwaysOnTop(SynthuseDlg.config.isAlwaysOnTop()); + } + + public void createMessageHook() { + if (hHook != null) + return; //hook already running don't add anymore + System.out.println("starting global message hook"); + HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null); + int threadId = Kernel32.INSTANCE.GetCurrentThreadId(); + HOOKPROC lpfn = new HOOKPROC() { + @SuppressWarnings("unused") + public LRESULT callback(int nCode, WPARAM wParam, LPARAM lParam) { + //System.out.println("Msg " + nCode); + + return User32.INSTANCE.CallNextHookEx(hHook, nCode, wParam, lParam); + } + }; + + hHook = User32.INSTANCE.SetWindowsHookEx(WH_CALLWNDPROC, lpfn, hMod, threadId); + if (hHook == null) + return; + + MSG msg = new MSG(); + try { + + while (!quit) { + User32.INSTANCE.PeekMessage(msg, null, 0, 0, 1); + if (msg.message == User32.WM_HOTKEY){ // && msg.wParam.intValue() == 1 + msg = new MSG(); //must clear msg so it doesn't repeat + } + Thread.sleep(10); + } + } catch (Exception e) { + e.printStackTrace(); + } + System.out.println("message loop stopped"); + unhook(); + } + + public void unhook() { + if (hHook == null) + return; + if (!User32.INSTANCE.UnhookWindowsHookEx(hHook)) + System.out.println("Failed to unhook"); + System.out.println("Unhooked"); + hHook = null; + } + + //stops Keyboard hook and causes the unhook command to be called + public static void stopMessageHook() { + quit = true; + } +} diff --git a/src/org/synthuse/MsgHook.java b/src/org/synthuse/MsgHook.java new file mode 100644 index 0000000..a23b374 --- /dev/null +++ b/src/org/synthuse/MsgHook.java @@ -0,0 +1,6 @@ +package org.synthuse; + +public class MsgHook { + + +} diff --git a/src/org/synthuse/SynthuseDlg.java b/src/org/synthuse/SynthuseDlg.java index 7a6adc1..c673b80 100644 --- a/src/org/synthuse/SynthuseDlg.java +++ b/src/org/synthuse/SynthuseDlg.java @@ -13,32 +13,15 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Point; +import java.awt.Rectangle; import java.awt.Toolkit; -import javax.swing.JPanel; import javax.swing.border.EmptyBorder; -import javax.swing.DefaultComboBoxModel; -import javax.swing.ImageIcon; -import javax.swing.JComponent; -import javax.swing.JFrame; -import javax.swing.JOptionPane; -import javax.swing.JToolBar; -import javax.swing.JSplitPane; -import javax.swing.JRadioButton; -import javax.swing.SwingUtilities; -import javax.swing.WindowConstants; +import javax.swing.*; import java.awt.Component; - -import javax.swing.Box; -import javax.swing.ButtonGroup; -import javax.swing.JButton; - import java.awt.Dimension; -import javax.swing.JComboBox; -import javax.swing.JScrollPane; - /* import com.jgoodies.forms.layout.FormLayout; import com.jgoodies.forms.layout.ColumnSpec; @@ -47,9 +30,6 @@ import com.jgoodies.forms.factories.FormFactory; */ import com.sun.jna.platform.win32.WinDef.HWND; -import javax.swing.JLabel; -import javax.swing.SwingConstants; - import java.awt.FlowLayout; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; @@ -60,8 +40,6 @@ import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.List; -import javax.swing.JTextPane; - import org.synthuse.Api.User32; import org.synthuse.DragTarget.dragEvents; @@ -72,7 +50,7 @@ public class SynthuseDlg extends JFrame { /** * */ - public static String VERSION_STR = "1.1.8"; + public static String VERSION_STR = "1.2.0"; public static String RES_STR_MAIN_ICON = "/org/synthuse/img/gnome-robots.png"; public static String RES_STR_REFRESH_IMG = "/org/synthuse/img/rapidsvn.png"; @@ -82,6 +60,9 @@ public class SynthuseDlg extends JFrame { public static String RES_STR_FIND_IMG = "/org/synthuse/img/edit-find-3.png"; public static String RES_STR_SETACTION_IMG = "/org/synthuse/img/document-new-5.png"; public static String RES_STR_CANCEL_IMG = "/org/synthuse/img/document-close-2.png"; + public static String RES_STR_PREFERENCES_IMG = "/org/synthuse/img/preferences-desktop.png"; + + private static final int STRUT_WIDTH = 10; public static List actionListQueue = new ArrayList(); private static final long serialVersionUID = 1L; @@ -99,8 +80,10 @@ public class SynthuseDlg extends JFrame { private String lastRuntimeId =""; private JComboBox cmbXpath; private JButton btnTestIde; + private JButton btnAdvanced; private TestIdeFrame testIde = null; + private MessageHookFrame msgHook = null; private int targetX; private int targetY; private UiaBridge uiabridge = new UiaBridge(); @@ -141,7 +124,7 @@ public class SynthuseDlg extends JFrame { rdbtnWindows.setSelected(true); toolBar.add(rdbtnWindows); - Component horizontalStrut = Box.createHorizontalStrut(20); + Component horizontalStrut = Box.createHorizontalStrut(STRUT_WIDTH); toolBar.add(horizontalStrut); JRadioButton rdbtnUrl = new JRadioButton("Url: "); @@ -158,7 +141,7 @@ public class SynthuseDlg extends JFrame { cmbUrl.setEditable(true); toolBar.add(cmbUrl); - Component horizontalStrut_1 = Box.createHorizontalStrut(20); + Component horizontalStrut_1 = Box.createHorizontalStrut(STRUT_WIDTH); toolBar.add(horizontalStrut_1); btnRefresh = new JButton(" Refresh "); @@ -172,7 +155,7 @@ public class SynthuseDlg extends JFrame { btnRefresh.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_REFRESH_IMG))); toolBar.add(btnRefresh); - Component horizontalStrut_3 = Box.createHorizontalStrut(20); + Component horizontalStrut_3 = Box.createHorizontalStrut(STRUT_WIDTH); toolBar.add(horizontalStrut_3); btnTestIde = new JButton("Test IDE"); @@ -192,8 +175,40 @@ public class SynthuseDlg extends JFrame { btnTestIde.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_TESTIDE_IMG))); toolBar.add(btnTestIde); - Component horizontalStrut_2 = Box.createHorizontalStrut(20); + Component horizontalStrut_2 = Box.createHorizontalStrut(STRUT_WIDTH); toolBar.add(horizontalStrut_2); + + btnAdvanced = new JButton("Advanced"); + btnAdvanced.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_PREFERENCES_IMG))); + btnAdvanced.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JPopupMenu menu = new JPopupMenu(); + ActionListener menuListener = new ActionListener() { + public void actionPerformed(ActionEvent event) { + //System.out.println("Popup menu item [" + event.getActionCommand() + "] was pressed."); + if (event.getActionCommand() == "Message Hook"){ + if (msgHook == null) + msgHook = new MessageHookFrame(); + msgHook.setVisible(true); + } + } + }; + JMenuItem mnMessageHook = new JMenuItem("Message Hook"); + mnMessageHook.addActionListener(menuListener); + menu.add(mnMessageHook); + JMenuItem mnSettings = new JMenuItem("Settings"); + mnSettings.setEnabled(false); + mnSettings.addActionListener(menuListener); + menu.add(mnSettings); + + Component c = (Component) e.getSource(); + menu.show(c, -1, c.getHeight()); + } + }); + toolBar.add(btnAdvanced); + + Component horizontalStrut_4 = Box.createHorizontalStrut(STRUT_WIDTH); + toolBar.add(horizontalStrut_4); JButton helpBtn = new JButton("Help"); helpBtn.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_HELP_IMG))); @@ -480,9 +495,12 @@ public class SynthuseDlg extends JFrame { String parentStr = Api.GetHandleAsString(User32.instance.GetParent(hwnd)); String enumProperties = ""; if (!SynthuseDlg.config.isUiaBridgeDisabled()) - enumProperties = uiabridge.getWindowInfo(targetX, targetY, WindowInfo.UIA_PROPERTY_LIST); + enumProperties = uiabridge.getWindowInfo(targetX, targetY, WindowInfo.UIA_PROPERTY_LIST_ADV); String runtimeId = WindowInfo.getRuntimeIdFromProperties(enumProperties); - lblStatus.setText("rid:" + runtimeId + " class: " + classStr + " hWnd: " + handleStr + " parent: " + parentStr + " X,Y: " + targetX + ", " + targetY); + String framework = WindowInfo.getFrameworkFromProperties(enumProperties); + Rectangle rect = UiaBridge.getBoundaryRect(enumProperties); + Point offsetPoint = WindowInfo.findOffset(rect, targetX, targetY); + lblStatus.setText("rid:" + runtimeId + " " + framework + " class: " + classStr + " hWnd: " + handleStr + " parent: " + parentStr + " X,Y (" + targetX + ", " + targetY + ") offset: " + offsetPoint.x + ", " + offsetPoint.y); if (!lastDragHwnd.equals(handleStr) || !lastRuntimeId.equals(runtimeId)) { if (!lastDragHwnd.isEmpty()) { Api.refreshWindow(Api.GetHandleFromString(lastDragHwnd)); @@ -490,7 +508,12 @@ public class SynthuseDlg extends JFrame { lastDragHwnd = handleStr; lastRuntimeId = runtimeId; //lastDragHwnd = (hwnd + ""); - Api.highlightWindow(hwnd); + if (framework.equals(UiaBridge.FRAMEWORK_ID_WPF) || framework.equals(UiaBridge.FRAMEWORK_ID_SILVER)) + {// WPF and Silverlight apps don't expose their child windows boundaries the same as win32 apps + Api.highlightWindow(Api.User32.instance.GetDesktopWindow(), rect.x, rect.y, rect.x + rect.width, rect.y + rect.height); + } + else + Api.highlightWindow(hwnd); XpathManager.buildXpathStatementThreaded(hwnd, enumProperties, textPane, xpathEvents); } } diff --git a/src/org/synthuse/UiaBridge.java b/src/org/synthuse/UiaBridge.java index 8880dab..e049dcc 100644 --- a/src/org/synthuse/UiaBridge.java +++ b/src/org/synthuse/UiaBridge.java @@ -1,6 +1,7 @@ package org.synthuse; import java.awt.Point; +import java.awt.Rectangle; import java.io.*; import javax.swing.JOptionPane; @@ -8,7 +9,10 @@ import javax.swing.JOptionPane; public class UiaBridge { public static String CACHED_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty,BoundingRectangleProperty"; - + public static final String FRAMEWORK_ID_WPF = "WPF"; + public static final String FRAMEWORK_ID_SILVER = "Silverlight"; + public static final String FRAMEWORK_ID_WINFORM = "WinForm"; + public static final String FRAMEWORK_ID_WIN = "Win32"; static { @@ -128,18 +132,41 @@ public class UiaBridge { public native String[] getProperties(String runtimeIdValue); public native String[] getPropertiesAndValues(String runtimeIdValue); */ + + public static String replaceEscapedCodes(String input) { + //, is a comma , + String result = input; + result = result.replaceAll(",", ","); + result = result.replaceAll("<", "<"); + result = result.replaceAll(">", ">"); + result = result.replaceAll("'", "'"); + result = result.replaceAll(""", "\""); + result = result.replaceAll("&", "&"); + return result; + } + public Point getCenterOfElement(String runtimeIdValue) { Point p = new Point(); - String boundary = getWindowInfo(runtimeIdValue, "BoundingRectangleProperty"); - boundary = WindowInfo.replaceEscapedCodes(boundary); - //System.out.println("runtimeId: " + runtimeIdValue + ", boundary: " + boundary); //boundary: 841,264,125,29 - String[] boundarySplt = boundary.split(","); - int x = Integer.parseInt(boundarySplt[0]); - int y = Integer.parseInt(boundarySplt[1]); - int width = Integer.parseInt(boundarySplt[2]); - int height = Integer.parseInt(boundarySplt[3]); - p.x = ((width) /2) + x; - p.y = ((height) /2) + y; + String boundaryProperty = getWindowInfo(runtimeIdValue, "BoundingRectangleProperty"); + Rectangle rect = getBoundaryRect(boundaryProperty); + p.x = ((rect.width) /2) + rect.x; + p.y = ((rect.height) /2) + rect.y; return p; } + + //BoundingRectangleProperty is the last property listed in comma separated properties string + public static Rectangle getBoundaryRect(String properties) { + Rectangle rect = new Rectangle(); + String[] propSplt = properties.split(","); + if (propSplt.length > 0) + { + String[] boundarySplt = replaceEscapedCodes(propSplt[propSplt.length - 1]).split(","); + if (boundarySplt.length == 4 ) + rect.x = Integer.parseInt(boundarySplt[0]); + rect.y = Integer.parseInt(boundarySplt[1]); + rect.width = Integer.parseInt(boundarySplt[2]); + rect.height = Integer.parseInt(boundarySplt[3]); + } + return rect; + } } diff --git a/src/org/synthuse/WinPtr.java b/src/org/synthuse/WinPtr.java index 75ac542..5aaeccc 100644 --- a/src/org/synthuse/WinPtr.java +++ b/src/org/synthuse/WinPtr.java @@ -46,6 +46,14 @@ public class WinPtr { return (runtimeIdTest.contains("-")); } + public void convertToNativeHwnd() + { + if (isWpfRuntimeIdFormat(runtimeId)){ + hWndStr = runtimeId.split("-")[1]; + hWnd = Api.GetHandleFromString(hWndStr); + } + } + public String toString() { if (isWin32() && !hWndStr.equals("")) return hWndStr; diff --git a/src/org/synthuse/WindowInfo.java b/src/org/synthuse/WindowInfo.java index 5076a63..eb39f49 100644 --- a/src/org/synthuse/WindowInfo.java +++ b/src/org/synthuse/WindowInfo.java @@ -7,6 +7,8 @@ package org.synthuse; +import java.awt.Point; +import java.awt.Rectangle; import java.util.LinkedHashMap; import java.util.Map; @@ -25,6 +27,7 @@ import com.sun.jna.ptr.PointerByReference; public class WindowInfo { public static String UIA_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty"; + public static String UIA_PROPERTY_LIST_ADV = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty,BoundingRectangleProperty"; public static String UIA_RUNTIME_ID = "RuntimeIdProperty"; public static String UIA_BOUNDING_RECT = "BoundingRectangleProperty"; public static int MAX_TEXT_SIZE = 200; @@ -46,6 +49,7 @@ public class WindowInfo { public String runtimeId = ""; public int menus = 0; public HMENU menu = null; + public boolean useUiaBridge = false; public Map extra = null; @@ -97,20 +101,6 @@ public class WindowInfo { extra = new LinkedHashMap(); extra.put("tvCount", tvCount.intValue() + ""); } - /* - if (isChild) { - int ctrlID = Api.User32.instance.GetDlgCtrlID(hWnd); - if (ctrlID > 0){ - //parent = User32.instance.GetParent(hWnd); - int dtresult = Api.User32.instance.GetDlgItemText(hWnd, ctrlID, buffer, 1024); - if (dtresult > 0) { - String dgText = Native.toString(buffer); - if (extra == null) - extra = new LinkedHashMap(); - extra.put("dgText", dgText + ""); - } - } - }*/ char[] buffer2 = new char[1026]; User32.instance.GetClassName(hWnd, buffer2, 1026); @@ -151,6 +141,9 @@ public class WindowInfo { if (isChild) { parent = User32.instance.GetParent(hWnd); parentStr = Api.GetHandleAsString(parent); + // test to see if uiaBridge should be used on this child + if (this.className.startsWith("HwndWrapper") || this.className.startsWith("MicrosoftSilverlight") || this.className.startsWith("GeckoPluginWindow")) + useUiaBridge = true; } else { @@ -160,7 +153,9 @@ public class WindowInfo { Pointer process = Kernel32.instance.OpenProcess(Api.PROCESS_QUERY_INFORMATION | Api.PROCESS_VM_READ, false, pointer.getValue()); Psapi.instance.GetModuleBaseNameW(process, null, buffer2, 512); processName = Native.toString(buffer2); - + //test to see if uiaBridge should be used on this parent + if (this.className.startsWith("HwndWrapper") || this.className.startsWith("WindowsForms")) + useUiaBridge = true; } this.hwnd = hWnd; hwndStr = Api.GetHandleAsString(hWnd); @@ -168,23 +163,12 @@ public class WindowInfo { this.hwndStr = ""; } - public static String replaceEscapedCodes(String input) { - //, is a comma , - String result = input; - result = result.replaceAll(",", ","); - result = result.replaceAll("<", "<"); - result = result.replaceAll(">", ">"); - result = result.replaceAll("'", "'"); - result = result.replaceAll(""", "\""); - result = result.replaceAll("&", "&"); - return result; - } - //support for WPF, Silverlight, WinForms public WindowInfo(String enumProperties, boolean isChild) { //WPF_PROPERTY_LIST = "RuntimeIdProperty,ParentRuntimeIdProperty,ProcessIdProperty,FrameworkIdProperty,LocalizedControlTypeProperty,ClassNameProperty,NameProperty,ValueProperty"; String[] spltProperties = enumProperties.split(","); this.isChild = isChild; + this.useUiaBridge = true; if (SynthuseDlg.config.isFilterUiaDisabled()) { //use wildcard mode extra = new LinkedHashMap(); for(String prop: spltProperties) { @@ -233,13 +217,13 @@ public class WindowInfo { if (spltProperties.length > 3) this.framework = spltProperties[3]; if (spltProperties.length > 4) - this.controlType = replaceEscapedCodes(spltProperties[4]); + this.controlType = UiaBridge.replaceEscapedCodes(spltProperties[4]); if (spltProperties.length > 5) - this.className = replaceEscapedCodes(spltProperties[5]); + this.className = UiaBridge.replaceEscapedCodes(spltProperties[5]); if (spltProperties.length > 6) - this.text = replaceEscapedCodes(spltProperties[6]); + this.text = UiaBridge.replaceEscapedCodes(spltProperties[6]); if (spltProperties.length > 7) - this.value = replaceEscapedCodes(spltProperties[7]); + this.value = UiaBridge.replaceEscapedCodes(spltProperties[7]); if (this.className == "") this.className = this.controlType; if (text != null) @@ -266,6 +250,7 @@ public class WindowInfo { */ } + public static String getRuntimeIdFromProperties(String enumProperties) { String[] spltProperties = enumProperties.split(","); @@ -274,6 +259,26 @@ public class WindowInfo { return ""; } + public static String getFrameworkFromProperties(String enumProperties) + { + String[] spltProperties = enumProperties.split(","); + if (spltProperties.length > 3) + return spltProperties[3]; + return ""; + } + + public static Point findOffset(Rectangle rect, int xPos, int yPos) + { + Point offset = new Point(); + int x = ((rect.width) /2) + rect.x; + int y = ((rect.height) /2) + rect.y; + + offset.x = xPos - x; + offset.y = yPos - y; + + return offset; + } + public String toString() { return String.format("%s \"%s\" [%s] (%s) {%s}", framework, text, className, controlType, hwndStr); } diff --git a/src/org/synthuse/WindowsEnumeratedXml.java b/src/org/synthuse/WindowsEnumeratedXml.java index 858f6d3..a9d92e3 100644 --- a/src/org/synthuse/WindowsEnumeratedXml.java +++ b/src/org/synthuse/WindowsEnumeratedXml.java @@ -79,62 +79,62 @@ public class WindowsEnumeratedXml implements Runnable{ public static String getXml() { final Map infoList = new LinkedHashMap(); - final List wpfParentList = new ArrayList();//HwndWrapper - final List silverlightParentList = new ArrayList();//MicrosoftSilverlight - final List winFormParentList = new ArrayList();//class="WindowsForms*" - //wpf.setTouchableOnly(false); - //wpf.countChildrenWindows();//fix for missing cached elements - - - class ChildWindowCallback implements WinUser.WNDENUMPROC { - @Override - public boolean callback(HWND hWnd, Pointer lParam) { - WindowInfo wi = new WindowInfo(hWnd, true); - infoList.put(wi.hwndStr, wi); - if (wi.className.startsWith("HwndWrapper")) - wpfParentList.add(wi.hwndStr); - if (wi.className.startsWith("MicrosoftSilverlight") || wi.className.startsWith("GeckoPluginWindow")) - silverlightParentList.add(wi.hwndStr); - return true; - } - } + HWND desktopRootHwnd = Api.User32.instance.GetDesktopWindow(); + WindowInfo wi = new WindowInfo(desktopRootHwnd, false); + wi.controlType = "DesktopRoot"; + infoList.put(wi.hwndStr, wi); class ParentWindowCallback implements WinUser.WNDENUMPROC { @Override public boolean callback(HWND hWnd, Pointer lParam) { WindowInfo wi = new WindowInfo(hWnd, false); infoList.put(wi.hwndStr, wi); - if (wi.className.startsWith("HwndWrapper")) - wpfParentList.add(wi.hwndStr); - if (wi.className.startsWith("WindowsForms")) - winFormParentList.add(wi.hwndStr); - Api.User32.instance.EnumChildWindows(hWnd, new ChildWindowCallback(), new Pointer(0)); + infoList.putAll(EnumerateWin32ChildWindows(hWnd)); return true; } - } + } Api.User32.instance.EnumWindows(new ParentWindowCallback(), 0); + //process all windows that have been flagged for uiaBridge (useUiaBridge == true) + appendUiaBridgeWindows(infoList); + + return generateWindowsXml(infoList, "EnumeratedWindows"); + } + + public static void appendUiaBridgeWindows(Map infoList) + { //Enumerate WPF, WinForm, Silverlight windows and add to list if (!SynthuseDlg.config.isUiaBridgeDisabled()) { UiaBridge uiabridge = new UiaBridge(); - for (String handle : wpfParentList) { - Map wpfInfoList = EnumerateWindowsWithUiaBridge(uiabridge, handle, "*"); - infoList.putAll(wpfInfoList); - } - for (String handle : winFormParentList) { - //System.out.println("winform parent " + handle); - Map winFormInfoList = EnumerateWindowsWithUiaBridge(uiabridge, handle, "*"); - infoList.putAll(winFormInfoList); - } - for (String handle : silverlightParentList) { - Map slInfoList = EnumerateWindowsWithUiaBridge(uiabridge, handle, "Silverlight"); - infoList.putAll(slInfoList); - } - + Map uiaInfoList = new LinkedHashMap(); + for (String handle : infoList.keySet()) { + if (infoList.get(handle).useUiaBridge) { + uiaInfoList.putAll(EnumerateWindowsWithUiaBridge(uiabridge, handle, "*")); + } + } + infoList.putAll(uiaInfoList); } - return generateWindowsXml(infoList, "EnumeratedWindows"); + //return infoList; + } + + public static Map EnumerateWin32ChildWindows(HWND parentHwnd) + { + final Map infoList = new LinkedHashMap(); + + class ChildWindowCallback implements WinUser.WNDENUMPROC { + @Override + public boolean callback(HWND hWnd, Pointer lParam) { + WindowInfo wi = new WindowInfo(hWnd, true); + infoList.put(wi.hwndStr, wi); + return true; + } + } + + Api.User32.instance.EnumChildWindows(parentHwnd, new ChildWindowCallback(), new Pointer(0)); + + return infoList; } public static String generateWindowsXml(Map infoList, String rootElementName) @@ -163,17 +163,17 @@ public class WindowsEnumeratedXml implements Runnable{ Element win = null; if (w.framework.equals("win32")) win = doc.createElement("win"); - else if (w.framework.equals("WPF")) + else if (w.framework.equals(UiaBridge.FRAMEWORK_ID_WPF)) { win = doc.createElement("wpf"); ++wpfCount; } - else if (w.framework.equals("WinForm")) + else if (w.framework.equals(UiaBridge.FRAMEWORK_ID_WINFORM)) { win = doc.createElement("winfrm"); ++winFormCount; } - else if (w.framework.equals("Silverlight")) + else if (w.framework.equals(UiaBridge.FRAMEWORK_ID_SILVER)) { win = doc.createElement("silver"); ++silverlightCount; diff --git a/src/org/synthuse/commands/BaseCommand.java b/src/org/synthuse/commands/BaseCommand.java index d885ff3..1d41ac9 100644 --- a/src/org/synthuse/commands/BaseCommand.java +++ b/src/org/synthuse/commands/BaseCommand.java @@ -6,11 +6,14 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.sql.Timestamp; import java.util.Date; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.synthuse.*; +import com.sun.jna.platform.win32.WinDef.HWND; + public class BaseCommand { static String WIN_XML = ""; @@ -132,7 +135,14 @@ public class BaseCommand { } else { // native target refresh - + infoList = new LinkedHashMap(); + HWND parentHwnd = Api.GetHandleFromString(resultHwndStr); + WindowInfo wi = new WindowInfo(parentHwnd, false); + infoList.put(wi.hwndStr, wi); + infoList.putAll(WindowsEnumeratedXml.EnumerateWin32ChildWindows(parentHwnd)); + //WindowsEnumeratedXml.appendUiaBridgeWindows(infoList); //if we need this we should specify a runtimeID handle instead + newXml = WindowsEnumeratedXml.generateWindowsXml(infoList, "updates"); + System.out.println("newNativeXml: " + newXml); } int pos = WIN_XML.indexOf(resultStr); diff --git a/src/org/synthuse/commands/MouseCommands.java b/src/org/synthuse/commands/MouseCommands.java index a7dcfc6..dd1e50a 100644 --- a/src/org/synthuse/commands/MouseCommands.java +++ b/src/org/synthuse/commands/MouseCommands.java @@ -18,9 +18,9 @@ public class MouseCommands extends BaseCommand { if (handle.isEmpty()) return false; String wtype = getWindowTypeWithXpath(args[0]); - //System.out.println("wtype: " + wtype + " hwnd " + handle.hWnd + " hmenu " + handle.hmenuStr + " pos " + handle.hmenuPos); + System.out.println("wtype: " + wtype + " hwnd " + handle.hWnd + " hmenu " + handle.hmenuStr + " pos " + handle.hmenuPos); Point p = getCenterWindowPosition(handle, wtype); - //System.out.println("cmdClick: " + p.x + "," + p.y); + System.out.println("cmdClick: " + p.x + "," + p.y); RobotMacro.mouseMove(p.x + parentProcessor.targetOffset.x, p.y + parentProcessor.targetOffset.y); RobotMacro.leftClickMouse(); return true; diff --git a/src/org/synthuse/commands/WindowsCommands.java b/src/org/synthuse/commands/WindowsCommands.java index 7180508..bc85be8 100644 --- a/src/org/synthuse/commands/WindowsCommands.java +++ b/src/org/synthuse/commands/WindowsCommands.java @@ -17,6 +17,7 @@ public class WindowsCommands extends BaseCommand { WinPtr handle = findHandleWithXpath(args[0]); if (handle.isEmpty()) return false; + handle.convertToNativeHwnd(); api.activateWindow(handle.hWnd); //api.showWindow(handle); return true; @@ -28,6 +29,7 @@ public class WindowsCommands extends BaseCommand { WinPtr handle = findHandleWithXpath(args[0]); if (handle.isEmpty()) return false; + handle.convertToNativeHwnd(); api.minimizeWindow(handle.hWnd); return true; } @@ -38,6 +40,7 @@ public class WindowsCommands extends BaseCommand { WinPtr handle = findHandleWithXpath(args[0]); if (handle.isEmpty()) return false; + handle.convertToNativeHwnd(); api.maximizeWindow(handle.hWnd); return true; } @@ -48,6 +51,7 @@ public class WindowsCommands extends BaseCommand { WinPtr handle = findHandleWithXpath(args[0]); if (handle.isEmpty()) return false; + handle.convertToNativeHwnd(); api.restoreWindow(handle.hWnd); return true; } @@ -58,6 +62,7 @@ public class WindowsCommands extends BaseCommand { WinPtr handle = findHandleWithXpath(args[0]); if (handle.isEmpty()) return false; + handle.convertToNativeHwnd(); api.hideWindow(handle.hWnd); return true; } @@ -68,6 +73,7 @@ public class WindowsCommands extends BaseCommand { WinPtr handle = findHandleWithXpath(args[0]); if (handle.isEmpty()) return false; + handle.convertToNativeHwnd(); api.showWindow(handle.hWnd); return true; } @@ -78,6 +84,7 @@ public class WindowsCommands extends BaseCommand { WinPtr handle = findHandleWithXpath(args[0]); if (handle.isEmpty()) return false; + handle.convertToNativeHwnd(); api.switchToThisWindow(handle.hWnd, true); return true; } @@ -89,6 +96,7 @@ public class WindowsCommands extends BaseCommand { WinPtr handle = findHandleWithXpath(args[0]); if (handle.isEmpty()) return false; + handle.convertToNativeHwnd(); api.closeWindow(handle.hWnd); return true; } @@ -99,6 +107,7 @@ public class WindowsCommands extends BaseCommand { WinPtr handle = findHandleWithXpath(args[0]); if (handle.isEmpty()) return false; + handle.convertToNativeHwnd(); api.sendWmSetText(handle.hWnd, args[1]); return true; } @@ -109,6 +118,7 @@ public class WindowsCommands extends BaseCommand { WinPtr handle = findHandleWithXpath(args[0]); if (handle.isEmpty()) return ""; + handle.convertToNativeHwnd(); return api.sendWmGetText(handle.hWnd); } @@ -119,6 +129,7 @@ public class WindowsCommands extends BaseCommand { if (handle.isEmpty()) return false; int id = findMenuIdWithXpath(args[0]); + handle.convertToNativeHwnd(); //LRESULT result = //System.out.println("PostMessage to " + handle.hWndStr + " for id " + id); api.user32.PostMessage(handle.hWnd, Api.WM_COMMAND, new WPARAM(id), new LPARAM(0)); @@ -133,6 +144,7 @@ public class WindowsCommands extends BaseCommand { if (handle.isEmpty()) return false; int id = Integer.parseInt(args[1]); //context menu id is supplied as second argument + handle.convertToNativeHwnd(); //LRESULT result = System.out.println("PostMessage to " + handle.toString() + " for id " + id + " - " + Api.MAKELONG(id, 0)); //api.user32.PostMessage(handle.hWnd, Api.WM_COMMAND, new WPARAM(id), new LPARAM(0)); diff --git a/src/org/synthuse/img/preferences-desktop.png b/src/org/synthuse/img/preferences-desktop.png new file mode 100644 index 0000000..8fe2675 Binary files /dev/null and b/src/org/synthuse/img/preferences-desktop.png differ