diff --git a/.gitignore b/.gitignore
index 4f40838..2f4e377 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,4 @@ native/uiabridge/release
native/uiabridge/Debug
!native/uiabridge/bin
!native/MsgHook/bin
-!native/MsgHookTest/bin
+!native/SetMsgHook/bin
diff --git a/native/MsgHook.sln b/native/MsgHook.sln
new file mode 100644
index 0000000..a18befb
--- /dev/null
+++ b/native/MsgHook.sln
@@ -0,0 +1,35 @@
+
+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}") = "SetMsgHook", "SetMsgHook\SetMsgHook.vcxproj", "{34A73B55-8A93-4FB5-83CE-7759C1D23348}"
+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
+ {34A73B55-8A93-4FB5-83CE-7759C1D23348}.Debug|Win32.ActiveCfg = Debug|Win32
+ {34A73B55-8A93-4FB5-83CE-7759C1D23348}.Debug|Win32.Build.0 = Debug|Win32
+ {34A73B55-8A93-4FB5-83CE-7759C1D23348}.Debug|x64.ActiveCfg = Debug|Win32
+ {34A73B55-8A93-4FB5-83CE-7759C1D23348}.Release|Win32.ActiveCfg = Release|Win32
+ {34A73B55-8A93-4FB5-83CE-7759C1D23348}.Release|Win32.Build.0 = Release|Win32
+ {34A73B55-8A93-4FB5-83CE-7759C1D23348}.Release|x64.ActiveCfg = Release|Win32
+ {34A73B55-8A93-4FB5-83CE-7759C1D23348}.Release|x64.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/native/MsgHook/MsgHook.cpp b/native/MsgHook/MsgHook.cpp
index 20149a7..f383607 100644
--- a/native/MsgHook/MsgHook.cpp
+++ b/native/MsgHook/MsgHook.cpp
@@ -8,10 +8,9 @@
// MsgHook.cpp : Defines the exported functions for the DLL application.
//
-
#include "stdafx.h"
-
+//to fix export declaration had to add .def file
LRESULT CALLBACK CwpHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
COPYDATASTRUCT CDS;
@@ -55,7 +54,11 @@ LRESULT CALLBACK CwpHookProc(int nCode, WPARAM wParam, LPARAM lParam)
}
}
- BOOL bRes = (BOOL)SendMessage(pData->g_hWnd, WM_COPYDATA, 0, (LPARAM)(VOID*)&CDS); // ask the controlling program if the hook should be passed
+ //printf("debug: sending to hwnd (%ld) msg %d, wParam %ld, lParam %ld\n", pData->g_hWnd, Event.nCode, Event.wParam, Event.lParam);
+ if (cwps->hwnd != pData->g_hWnd)
+ {
+ BOOL bRes = (BOOL)SendMessage(pData->g_hWnd, WM_COPYDATA, 0, (LPARAM)(VOID*)&CDS); // ask the controlling program if the hook should be passed
+ }
}
return CallNextHookEx(pData->g_CwpHook, nCode, wParam, lParam); // pass hook to next handler
//return bRes; // Don't tell the other hooks about this message.
@@ -70,7 +73,7 @@ LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam)
CDS.cbData = sizeof(Event);
CDS.lpData = &Event;
- //if (nCode == HC_ACTION)
+ if (nCode >=0 && nCode == HC_ACTION)
{
//For WH_GETMESSAGE hook a pointer to a MSG structure that contains details about the message.
MSG *msg = (MSG *)lParam;
@@ -84,19 +87,48 @@ LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam)
//if (msg->message == WM_SETTEXT && msg->lParam != 0)
// _tcscpy_s(Event.lParamStr, 25, (const wchar_t*)Event.lParam);
//if (msg->message == WM_COMMAND || msg->message == WM_MENUCOMMAND) //infinite loop?
- BOOL bRes = (BOOL)SendMessage(pData->g_hWnd, WM_COPYDATA, 0, (LPARAM)(VOID*)&CDS); // ask the controlling program if the hook should be passed
+ if (msg->hwnd != pData->g_hWnd)
+ {
+ BOOL bRes = (BOOL)SendMessage(pData->g_hWnd, WM_COPYDATA, 0, (LPARAM)(VOID*)&CDS); // ask the controlling program if the hook should be passed
+ }
}
return CallNextHookEx(pData->g_MsgHook, nCode, wParam, lParam); // pass hook to next handler
//return bRes; // Don't tell the other hooks about this message.
}
+//support for 32-bit/64-bit apps means the dll might be different to match the process we want to see
+extern "C" __declspec(dllexport) BOOL SetCustomMsgHookDll(const TCHAR * hookDll, const char * hookDllProcName)
+{
+ HMODULE dll = LoadLibrary(hookDll); //should provide full dll path and filename
+ if (dll == NULL)
+ {
+ TCHAR errorStr[200];
+ _stprintf_s(errorStr, _T("Error loading hook library %s"), hookDll);
+ MessageBox(0, errorStr, _T("Set Hook Dll Error"), 0);
+ return false;
+ }
+ HOOKPROC addr = (HOOKPROC)GetProcAddress(dll, hookDllProcName); //should provide the 'CwpHookProc'
+ if (addr == NULL)
+ {
+ char errorStr[200];
+ sprintf_s(errorStr, "Error loading hook library procedure %s", hookDllProcName);
+ MessageBoxA(0, errorStr, "Set Hook Dll Error", 0);
+ return false;
+ }
+ pData->g_hInstance = dll;
+ pData->g_CwpHookProc = addr;
+ return true;
+}
+
extern "C" __declspec(dllexport) BOOL SetMsgHook(HWND callerHWnd, DWORD threadId)
{
- if(bStartingProcess) // if we're just starting the DLL for the first time,
+// 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_CwpHook = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)CwpHookProc, (HINSTANCE)pData->g_hInstance, threadId);
+ if (pData->g_CwpHookProc == NULL)
+ pData->g_CwpHookProc = (HOOKPROC)CwpHookProc;
+ pData->g_CwpHook = SetWindowsHookEx(WH_CALLWNDPROC, pData->g_CwpHookProc, (HINSTANCE)pData->g_hInstance, threadId);
//pData->g_MsgHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)MsgHookProc, (HINSTANCE)pData->g_hInstance, threadId);
if (pData->g_CwpHook == NULL) {
TCHAR tmp[100];
@@ -106,11 +138,21 @@ extern "C" __declspec(dllexport) BOOL SetMsgHook(HWND callerHWnd, DWORD threadId
return (pData->g_CwpHook != NULL); //pData->g_CwpHook != NULL &&
}
- else
+ /*else
{
//MessageBox(0, _T("Error: Not starting process"), _T("Set Hook Error"), 0);
return false;
- }
+ }*/
+}
+
+extern "C" __declspec(dllexport) HHOOK GetCurrentHookHandle()
+{
+ return pData->g_CwpHook; //if NULL hook isn't running
+}
+
+extern "C" __declspec(dllexport) void SetGlobalDLLInstance(HANDLE dllInstance)
+{
+ pData->g_hInstance = dllInstance;
}
extern "C" __declspec(dllexport) BOOL RemoveHook()
@@ -127,7 +169,93 @@ extern "C" __declspec(dllexport) BOOL RemoveHook()
BOOL ret = UnhookWindowsHookEx(pData->g_CwpHook);
pData->g_hWnd = NULL; // reset data
pData->g_CwpHook = NULL;
+ pData->g_CwpHookProc = NULL;
return ret;
}
return false;
+}
+
+
+//testing if process 64 bit, needed to verify this dll can hook & attach to target process
+typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
+LPFN_ISWOW64PROCESS fnIsWow64Process;
+
+extern "C" __declspec(dllexport) BOOL IsCurrentProcess64Bit()
+{
+ return IsProcess64Bit(_getpid());
+}
+
+extern "C" __declspec(dllexport) BOOL IsProcess64Bit(DWORD procId)
+{
+ SYSTEM_INFO stInfo;
+ GetNativeSystemInfo(&stInfo); // if native system is x86 skip wow64 test
+ if (stInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
+ return false; //printf( "Processor Architecture: Intel x86\n");
+
+ BOOL bIsWow64 = FALSE;
+ //IsWow64Process is not available on all supported versions of Windows.
+ //Use GetModuleHandle to get a handle to the DLL that contains the function
+ //and GetProcAddress to get a pointer to the function if available.
+
+ fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
+ if(fnIsWow64Process != NULL)
+ {
+ HANDLE procHandle = NULL;//GetCurrentProcess();
+ procHandle = OpenProcess(PROCESS_QUERY_INFORMATION, false, procId);
+ if (!fnIsWow64Process(procHandle, &bIsWow64))
+ {
+ //handle error
+ }
+ CloseHandle(procHandle);
+ if (bIsWow64) // NOT a native 64bit process
+ return false;
+ return true;// is a native 64bit process
+ }
+ return false; //some error finding function "IsWow64Process" assume not 64-bit
+}
+
+extern "C" __declspec(dllexport) DWORD GetProcessMainThreadId(DWORD procId)
+{
+
+#ifndef MAKEULONGLONG
+ #define MAKEULONGLONG(ldw, hdw) ((ULONGLONG(hdw) << 32) | ((ldw) & 0xFFFFFFFF))
+#endif
+#ifndef MAXULONGLONG
+ #define MAXULONGLONG ((ULONGLONG)~((ULONGLONG)0))
+#endif
+
+ DWORD dwMainThreadID = 0;
+ ULONGLONG ullMinCreateTime = MAXULONGLONG;
+ //includes all threads in the system
+ HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+ if (hThreadSnap != INVALID_HANDLE_VALUE) {
+ THREADENTRY32 th32;
+ th32.dwSize = sizeof(THREADENTRY32);
+ BOOL bOK = TRUE;
+ //Enumerate all threads in the system and filter on th32OwnerProcessID = pid
+ for (bOK = Thread32First(hThreadSnap, &th32); bOK ; bOK = Thread32Next(hThreadSnap, &th32)) {
+ //if (th32.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(th32.th32OwnerProcessID)) {
+ if (th32.th32OwnerProcessID == procId && (th32.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(th32.th32OwnerProcessID))) {
+ //_tprintf(_T("DEBUG Enumerate Process (%ld) Thread Id: %ld\n"), procId, th32.th32ThreadID);
+ HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION, TRUE, th32.th32ThreadID);
+ if (hThread) {
+ FILETIME afTimes[4] = {0};
+ if (GetThreadTimes(hThread, &afTimes[0], &afTimes[1], &afTimes[2], &afTimes[3])) {
+ ULONGLONG ullTest = MAKEULONGLONG(afTimes[0].dwLowDateTime, afTimes[0].dwHighDateTime);
+ if (ullTest && ullTest < ullMinCreateTime) { //check each thread's creation time
+ ullMinCreateTime = ullTest;
+ dwMainThreadID = th32.th32ThreadID; // let it be main thread
+ }
+ }
+ CloseHandle(hThread); //must close opened thread
+ }
+ }
+ }
+#ifndef UNDER_CE
+ CloseHandle(hThreadSnap); //close thread snapshot
+#else
+ CloseToolhelp32Snapshot(hThreadSnap); //close thread snapshot
+#endif
+ }
+ return dwMainThreadID; //returns main thread id or returns 0 if can't find it
}
\ No newline at end of file
diff --git a/native/MsgHook/MsgHook.def b/native/MsgHook/MsgHook.def
new file mode 100644
index 0000000..0176c73
--- /dev/null
+++ b/native/MsgHook/MsgHook.def
@@ -0,0 +1,5 @@
+LIBRARY MsgHook
+
+EXPORTS
+ CwpHookProc @1
+ MsgHookProc @2
\ No newline at end of file
diff --git a/native/MsgHook/MsgHook.vcxproj b/native/MsgHook/MsgHook.vcxproj
index 108ce52..5f6a80f 100644
--- a/native/MsgHook/MsgHook.vcxproj
+++ b/native/MsgHook/MsgHook.vcxproj
@@ -87,6 +87,7 @@
Windows
true
+ MsgHook.def
@@ -99,6 +100,7 @@
Windows
true
+ MsgHook.def
@@ -115,6 +117,7 @@
true
true
true
+ MsgHook.def
mkdir "$(ProjectDir)bin"
@@ -135,6 +138,7 @@ copy /Y "$(TargetPath)" "$(ProjectDir)bin\MsgHook$(PlatformArchitecture)$(Target
true
true
true
+ MsgHook.def
mkdir "$(ProjectDir)bin"
@@ -142,6 +146,10 @@ copy /Y "$(TargetPath)" "$(ProjectDir)bin\MsgHook$(PlatformArchitecture)$(Target
+
+
+
+
@@ -149,6 +157,7 @@ copy /Y "$(TargetPath)" "$(ProjectDir)bin\MsgHook$(PlatformArchitecture)$(Target
+
diff --git a/native/MsgHook/MsgHook.vcxproj.filters b/native/MsgHook/MsgHook.vcxproj.filters
index 6e37813..8a2e05b 100644
--- a/native/MsgHook/MsgHook.vcxproj.filters
+++ b/native/MsgHook/MsgHook.vcxproj.filters
@@ -22,6 +22,14 @@
Resource Files
+
+ Source Files
+
+
+ Resource Files
+
+
+
@@ -39,6 +47,9 @@
Header Files
+
+ Header Files
+
diff --git a/native/MsgHook/MsgHookTest.aps b/native/MsgHook/MsgHookTest.aps
index ab709a6..0f73f84 100644
Binary files a/native/MsgHook/MsgHookTest.aps and b/native/MsgHook/MsgHookTest.aps differ
diff --git a/native/MsgHook/MsgHookTest.rc b/native/MsgHook/MsgHookTest.rc
index 8aaa3ec..5857274 100644
Binary files a/native/MsgHook/MsgHookTest.rc and b/native/MsgHook/MsgHookTest.rc differ
diff --git a/native/MsgHook/MsgHookWindow.cpp b/native/MsgHook/MsgHookWindow.cpp
index 7d975b9..58a306d 100644
--- a/native/MsgHook/MsgHookWindow.cpp
+++ b/native/MsgHook/MsgHookWindow.cpp
@@ -11,6 +11,7 @@
#include "stdafx.h"
#include "resource.h"
#include "MsgLookup.h"
+#include "ResExtract.h"
//#include "MsgHookTest.h"
//#include "MsgHook.h"
@@ -24,18 +25,25 @@ HWND mainHwnd = NULL;
HMENU mainMenu = NULL;
HWND txtbox = NULL;
HWND targetHwnd = NULL;
+DWORD targetPid = 0;
const int txtboxSpacing = 2;
+long msgCount = 0;
-bool filterWmCommand = true;
+//message filters flags
+bool filterWmCommand = false;
bool filterWmNotify = false;
bool filterCustom = false;
bool filterAbove = false;
+TCHAR dll32bitName[500] = _T("");
+TCHAR dll64bitName[500] = _T("");
+char dllProcName[500] = "CwpHookProc";
//#define MAX_TEST_SIZE 100
//TCHAR targetClassname[MAX_TEST_SIZE] = _T("Notepad");
-TCHAR targetClassname[MAX_TEST_SIZE] = _T("WordPadClass");
+TCHAR targetProcessId[MAX_TEST_SIZE] = _T("");
+TCHAR targetClassname[MAX_TEST_SIZE] = _T("");
TCHAR targetHwndStr[MAX_TEST_SIZE] = _T("");
TCHAR testWmSettextL[MAX_TEST_SIZE] = _T("This is a test");
TCHAR testWmSettextW[MAX_TEST_SIZE] = _T("0");
@@ -117,30 +125,75 @@ void InitMsgFiltersAndLookup()
void StartMessageHook()
{
AppendText(txtbox, _T("Starting Message Hook\r\n"));
- targetHwnd = FindWindow(targetClassname, NULL);
-
- if (_tcscmp(targetHwndStr, _T("")) != 0) //if target HWND was used then override classname hwnd
+ //targetHwnd = FindWindow(targetClassname, NULL);
+
+ TCHAR tmp[500];
+
+ DWORD tid = 0;
+ if (_tcscmp(targetHwndStr, _T("")) != 0) //if target HWND was used
{
TCHAR *stopStr;
targetHwnd = (HWND)_tcstol(targetHwndStr, &stopStr, 10);
+ tid = GetWindowThreadProcessId(targetHwnd, NULL);
+ _stprintf_s(tmp, _T("Target Handle: %ld, and Thread Id: %ld\r\n"), targetHwnd, tid);
}
- DWORD tid = GetWindowThreadProcessId(targetHwnd, NULL);
-
+ targetPid = 0;
+ if (_tcscmp(targetProcessId, _T("")) != 0) //if target pid was used
+ {
+ TCHAR *stopStr;
+ targetPid = (DWORD)_tcstol(targetProcessId, &stopStr, 10);
+ tid = GetProcessMainThreadId(targetPid);
+ _stprintf_s(tmp, _T("Target PId: %ld, and Thread Id: %ld\r\n"), targetPid, tid);
+ }
+
InitMsgFiltersAndLookup();
//InitializeMsgLookup();
- TCHAR tmp[50];
- _stprintf_s(tmp, _T("Target Handle: %ld, and Thread Id: %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"));
+ if (tid == 0) {
+ AppendText(txtbox, _T("Target thread not found\r\n"));
return;
}
- //if (InitMsgHook(mainHwnd, tid))
+ if (targetPid != 0) // handle various types of bit matching
+ {
+ BOOL current64bit = IsCurrentProcess64Bit();
+ if (IsProcess64Bit(targetPid) && current64bit)
+ {
+ _stprintf_s(tmp, _T("Target PId (%ld) is a matching 64 bit process\r\n"), targetPid);
+ SetCustomMsgHookDll(dll64bitName, dllProcName);
+ }
+ else if(!IsProcess64Bit(targetPid) && !current64bit)
+ {
+ _stprintf_s(tmp, _T("Target PId (%ld) is a matching 32 bit process\r\n"), targetPid);
+ SetCustomMsgHookDll(dll32bitName, dllProcName);
+ }
+ else
+ {
+ _stprintf_s(tmp, _T("Target PId (%ld) is a not matching bit process\r\n"), targetPid);
+ AppendText(txtbox, tmp);
+ TCHAR *dllname = dll32bitName;
+ TCHAR *exename = _T("SetMsgHook32.exe");
+ int setMsgHookRes = IDR_SETMH32;
+ if (IsProcess64Bit(targetPid))
+ {
+ dllname = dll64bitName;
+ exename = _T("SetMsgHook64.exe");
+ setMsgHookRes = IDR_SETMH64;
+ }
+ _stprintf_s(tmp, _T("%s %s 0 %d"), exename, dllname, targetPid);
+ RunResource(setMsgHookRes, tmp);
+ //EnableMenuItem(mainMenu, ID_FILE_STOPHOOK, MF_ENABLED);
+ //EnableMenuItem(mainMenu, ID_FILE_STARTHOOK, MF_DISABLED | MF_GRAYED);
+ _tcscat_s(tmp, 500, _T("\r\n"));
+ AppendText(txtbox, tmp);
+ return;
+ }
+ AppendText(txtbox, tmp);
+ }
if (SetMsgHook(mainHwnd, tid))
{
EnableMenuItem(mainMenu, ID_FILE_STOPHOOK, MF_ENABLED);
@@ -158,6 +211,7 @@ void StopMessageHook()
AppendText(txtbox, TEXT("Stopping Message Hook\r\n"));
//KillHook();
RemoveHook();
+ msgCount = 0;
}
bool OnCopyData(COPYDATASTRUCT* pCopyDataStruct) // WM_COPYDATA lParam will have this struct
@@ -193,10 +247,11 @@ bool OnCopyData(COPYDATASTRUCT* pCopyDataStruct) // WM_COPYDATA lParam will have
}
if (_tcscmp(msgName, _T("")) != 0)
{
+ ++msgCount;
TCHAR msgHwndClassname[20];
GetClassName(Event.hWnd, msgHwndClassname, 20);
TCHAR tmp[200];
- _stprintf_s(tmp, _T("hwnd: %ld (%s), msg: %s (%ld), wparam: '%s'[%ld], lparam: '%s'{%ld}\r\n"), Event.hWnd, msgHwndClassname, msgName, Event.nCode, Event.wParamStr, Event.wParam, Event.lParamStr,Event.lParam);
+ _stprintf_s(tmp, _T("<%07ld> hwnd: %ld (%s), msg: %s (%ld), wparam: '%s'[%ld], lparam: '%s'{%ld}\r\n"), msgCount, Event.hWnd, msgHwndClassname, msgName, Event.nCode, Event.wParamStr, Event.wParam, Event.lParamStr,Event.lParam);
AppendText(txtbox, tmp);
}
}
@@ -225,6 +280,11 @@ void SendWmCommand() //ID_TESTMSGS_WM
long wparam = _tcstol(testWmCommandW, &stopStr, 10);
long lparam = _tcstol(testWmCommandL, &stopStr, 10);
SendMessage(sendHwnd, WM_COMMAND, wparam, lparam);
+
+ /*
+ TCHAR tmp[500];
+ _stprintf_s(tmp, _T("hook handle %ld\r\n"), (long)GetCurrentHookHandle());
+ AppendText(txtbox, tmp); */
}
void HotKeyPressed(WPARAM wParam)
@@ -254,6 +314,19 @@ extern "C" __declspec(dllexport) void CreateMsgHookWindow(LPTSTR lpCmdLine)
int APIENTRY StartWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
+ // get this Dlls path, by default set both 32 and 64 bit names the same
+ if (_tcscmp(dll32bitName, _T("")) == 0 && _tcscmp(dll64bitName, _T("")) == 0)
+ {
+ HMODULE hm = NULL;
+ if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,(LPCWSTR) &StartWinMain, &hm))
+ {
+ int ret = GetLastError();
+ fprintf(stderr, "GetModuleHandle returned %d\n", ret);
+ }
+ GetModuleFileName(hm, dll32bitName, sizeof(dll32bitName));
+ GetModuleFileName(hm, dll64bitName, sizeof(dll64bitName));
+ //MessageBox(0, dll32bitname, dll64bitname, 0);
+ }
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
@@ -275,6 +348,17 @@ int APIENTRY StartWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR l
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MSGHOOKTEST));
+ if (lpCmdLine != NULL) //process command line args
+ {
+ if (_tcslen(lpCmdLine) > 0)
+ {
+ TCHAR *stopStr;
+ targetPid = (DWORD)_tcstol(lpCmdLine, &stopStr, 10);
+ _stprintf_s(targetProcessId, _T("%ld"), (long)targetPid);
+ StartMessageHook();
+ }
+ }
+
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
@@ -315,7 +399,7 @@ ATOM MyRegisterClass(HINSTANCE hInstance)
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
- wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MSGHOOKTEST));
+ wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MSGHOOKICO));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_MSGHOOKTEST);
@@ -419,6 +503,29 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case ID_TESTMSGS_WMCOM:
SendWmCommand();
break;
+ case ID_PROC64TEST:
+ if (_tcscmp(targetProcessId, _T("")) != 0) //if target pid was used
+ {
+ TCHAR tmp[500];
+ TCHAR *stopStr;
+ targetPid = (DWORD)_tcstol(targetProcessId, &stopStr, 10);
+ BOOL current64bit = IsCurrentProcess64Bit();
+ if (IsProcess64Bit(targetPid) && current64bit)
+ _stprintf_s(tmp, _T("Target pid (%ld) is a matching 64 bit process\r\n"), targetPid);
+ else if(!IsProcess64Bit(targetPid) && !current64bit)
+ _stprintf_s(tmp, _T("Target pid (%ld) is a matching 32 bit process\r\n"), targetPid);
+ else if (IsProcess64Bit(targetPid))
+ _stprintf_s(tmp, _T("Target pid (%ld) is 64 bit process\r\n"), targetPid);
+ else
+ _stprintf_s(tmp, _T("Target pid (%ld) is 32 bit process\r\n"), targetPid);
+ AppendText(txtbox, tmp);
+ //ExtractResource(IDR_SETMH32, _T("SetMsgHook32.exe"));
+ //_stprintf_s(tmp, _T(" %s %ld %d"), dll32bitName, (long)mainHwnd, targetPid);
+ //RunResource(IDR_SETMH32, tmp);
+
+ //MessageBox(0, , _T("64 bit Test"), 0);
+ }
+ break;
case ID_FILE_SETTINGS:
DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, DlgProc);
break;
@@ -468,7 +575,8 @@ INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
case WM_INITDIALOG:
{
//IDC_EDIT1
- SendDlgItemMessage(hDlg, IDC_EDIT1, WM_SETTEXT, 0 , (LPARAM)targetClassname);
+ //SendDlgItemMessage(hDlg, IDC_EDIT1, WM_SETTEXT, 0 , (LPARAM)targetClassname);
+ SendDlgItemMessage(hDlg, IDC_TARGETPID, WM_SETTEXT, 0 , (LPARAM)targetProcessId);
if (filterWmCommand)
SendDlgItemMessage(hDlg, IDC_CHECK_CMD, BM_SETCHECK, BST_CHECKED, 0);
if (filterWmNotify)
@@ -489,7 +597,8 @@ INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
case WM_COMMAND:
if (LOWORD(wParam) == IDOK) //only save on OK
{
- GetDlgItemText(hDlg, IDC_EDIT1, targetClassname, 100);
+ //GetDlgItemText(hDlg, IDC_EDIT1, targetClassname, MAX_TEST_SIZE);
+ GetDlgItemText(hDlg, IDC_TARGETPID, targetProcessId, MAX_TEST_SIZE);
GetDlgItemText(hDlg, IDC_WMCOMW, testWmCommandW, MAX_TEST_SIZE);
GetDlgItemText(hDlg, IDC_WMCOML, testWmCommandL, MAX_TEST_SIZE);
GetDlgItemText(hDlg, IDC_WMSETW, testWmSettextW, MAX_TEST_SIZE);
diff --git a/native/MsgHook/ResExtract.h b/native/MsgHook/ResExtract.h
new file mode 100644
index 0000000..e7662ce
--- /dev/null
+++ b/native/MsgHook/ResExtract.h
@@ -0,0 +1,86 @@
+//This function will extract a binary resource.
+//
+//IDR_SETMH64 BINARY MOVEABLE PURE "..\\SetMsgHook\\bin\\SetMsgHook64.exe"
+//IDR_SETMH32 BINARY MOVEABLE PURE "..\\SetMsgHook\\bin\\SetMsgHook32.exe"
+
+#include "stdafx.h"
+
+void ExtractResource(const WORD nID, LPCTSTR szFilename)
+{
+ const HINSTANCE hInstance = (HINSTANCE)pData->g_hInstance;//GetModuleHandle(NULL);
+ HRSRC hResource = FindResource(hInstance, MAKEINTRESOURCE(nID), _T("BINARY"));// _ASSERTE(hResource);
+ if (hResource == NULL) // no resource found.
+ {
+ //MessageBoxA(0, "error, no resource found", "error", 0);
+ printf("error, resource %d not found\n", nID);
+ return;
+ }
+ HGLOBAL hFileResource = LoadResource(hInstance, hResource);// _ASSERTE(hFileResource);
+ LPVOID lpFile = LockResource(hFileResource);
+
+ DWORD dwSize = SizeofResource(hInstance, hResource);
+
+ // Open the file and filemap
+ HANDLE hFile = CreateFile(szFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ HANDLE hFilemap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, dwSize, NULL);
+
+ // Get a pointer to write to
+ LPVOID lpBaseAddress = MapViewOfFile(hFilemap, FILE_MAP_WRITE, 0, 0, 0);
+
+ // Write the file
+ CopyMemory(lpBaseAddress, lpFile, dwSize);
+
+ // Unmap the file and close the handles
+ UnmapViewOfFile(lpBaseAddress);
+ CloseHandle(hFilemap);
+ CloseHandle(hFile);
+
+}
+
+void RunResource(const WORD nID, LPWSTR params)
+{
+ TCHAR tmpFilename[500];
+ TCHAR tmpPath[500];
+ GetTempPath(500, tmpPath);
+ if (GetTempFileName(tmpPath, _T(""), 0, tmpFilename) == 0)
+ {
+ MessageBox(0,_T("Error getting temp file name"), _T("Error"), 0);
+ return;
+ }
+
+ ExtractResource(nID, tmpFilename);
+ //MessageBox(0, tmpFilename, _T("tmp file2"), 0);
+
+ STARTUPINFO si;
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+
+ PROCESS_INFORMATION pi;
+ ZeroMemory( &pi, sizeof(pi) );
+
+ si.wShowWindow = SW_MINIMIZE;
+
+ // Start the child process.
+ if(!CreateProcess(tmpFilename, // No module name (use command line)
+ params, // Command line
+ NULL, // Process handle not inheritable
+ NULL, // Thread handle not inheritable
+ FALSE, // Set handle inheritance to FALSE
+ 0, // No creation flags
+ NULL, // Use parent's environment block
+ NULL, // Use parent's starting directory
+ &si, // Pointer to STARTUPINFO structure
+ &pi )) // Pointer to PROCESS_INFORMATION structure
+ {
+ MessageBox(0, _T("CreateProcess failed"), _T("error"), 0);
+ printf( "CreateProcess failed (%d).\n", GetLastError() );
+ return;
+ }
+ //MessageBox(0, tmpFilename, _T("tmp file3"), 0);
+
+ // Wait until child process exits.
+ //WaitForSingleObject( pi.hProcess, INFINITE );
+ // Close process and thread handles.
+ //CloseHandle( pi.hProcess );
+ //CloseHandle( pi.hThread );
+}
\ No newline at end of file
diff --git a/native/MsgHook/bin/MsgHook32.dll b/native/MsgHook/bin/MsgHook32.dll
index c5b0807..493932a 100644
Binary files a/native/MsgHook/bin/MsgHook32.dll and b/native/MsgHook/bin/MsgHook32.dll differ
diff --git a/native/MsgHook/bin/MsgHook64.dll b/native/MsgHook/bin/MsgHook64.dll
index 780332f..7c1bd4c 100644
Binary files a/native/MsgHook/bin/MsgHook64.dll and b/native/MsgHook/bin/MsgHook64.dll differ
diff --git a/native/MsgHook/dllmain.cpp b/native/MsgHook/dllmain.cpp
index 5882787..f9560c6 100644
--- a/native/MsgHook/dllmain.cpp
+++ b/native/MsgHook/dllmain.cpp
@@ -15,6 +15,7 @@ BOOL APIENTRY DllMain( HMODULE hModule,
{
case DLL_PROCESS_ATTACH:
{
+ //printf("debug DLL_PROCESS_ATTACH hModule: %ld\n", (long)hModule);
TCHAR szBaseName[_MAX_FNAME], szTmp[_MAX_FNAME];
memset((void *)&szBaseName, '\0', sizeof(TCHAR) * _MAX_FNAME);
@@ -23,6 +24,10 @@ BOOL APIENTRY DllMain( HMODULE hModule,
//_wsplitpath(szTmp, NULL, NULL, szBaseName, NULL);
wcscat_s(szBaseName, TEXT("MsgHookSharedMem")); // add specifier string
+ if (IsCurrentProcess64Bit())
+ wcscat_s(szBaseName, TEXT("64")); // add bit specifier
+ else
+ wcscat_s(szBaseName, TEXT("32")); // add bit specifier
hMappedFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(GLOBALDATA), szBaseName);
pData = (GLOBALDATA*)MapViewOfFile(hMappedFile, FILE_MAP_WRITE, 0, 0, 0);
@@ -34,6 +39,13 @@ BOOL APIENTRY DllMain( HMODULE hModule,
pData->g_hWnd = NULL; // and initialize the other handles
pData->g_CwpHook = NULL;
pData->g_MsgHook = NULL;
+ pData->g_CwpHookProc = NULL;
+ }
+ else
+ {
+ //open
+ hMappedFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, szBaseName);
+ pData = (GLOBALDATA*)MapViewOfFile(hMappedFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
}
DisableThreadLibraryCalls((HMODULE)hModule);
}
diff --git a/native/MsgHook/org_synthuse_MsgHook.cpp b/native/MsgHook/org_synthuse_MsgHook.cpp
index 3dc824b..b851c18 100644
--- a/native/MsgHook/org_synthuse_MsgHook.cpp
+++ b/native/MsgHook/org_synthuse_MsgHook.cpp
@@ -8,6 +8,30 @@
#include "stdafx.h"
#include "org_synthuse_MsgHook.h"
+/*
+ * Class: org_synthuse_MsgHook
+ * Method: initialize
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_synthuse_MsgHook_initialize(JNIEnv *env, jobject obj, jstring jdll32bitname, jstring jdll64bitname)
+{
+ const char *tdll32bitname = env->GetStringUTFChars(jdll32bitname, 0);//convert string
+
+ memset((void *)&dll32bitName, '\0', sizeof(TCHAR) * MAX_TEST_SIZE); // set TCHAR array to all 0
+ int tstrLen = MultiByteToWideChar(CP_UTF8, 0, tdll32bitname, (int)strlen(tdll32bitname), NULL, 0); //get t len
+ MultiByteToWideChar(CP_UTF8, 0, tdll32bitname, (int)strlen(tdll32bitname), dll32bitName, tstrLen); // convert char to tchar
+
+ env->ReleaseStringUTFChars(jdll32bitname, tdll32bitname); //release string
+
+ const char *tdll64bitname = env->GetStringUTFChars(jdll64bitname, 0);//convert string
+
+ memset((void *)&dll64bitName, '\0', sizeof(TCHAR) * MAX_TEST_SIZE); // set TCHAR array to all 0
+ tstrLen = MultiByteToWideChar(CP_UTF8, 0, tdll64bitname, (int)strlen(tdll64bitname), NULL, 0); //get t len
+ MultiByteToWideChar(CP_UTF8, 0, tdll64bitname, (int)strlen(tdll64bitname), dll64bitName, tstrLen); // convert char to tchar
+
+ env->ReleaseStringUTFChars(jdll64bitname, tdll64bitname); //release string
+ return true;
+}
/*
* Class: org_synthuse_MsgHook
@@ -48,6 +72,12 @@ JNIEXPORT jboolean JNICALL Java_org_synthuse_MsgHook_setMsgHookWindowTargetClass
return true;
}
+JNIEXPORT jboolean JNICALL Java_org_synthuse_MsgHook_setMsgHookWindowTargetPid(JNIEnv *env, jobject obj, jint jpid)
+{
+ _stprintf_s(targetProcessId, _T("%ld"), (long)jpid);
+ return true;
+}
+
/*
* Class: org_synthuse_MsgHook
* Method: setMessageHook
diff --git a/native/MsgHook/org_synthuse_MsgHook.h b/native/MsgHook/org_synthuse_MsgHook.h
index 6e1e704..5bd9535 100644
--- a/native/MsgHook/org_synthuse_MsgHook.h
+++ b/native/MsgHook/org_synthuse_MsgHook.h
@@ -7,6 +7,14 @@
#ifdef __cplusplus
extern "C" {
#endif
+/*
+ * Class: org_synthuse_MsgHook
+ * Method: initialize
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_synthuse_MsgHook_initialize
+ (JNIEnv *, jobject, jstring, jstring);
+
/*
* Class: org_synthuse_MsgHook
* Method: createMsgHookWindow
@@ -25,11 +33,11 @@ JNIEXPORT jboolean JNICALL Java_org_synthuse_MsgHook_setMsgHookWindowTargetHwnd
/*
* Class: org_synthuse_MsgHook
- * Method: setMsgHookWindowTargetClass
- * Signature: (Ljava/lang/String;)Z
+ * Method: setMsgHookWindowTargetPid
+ * Signature: (I)Z
*/
-JNIEXPORT jboolean JNICALL Java_org_synthuse_MsgHook_setMsgHookWindowTargetClass
- (JNIEnv *, jobject, jstring);
+JNIEXPORT jboolean JNICALL Java_org_synthuse_MsgHook_setMsgHookWindowTargetPid
+ (JNIEnv *, jobject, jint);
/*
* Class: org_synthuse_MsgHook
diff --git a/native/MsgHook/resource.h b/native/MsgHook/resource.h
index efdecfc..24aed16 100644
Binary files a/native/MsgHook/resource.h and b/native/MsgHook/resource.h differ
diff --git a/native/MsgHook/stdafx.h b/native/MsgHook/stdafx.h
index d146995..055ffbf 100644
--- a/native/MsgHook/stdafx.h
+++ b/native/MsgHook/stdafx.h
@@ -11,11 +11,14 @@
// Windows Header Files:
#include
#include
+#include
#include
#include
#include
+#include //CreateToolhelp32Snapshot
#pragma comment( lib, "psapi.lib" )
+//#pragma comment( lib, "kernel32.lib" )
// TODO: reference additional headers your program requires here
@@ -37,14 +40,23 @@ typedef struct
//HHOOK g_hHook;
HWND g_hWnd;
HANDLE g_hInstance;
+ HOOKPROC g_CwpHookProc;
}GLOBALDATA;
#ifndef GLOBAL_VARS_H // header guards
#define GLOBAL_VARS_H
extern "C" __declspec(dllexport) void CreateMsgHookWindow(LPTSTR lpCmdLine);
+extern "C" __declspec(dllexport) BOOL SetCustomMsgHookDll(const TCHAR * hookDll, const char * hookDllProcName);
extern "C" __declspec(dllexport) BOOL SetMsgHook(HWND callerHWnd, DWORD threadId);
+extern "C" __declspec(dllexport) HHOOK GetCurrentHookHandle();
+extern "C" __declspec(dllexport) void SetGlobalDLLInstance(HANDLE dllInstance);
extern "C" __declspec(dllexport) BOOL RemoveHook();
+extern "C" __declspec(dllexport) BOOL IsCurrentProcess64Bit();
+extern "C" __declspec(dllexport) BOOL IsProcess64Bit(DWORD procId);
+extern "C" __declspec(dllexport) DWORD GetProcessMainThreadId(DWORD procId);
+
+//void ExtractResource(const WORD nID, LPCTSTR szFilename);
//Global variables , remember not to initialize here
extern HANDLE hMappedFile;
@@ -53,6 +65,10 @@ extern bool bStartingProcess;
#define MAX_TEST_SIZE 100
extern TCHAR targetHwndStr[MAX_TEST_SIZE];
+extern TCHAR targetProcessId[MAX_TEST_SIZE];
extern TCHAR targetClassname[MAX_TEST_SIZE];
+extern TCHAR dll32bitName[500];
+extern TCHAR dll64bitName[500];
+extern char dllProcName[500];
#endif
\ No newline at end of file
diff --git a/native/SetMsgHook/MsgHook.h b/native/SetMsgHook/MsgHook.h
new file mode 100644
index 0000000..929d8e1
--- /dev/null
+++ b/native/SetMsgHook/MsgHook.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2014, Synthuse.org
+ * Released under the Apache Version 2.0 License.
+ *
+ * last modified by ejakubowski7@gmail.com
+*/
+
+#include
+
+typedef struct
+{
+ HHOOK g_CwpHook;
+ HHOOK g_MsgHook;
+ //HHOOK g_hHook;
+ HWND g_hWnd;
+ HANDLE g_hInstance;
+ HOOKPROC g_CwpHookProc;
+}GLOBALDATA;
+
+//#define MSGHOOKER_FILE TEXT("MsgHook.dll")
+TCHAR MSGHOOK_DLL_NAME[MAX_NAME_SIZE] = _T("MsgHook.dll");
+
+HINSTANCE msgHookDll;
+
+//void CreateMsgHookWindow(LPTSTR lpCmdLine)
+typedef VOID (* CREATEMSGHOOKWINDOW)(LPTSTR);
+CREATEMSGHOOKWINDOW CreateMsgHookWindow;
+
+//BOOL SetCustomMsgHookDll(const TCHAR * hookDll, const char * hookDllProcName)
+typedef BOOL (* SETCUSTOMMSGHOOKDLL)(LPCTSTR, LPCSTR);
+SETCUSTOMMSGHOOKDLL SetCustomMsgHookDll;
+
+//BOOL SetMsgHook(HWND callerHWnd, DWORD threadId)
+typedef BOOL (* SETMSGHOOK)(HWND, DWORD);
+SETMSGHOOK SetMsgHook;
+
+//HHOOK GetCurrentHookHandle()
+typedef HHOOK (* GETCURRENTHOOKHANDLE)(VOID);
+GETCURRENTHOOKHANDLE GetCurrentHookHandle;
+
+//void SetGlobalDLLInstance(HANDLE dllInstance)
+typedef VOID (* SETGLOBALDLLINSTANCE)(HANDLE);
+SETGLOBALDLLINSTANCE SetGlobalDLLInstance;
+
+//BOOL RemoveHook()
+typedef BOOL (* REMOVEHOOK)(VOID);
+REMOVEHOOK RemoveHook;
+
+// DWORD GetProcessMainThreadId(DWORD procId)
+typedef DWORD (* GETPROCESSMAINTHREADID)(DWORD);
+GETPROCESSMAINTHREADID GetProcessMainThreadId;
+
+
+typedef struct
+{
+ HWND hWnd;
+ int nCode;
+ DWORD dwHookType;
+ WPARAM wParam;
+ LPARAM lParam;
+ TCHAR wParamStr[25];
+ TCHAR lParamStr[25];
+}HEVENT;
+
+/*
+typedef struct {
+ DWORD vkCode;
+ DWORD scanCode;
+ DWORD flags;
+ DWORD time;
+ ULONG_PTR dwExtraInfo;
+} KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;
+*/
+
+void MsgHook_CreateMsgHookWindow(LPTSTR args)
+{
+ msgHookDll = LoadLibrary(MSGHOOK_DLL_NAME);
+ if (msgHookDll != NULL)
+ {
+ CreateMsgHookWindow = (CREATEMSGHOOKWINDOW)GetProcAddress(msgHookDll, "CreateMsgHookWindow");
+ if (CreateMsgHookWindow)
+ {
+ CreateMsgHookWindow(args);
+ }
+ }
+}
+
+BOOL MsgHook_SetMsgHook(HWND hw, int threadId)
+{
+ msgHookDll = LoadLibrary(MSGHOOK_DLL_NAME);
+ if (msgHookDll != NULL)
+ {
+ SetMsgHook = (SETMSGHOOK)GetProcAddress(msgHookDll, "SetMsgHook");
+ GetCurrentHookHandle = (GETCURRENTHOOKHANDLE)GetProcAddress(msgHookDll, "GetCurrentHookHandle");
+ SetGlobalDLLInstance = (SETGLOBALDLLINSTANCE)GetProcAddress(msgHookDll, "SetGlobalDLLInstance");
+ RemoveHook = (REMOVEHOOK)GetProcAddress(msgHookDll, "RemoveHook");
+ if (SetMsgHook)
+ {
+ //printf("LoadLibrary MSGHOOK %ld\n", (long)msgHookDll);
+ SetGlobalDLLInstance(msgHookDll);
+ return SetMsgHook(hw, threadId);
+ }
+ }
+ return false;
+}
+
+void MsgHook_RemoveHook()
+{
+ if (RemoveHook)
+ RemoveHook();
+
+ if (msgHookDll != NULL)
+ FreeLibrary(msgHookDll);
+}
+
+DWORD MsgHook_GetProcessMainThreadId(DWORD procId)
+{
+ msgHookDll = LoadLibrary(MSGHOOK_DLL_NAME);
+ if (msgHookDll != NULL)
+ {
+ GetProcessMainThreadId = (GETPROCESSMAINTHREADID)GetProcAddress(msgHookDll, "GetProcessMainThreadId");
+ if (GetProcessMainThreadId)
+ {
+ return GetProcessMainThreadId(procId);
+ }
+ }
+ printf("error, failed loading library");
+ return 0;
+}
diff --git a/native/SetMsgHook/ReadMe.txt b/native/SetMsgHook/ReadMe.txt
new file mode 100644
index 0000000..48ecfa9
--- /dev/null
+++ b/native/SetMsgHook/ReadMe.txt
@@ -0,0 +1,40 @@
+========================================================================
+ CONSOLE APPLICATION : SetMsgHook Project Overview
+========================================================================
+
+AppWizard has created this SetMsgHook application for you.
+
+This file contains a summary of what you will find in each of the files that
+make up your SetMsgHook application.
+
+
+SetMsgHook.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.
+
+SetMsgHook.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).
+
+SetMsgHook.cpp
+ This is the main application source file.
+
+/////////////////////////////////////////////////////////////////////////////
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named SetMsgHook.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/SetMsgHook/SetMsgHook.cpp b/native/SetMsgHook/SetMsgHook.cpp
new file mode 100644
index 0000000..b93cb8f
--- /dev/null
+++ b/native/SetMsgHook/SetMsgHook.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2014, Synthuse.org
+ * Released under the Apache Version 2.0 License.
+ *
+ * last modified by ejakubowski7@gmail.com
+*/
+// SetMsgHook.cpp : Defines the entry point for the console application.
+//
+
+#include "stdafx.h"
+#include "MsgHook.h"
+
+
+int _tmain(int argc, _TCHAR* argv[])
+{
+ if (argc == 1) //no args passed, show MsgHook Viewer gui
+ {
+ MsgHook_CreateMsgHookWindow(NULL);
+ return 0;
+ }
+
+ HWND hookHwnd = NULL;
+ long procId = 0;
+ TCHAR *stopStr;
+
+ for (int i = 1 ; i < argc ; i++)
+ {
+ if (_tcscmp(argv[i], _T("?")) == 0 || _tcscmp(argv[i], _T("-?")) == 0 || argc == 3 || argc > 4)
+ {
+ printf("SetMsgHook version 1.0 by Edward Jakubowski \n\n");
+ printf("Usage: SetMsgHook.exe [(MSG_HOOK_DLL) (MSG_HOOK_HWND_OR_ZERO) (TARGET_PID)] [MSG_HOOK_DLL] [?] \n\n");
+ printf(" Additional Notes:\n");
+ printf(" Message Hook Viewer Gui - To open the gui you must provide the path to the msg hook dll as the ");
+ printf("only argument when running SetMsgHook.exe. Also setting the (MSG_HOOK_HWND) argument to 0 (zero) ");
+ printf("will start the gui and message hook on the given Process Id.\n\n");
+ HWND currentHwnd = FindWindow(_T("MSGHOOKVIEW"), NULL);
+ printf(" Current MSG_HOOK_HWND: %ld\n", (long)currentHwnd);
+ return 0;
+ }
+ if (i == 1)
+ _tcsncpy_s(MSGHOOK_DLL_NAME, MAX_NAME_SIZE, argv[i], _TRUNCATE);
+ if (i == 2)
+ hookHwnd = (HWND)_tcstol(argv[i], &stopStr, 10);
+ if (i == 3)
+ procId = (long)_tcstol(argv[i], &stopStr, 10);
+ }
+
+ if (argc == 2) //one arg passed (dll), show MsgHook Viewer gui
+ {
+ printf("Starting msg hook viewer...");
+ MsgHook_CreateMsgHookWindow(NULL);
+ return 0;
+ }
+ if (argc == 4 && hookHwnd == 0)
+ {
+ printf("Starting msg hook viewer on pid %ld...", (long)procId);
+ TCHAR tmp[100];
+ _stprintf_s(tmp, _T("%ld"), (long)procId);
+ MsgHook_CreateMsgHookWindow(tmp);
+ return 0;
+ }
+
+ char tmp[MAX_NAME_SIZE];
+ size_t convertedCnt = 0;
+ wcstombs_s(&convertedCnt, tmp, MAX_NAME_SIZE, MSGHOOK_DLL_NAME, _TRUNCATE);
+ printf("MsgHook DLL: %s, HWND: %ld, PID: %ld", tmp, (long)hookHwnd, procId);
+ DWORD threadId = MsgHook_GetProcessMainThreadId(procId);
+ printf(", ThreadId: %ld\n", (long)threadId);
+
+ if (MsgHook_SetMsgHook(hookHwnd, threadId))
+ printf("Hook successfully initialized\n");
+ else
+ {
+ printf("Hook failed to initialize\n");
+ return -1;
+ }
+
+ //don't exit SetMsgHook until hooked process exits
+ HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, procId);
+ while(WaitForSingleObject(process, 0) == WAIT_TIMEOUT)
+ {
+ Sleep(1000); //check once per second
+ if (GetCurrentHookHandle() == NULL)
+ {
+ printf("unhooked.");
+ break;
+ }
+ }
+ CloseHandle(process);
+ MsgHook_RemoveHook();
+
+ //_getch();
+ printf("done.");
+ return 0;
+}
+
diff --git a/native/SetMsgHook/SetMsgHook.vcxproj b/native/SetMsgHook/SetMsgHook.vcxproj
new file mode 100644
index 0000000..d9ee930
--- /dev/null
+++ b/native/SetMsgHook/SetMsgHook.vcxproj
@@ -0,0 +1,169 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {34A73B55-8A93-4FB5-83CE-7759C1D23348}
+ Win32Proj
+ SetMsgHook
+
+
+
+ Application
+ true
+ Unicode
+
+
+ Application
+ true
+ Unicode
+
+
+ Application
+ false
+ true
+ Unicode
+
+
+ Application
+ false
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ false
+
+
+
+ Use
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+
+
+ Console
+ true
+
+
+ mkdir "$(ProjectDir)bin"
+copy /Y "$(TargetPath)" "$(ProjectDir)bin\SetMsgHook$(PlatformArchitecture)$(TargetExt)"
+
+
+
+
+ Use
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+
+
+ Console
+ true
+
+
+ mkdir "$(ProjectDir)bin"
+copy /Y "$(TargetPath)" "$(ProjectDir)bin\SetMsgHook$(PlatformArchitecture)$(TargetExt)"
+
+
+
+
+ Level3
+ Use
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+
+
+ Console
+ true
+ true
+ true
+
+
+ mkdir "$(ProjectDir)bin"
+copy /Y "$(TargetPath)" "$(ProjectDir)bin\SetMsgHook$(PlatformArchitecture)$(TargetExt)"
+
+
+
+
+ Level3
+ Use
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+
+
+ Console
+ true
+ true
+ true
+
+
+ mkdir "$(ProjectDir)bin"
+copy /Y "$(TargetPath)" "$(ProjectDir)bin\SetMsgHook$(PlatformArchitecture)$(TargetExt)"
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+
+
\ No newline at end of file
diff --git a/native/SetMsgHook/SetMsgHook.vcxproj.filters b/native/SetMsgHook/SetMsgHook.vcxproj.filters
new file mode 100644
index 0000000..ff22488
--- /dev/null
+++ b/native/SetMsgHook/SetMsgHook.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
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/native/SetMsgHook/SetMsgHook.vcxproj.user b/native/SetMsgHook/SetMsgHook.vcxproj.user
new file mode 100644
index 0000000..ace9a86
--- /dev/null
+++ b/native/SetMsgHook/SetMsgHook.vcxproj.user
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/native/SetMsgHook/bin/SetMsgHook32.exe b/native/SetMsgHook/bin/SetMsgHook32.exe
new file mode 100644
index 0000000..8f9ede1
Binary files /dev/null and b/native/SetMsgHook/bin/SetMsgHook32.exe differ
diff --git a/native/SetMsgHook/bin/SetMsgHook64.exe b/native/SetMsgHook/bin/SetMsgHook64.exe
new file mode 100644
index 0000000..4581d77
Binary files /dev/null and b/native/SetMsgHook/bin/SetMsgHook64.exe differ
diff --git a/native/SetMsgHook/build.bat b/native/SetMsgHook/build.bat
new file mode 100644
index 0000000..626076c
--- /dev/null
+++ b/native/SetMsgHook/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/SetMsgHook/stdafx.cpp b/native/SetMsgHook/stdafx.cpp
new file mode 100644
index 0000000..77e5e87
--- /dev/null
+++ b/native/SetMsgHook/stdafx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// SetMsgHook.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/SetMsgHook/stdafx.h b/native/SetMsgHook/stdafx.h
new file mode 100644
index 0000000..fe28c4b
--- /dev/null
+++ b/native/SetMsgHook/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"
+
+#include
+#include
+#include
+
+
+// TODO: reference additional headers your program requires here
+
+#ifndef GLOBAL_VARS_H // header guards
+#define GLOBAL_VARS_H
+
+#define MAX_NAME_SIZE 500
+extern TCHAR MSGHOOK_DLL_NAME[MAX_NAME_SIZE];
+
+#endif
\ No newline at end of file
diff --git a/native/SetMsgHook/targetver.h b/native/SetMsgHook/targetver.h
new file mode 100644
index 0000000..87c0086
--- /dev/null
+++ b/native/SetMsgHook/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 f3d26f3..231e4db 100644
--- a/src/org/synthuse/Api.java
+++ b/src/org/synthuse/Api.java
@@ -20,12 +20,14 @@ import com.sun.jna.platform.win32.WinDef.*;
import com.sun.jna.platform.win32.Advapi32Util;
import com.sun.jna.platform.win32.BaseTSD.LONG_PTR;
import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
+import com.sun.jna.platform.win32.WinBase.SYSTEM_INFO;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinReg;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.platform.win32.WinNT.LARGE_INTEGER;
import com.sun.jna.platform.win32.WinUser.WNDENUMPROC;
+import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.win32.StdCallLibrary.StdCallCallback;
import com.sun.jna.win32.W32APIOptions;
@@ -323,6 +325,9 @@ public class Api {
boolean GetDiskFreeSpaceEx(String lpDirectoryName, LARGE_INTEGER.ByReference lpFreeBytesAvailable, LARGE_INTEGER.ByReference lpTotalNumberOfBytes, LARGE_INTEGER.ByReference lpTotalNumberOfFreeBytes);
int GetLastError();
Pointer OpenProcess(int dwDesiredAccess, boolean bInheritHandle, Pointer pointer);
+ boolean CloseHandle(HANDLE hObject);
+ void GetNativeSystemInfo(SYSTEM_INFO lpSystemInfo);
+ boolean IsWow64Process(HANDLE hProcess, IntByReference Wow64Process);
}
@@ -627,6 +632,36 @@ public class Api {
return false;
}
+ public static boolean isProcess64bit(int pid)
+ {
+ try {
+ SYSTEM_INFO lpSystemInfo = new SYSTEM_INFO();
+ Kernel32.instance.GetNativeSystemInfo(lpSystemInfo);
+ if (lpSystemInfo.processorArchitecture.dwOemID.intValue() == 0)
+ {
+ System.out.println("intel x86"); //not a 64 bit os
+ return false;
+ }
+
+ Pointer process = Kernel32.instance.OpenProcess(Api.PROCESS_QUERY_INFORMATION | Api.PROCESS_VM_READ, false, new Pointer(pid));
+ IntByReference isWow64 = new IntByReference(0);
+ if (!Kernel32.instance.IsWow64Process(new HANDLE(process), isWow64))
+ {
+ //handle error
+ }
+ //System.out.println("isProcess64bit " + pid + " = " + isWow64.getValue());
+ Kernel32.instance.CloseHandle(new HANDLE(process));
+ if (isWow64.getValue() == 1)
+ return false;
+ return true;
+ //CloseHandle()
+ } catch(Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ return false;
+ }
+
public static HWND FindMainWindowFromPid(final long targetProcessId) {
final List resultList = new ArrayList();
diff --git a/src/org/synthuse/CommandPopupMenu.java b/src/org/synthuse/CommandPopupMenu.java
index 0bbe7b9..e4e52cb 100644
--- a/src/org/synthuse/CommandPopupMenu.java
+++ b/src/org/synthuse/CommandPopupMenu.java
@@ -117,6 +117,9 @@ public class CommandPopupMenu extends JPopupMenu {
CommandMenuItem mntmSendCommandMsg = new CommandMenuItem("sendCommandMsg", 4);
mnWinMessages.add(mntmSendCommandMsg);
+ CommandMenuItem mntmSendMessage = new CommandMenuItem("sendMessage", 5);
+ mnWinMessages.add(mntmSendMessage);
+
CommandMenuItem mntmSetcursorposition = new CommandMenuItem("setCursorPosition", 3);
mnWinMessages.add(mntmSetcursorposition);
@@ -232,6 +235,8 @@ public class CommandPopupMenu extends JPopupMenu {
actionStr += "with | |";
if (paramCount > 3)
actionStr += " and | |";
+ if (paramCount > 4)
+ actionStr += " and | |";
return actionStr;
}
}
diff --git a/src/org/synthuse/CommandProcessor.java b/src/org/synthuse/CommandProcessor.java
index 5bfb2ac..be41135 100644
--- a/src/org/synthuse/CommandProcessor.java
+++ b/src/org/synthuse/CommandProcessor.java
@@ -24,6 +24,7 @@ public class CommandProcessor implements Runnable{
public static boolean DEFAULT_QUIET = false; //by default is quiet enabled
protected CommandProcessor CommandProcessor = null;
+ public int executeCount = 0;
public int executeErrorCount;
public String lastError = "";
public String currentCommandText = "";
@@ -94,6 +95,7 @@ public class CommandProcessor implements Runnable{
events.statusChanged("Executing Test Script...");
//CommandProcessor cmdProcessor = new CommandProcessor();
scriptErrorCount = 0;
+ executeCount = 0;
lastError = "";
long startTime = System.nanoTime();
String[] lines = scriptStr.split("\n");
@@ -101,7 +103,7 @@ public class CommandProcessor implements Runnable{
if (!line.trim().startsWith("|"))
continue; //skip if it doesn't start with bar
- String[] parsed = line.split("\\|");
+ String[] parsed = line.trim().split("\\|");
//
//System.out.println("line: " + line);
@@ -117,6 +119,8 @@ public class CommandProcessor implements Runnable{
execute(parsed[2].trim(), new String[] {parsed[4].trim(), parsed[6].trim()});
if (parsed.length == 9)
execute(parsed[2].trim(), new String[] {parsed[4].trim(), parsed[6].trim(), parsed[8].trim()});
+ if (parsed.length == 11)
+ execute(parsed[2].trim(), new String[] {parsed[4].trim(), parsed[6].trim(), parsed[8].trim(), parsed[10].trim()});
if (executeErrorCount > 0) //check if any errors occurred
++scriptErrorCount;
@@ -128,7 +132,7 @@ public class CommandProcessor implements Runnable{
String forcedStr = "Completed";
if (STOP_PROCESSOR.get())
forcedStr = "Stopped";
- events.statusChanged("Script Execution " + forcedStr + " with " + scriptErrorCount + " error(s) in " + new DecimalFormat("#.###").format(seconds) + " seconds");
+ events.statusChanged("Script Execution " + forcedStr + " " + executeCount + " command(s) with " + scriptErrorCount + " error(s) in " + new DecimalFormat("#.###").format(seconds) + " seconds");
events.executionCompleted();
if (scriptErrorCount > 0 && !isQuiet)
{
@@ -142,6 +146,7 @@ public class CommandProcessor implements Runnable{
}
public Object execute(String command, String[] args) {
+ ++executeCount;
executeErrorCount = 0;
currentCommandText = command;
String joinedArgs = "";
@@ -221,6 +226,8 @@ public class CommandProcessor implements Runnable{
return win.cmdSelectContextMenuId(args);
if (command.equals("sendCommandMsg"))
return win.cmdSendCommandMsg(args);
+ if (command.equals("sendMessage"))
+ return win.cmdSendMessage(args);
if (command.equals("windowMinimize"))
return win.cmdWindowMinimize(args);
if (command.equals("windowMaximize"))
diff --git a/src/org/synthuse/MsgHook.java b/src/org/synthuse/MsgHook.java
index 002b1be..1afc2a1 100644
--- a/src/org/synthuse/MsgHook.java
+++ b/src/org/synthuse/MsgHook.java
@@ -19,14 +19,23 @@ import javax.swing.JOptionPane;
public class MsgHook {
-
+ public static String targetdllName = "";
+ public static String dll64bitName = "";
+ public static String dll32bitName = "";
static
{
String loadFailedMsg = "Failed to load MsgHook library.\n";
//System.out.println("SynthuseDlg.config.disableUiaBridge: " + SynthuseDlg.config.disableUiaBridge);
String archDataModel = System.getProperty("sun.arch.data.model");//32 or 64 bit
try {
- loadNativeLibraryFromJar("/MsgHook" + archDataModel + ".dll");
+ targetdllName = "/MsgHook" + archDataModel + ".dll";
+ dll64bitName = SaveNativeLibraryFromJar("/MsgHook64.dll"); //need to save both 32 and 64 bit dlls for hooking both types
+ dll32bitName = SaveNativeLibraryFromJar("/MsgHook32.dll");
+ if (archDataModel.equals("32"))
+ System.load(dll32bitName);
+ else
+ System.load(dll64bitName);
+
} catch (Exception ex) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
@@ -36,7 +45,7 @@ public class MsgHook {
}
}
- public static void loadNativeLibraryFromJar(String path) {
+ public static String SaveNativeLibraryFromJar(String path) {
// Obtain filename from path
String[] parts = path.split("/");
String filename = (parts.length > 1) ? parts[parts.length - 1] : null;
@@ -58,7 +67,7 @@ public class MsgHook {
}
if (!temp.exists()) { //some reason the temp file wasn't create so abort
System.out.println("File " + temp.getAbsolutePath() + " does not exist.");
- return;
+ return "";
}
// Prepare buffer for data copying
@@ -68,7 +77,7 @@ public class MsgHook {
InputStream is = MsgHook.class.getResourceAsStream(path);
if (is == null) { //check if valid
System.out.println("File " + path + " was not found inside JAR.");
- return;
+ return "";
}
// Open output stream and copy data between source file in JAR and the temporary file
OutputStream os = null;
@@ -83,23 +92,25 @@ public class MsgHook {
e.printStackTrace();
}
// Finally, load the library
- System.load(temp.getAbsolutePath());
+ return temp.getAbsolutePath();
}
- //public native boolean initialize(int hwnd);
+ public native boolean initialize(String dll32bitName, String dll64bitName);
public native boolean createMsgHookWindow();
public native boolean setMsgHookWindowTargetHwnd(int hwnd);
- public native boolean setMsgHookWindowTargetClass(String classname);
+ public native boolean setMsgHookWindowTargetPid(int pid);
public native boolean setMessageHook(int hwnd, int threadId);
public native boolean removeMessageHook();
//public native boolean shutdown();
- public static Thread createMsgHookWinThread(final long targetHwnd)
+ public static Thread createMsgHookWinThread(final long targetHwnd, final int targetPid)
{
Thread t = new Thread() {
public void run() {
MsgHook mh = new MsgHook();
- mh.setMsgHookWindowTargetClass("");
+ mh.initialize(dll32bitName, dll64bitName);
+ if (targetPid != 0)
+ mh.setMsgHookWindowTargetPid(targetPid);
if (targetHwnd != 0)
mh.setMsgHookWindowTargetHwnd((int)targetHwnd);
mh.createMsgHookWindow();
diff --git a/src/org/synthuse/SynthuseDlg.java b/src/org/synthuse/SynthuseDlg.java
index 228c317..1d643fa 100644
--- a/src/org/synthuse/SynthuseDlg.java
+++ b/src/org/synthuse/SynthuseDlg.java
@@ -29,6 +29,7 @@ import com.jgoodies.forms.layout.RowSpec;
import com.jgoodies.forms.factories.FormFactory;
*/
import com.sun.jna.platform.win32.WinDef.HWND;
+import com.sun.jna.ptr.PointerByReference;
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
@@ -50,7 +51,7 @@ public class SynthuseDlg extends JFrame {
/**
*
*/
- public static String VERSION_STR = "1.2.1";
+ public static String VERSION_STR = "1.2.2";
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";
@@ -77,6 +78,7 @@ public class SynthuseDlg extends JFrame {
public static Config config = new Config(Config.DEFAULT_PROP_FILENAME);
private String dialogResult = "";
private String lastDragHwnd = "";
+ private int lastDragPid = 0;
private String lastRuntimeId ="";
private JComboBox cmbXpath;
private JButton btnTestIde;
@@ -195,10 +197,10 @@ public class SynthuseDlg extends JFrame {
*/
long lastHwndLong = 0;
try {
- lastHwndLong = Long.parseLong(lastDragHwnd);
+ //lastHwndLong = Long.parseLong(lastDragHwnd);
} catch (Exception ex) {
}
- MsgHook.createMsgHookWinThread(lastHwndLong);
+ MsgHook.createMsgHookWinThread(lastHwndLong, lastDragPid);
}
}
@@ -510,6 +512,10 @@ public class SynthuseDlg extends JFrame {
String handleStr = Api.GetHandleAsString(hwnd);
String classStr = WindowsEnumeratedXml.escapeXmlAttributeValue(Api.getWindowClassName(hwnd));
String parentStr = Api.GetHandleAsString(User32.instance.GetParent(hwnd));
+ PointerByReference pointer = new PointerByReference();
+ User32.instance.GetWindowThreadProcessId(hwnd, pointer);
+ int pid = pointer.getPointer().getInt(0);
+
String enumProperties = "";
if (!SynthuseDlg.config.isUiaBridgeDisabled())
enumProperties = uiabridge.getWindowInfo(targetX, targetY, WindowInfo.UIA_PROPERTY_LIST_ADV);
@@ -524,6 +530,7 @@ public class SynthuseDlg extends JFrame {
}
lastDragHwnd = handleStr;
lastRuntimeId = runtimeId;
+ lastDragPid = pid;
//lastDragHwnd = (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
diff --git a/src/org/synthuse/TestIdeFrame.java b/src/org/synthuse/TestIdeFrame.java
index 9bbd259..aa14ddd 100644
--- a/src/org/synthuse/TestIdeFrame.java
+++ b/src/org/synthuse/TestIdeFrame.java
@@ -12,7 +12,9 @@ import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
+import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.ImageIcon;
+import javax.swing.JFileChooser;
import javax.swing.JToolBar;
import javax.swing.JButton;
import javax.swing.JScrollPane;
@@ -26,6 +28,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.Toolkit;
+import java.io.*;
import javax.swing.JLabel;
@@ -36,7 +39,8 @@ public class TestIdeFrame extends JFrame {
public static String RES_STR_RUN_IMG = "/org/synthuse/img/arrow-right-3.png";
public static String RES_STR_CLEAR_IMG = "/org/synthuse/img/user-trash-2.png";
public static String RES_STR_COPY_IMG = "/org/synthuse/img/edit-copy-7.png";
-
+ public static String RES_STR_SAVE_IMG = "/org/synthuse/img/document-save-6.png";
+ public static String RES_STR_OPEN_IMG = "/org/synthuse/img/document-open-folder.png";
/**
*
*/
@@ -46,6 +50,8 @@ public class TestIdeFrame extends JFrame {
private JButton btnRun;
private JButton btnClear;
private JButton btnCopy;
+ private JButton btnSave;
+ private JButton btnOpen;
private JLabel lblStatus;
/**
@@ -68,32 +74,30 @@ public class TestIdeFrame extends JFrame {
btnRun = new JButton("Run");
btnRun.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
- if (btnRun.getText().equals("Run")) {
- btnRun.setText("Stop");
- btnRun.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_STOP_IMG)));
- CommandProcessor.STOP_PROCESSOR.set(false);
- CommandProcessor.executeThreaded(txtTest.getText(), new CommandProcessor.Events() {
- @Override
- public void statusChanged(String status) {
- lblStatus.setText(status);
- }
- @Override
- public void executionCompleted() {
- btnRun.setText("Run");
- btnRun.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_RUN_IMG)));
- }
- });
- }
- else {
- CommandProcessor.STOP_PROCESSOR.set(true);
- //btnRun.setText("Run");
- //btnRun.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_RUN_IMG)));
- }
+ runTestScript();
}
});
btnRun.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_RUN_IMG)));
toolBar.add(btnRun);
+ btnSave = new JButton("Save");
+ btnSave.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent arg0) {
+ saveTestScript();
+ }
+ });
+ btnSave.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_SAVE_IMG)));
+ toolBar.add(btnSave);
+
+ btnOpen = new JButton("Open");
+ btnOpen.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent arg0) {
+ openTestScript();
+ }
+ });
+ btnOpen.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_OPEN_IMG)));
+ toolBar.add(btnOpen);
+
btnClear = new JButton("Clear");
btnClear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
@@ -135,5 +139,83 @@ public class TestIdeFrame extends JFrame {
});
super.setAlwaysOnTop(SynthuseDlg.config.isAlwaysOnTop());
}
+
+ public void runTestScript()
+ {
+ if (btnRun.getText().equals("Run")) {
+ btnRun.setText("Stop");
+ btnRun.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_STOP_IMG)));
+ CommandProcessor.STOP_PROCESSOR.set(false);
+ CommandProcessor.executeThreaded(txtTest.getText(), new CommandProcessor.Events() {
+ @Override
+ public void statusChanged(String status) {
+ lblStatus.setText(status);
+ }
+ @Override
+ public void executionCompleted() {
+ btnRun.setText("Run");
+ btnRun.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_RUN_IMG)));
+ }
+ });
+ }
+ else {
+ CommandProcessor.STOP_PROCESSOR.set(true);
+ //btnRun.setText("Run");
+ //btnRun.setIcon(new ImageIcon(SynthuseDlg.class.getResource(RES_STR_RUN_IMG)));
+ }
+ }
+
+ private void saveTestScript()
+ {
+ JFileChooser fChoose = new JFileChooser();
+ fChoose.setFileFilter(new FileNameExtensionFilter("Text Files", "txt", "text"));
+ int result = fChoose.showSaveDialog(this);
+ if (result == JFileChooser.CANCEL_OPTION)
+ return;
+ File file = fChoose.getSelectedFile();
+ if (fChoose.getFileFilter().getDescription().startsWith("Text") && !file.getAbsolutePath().toLowerCase().endsWith(".txt"))
+ file = new File(file.getAbsolutePath() + ".txt"); //append extension if not already there
+
+ FileWriter fw = null;
+ try {
+ fw = new FileWriter(file);
+ fw.write(txtTest.getText());
+ fw.flush();
+ fw.close();
+ fw = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (fw != null)
+ try { fw.close(); } catch (Exception e){ e.printStackTrace(); };
+ lblStatus.setText("Script Saved: " + file.getAbsolutePath());
+ }
+
+ private void openTestScript()
+ {
+ JFileChooser fChoose = new JFileChooser();
+ fChoose.setFileFilter(new FileNameExtensionFilter("Text Files", "txt", "text"));
+ int result = fChoose.showOpenDialog(this);
+ if (result == JFileChooser.CANCEL_OPTION)
+ return;
+ File file = fChoose.getSelectedFile();
+ BufferedReader br = null;
+ try {
+ br = new BufferedReader(new FileReader(file));
+ String line = "";
+ txtTest.setText("");
+ while((line = br.readLine()) != null){
+ txtTest.append(line + System.getProperty("line.separator"));
+ //System.out.println(line);
+ }
+ br.close();
+ br = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (br != null)
+ try { br.close(); } catch (Exception e){ e.printStackTrace(); };
+ lblStatus.setText("Script Loaded: " + file.getAbsolutePath());
+ }
}
diff --git a/src/org/synthuse/WindowInfo.java b/src/org/synthuse/WindowInfo.java
index eb39f49..e9a0ece 100644
--- a/src/org/synthuse/WindowInfo.java
+++ b/src/org/synthuse/WindowInfo.java
@@ -22,6 +22,7 @@ import com.sun.jna.platform.win32.WinDef.LPARAM;
import com.sun.jna.platform.win32.WinDef.LRESULT;
import com.sun.jna.platform.win32.WinDef.RECT;
import com.sun.jna.platform.win32.WinDef.WPARAM;
+import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.PointerByReference;
public class WindowInfo {
@@ -50,6 +51,7 @@ public class WindowInfo {
public int menus = 0;
public HMENU menu = null;
public boolean useUiaBridge = false;
+ public boolean is64bit = false;
public Map extra = null;
@@ -146,13 +148,10 @@ public class WindowInfo {
useUiaBridge = true;
}
else {
-
PointerByReference pointer = new PointerByReference();
User32.instance.GetWindowThreadProcessId(hWnd, pointer);
pid = pointer.getPointer().getInt(0);
- 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);
+ getProcessInfo();
//test to see if uiaBridge should be used on this parent
if (this.className.startsWith("HwndWrapper") || this.className.startsWith("WindowsForms"))
useUiaBridge = true;
@@ -204,6 +203,8 @@ public class WindowInfo {
this.hwndStr = "";
//if (this.framework == null)
// this.framework = "na";
+ if(this.controlType.equals("window"))
+ this.isChild = false;
return;
}
// non-wildcard mode
@@ -234,7 +235,9 @@ public class WindowInfo {
value = value.substring(0, MAX_TEXT_SIZE);
if (this.hwndStr == null)
this.hwndStr = "";
-
+ getProcessInfo();
+ if(this.controlType.equals("window"))
+ this.isChild = false;
/*
this.rect = new RECT();
try {
@@ -250,6 +253,18 @@ public class WindowInfo {
*/
}
+ private void getProcessInfo()
+ {
+ if (pid == 0)
+ return;
+ char[] buffer = new char[1026];
+ Pointer process = Kernel32.instance.OpenProcess(Api.PROCESS_QUERY_INFORMATION | Api.PROCESS_VM_READ, false, new Pointer(pid));
+ Psapi.instance.GetModuleBaseNameW(process, null, buffer, 512);
+ processName = Native.toString(buffer);
+ Kernel32.instance.CloseHandle(new HANDLE(process));
+ is64bit = Api.isProcess64bit((int)pid);
+ }
+
public static String getRuntimeIdFromProperties(String enumProperties)
{
diff --git a/src/org/synthuse/WindowsEnumeratedXml.java b/src/org/synthuse/WindowsEnumeratedXml.java
index a9d92e3..52b135e 100644
--- a/src/org/synthuse/WindowsEnumeratedXml.java
+++ b/src/org/synthuse/WindowsEnumeratedXml.java
@@ -195,6 +195,7 @@ public class WindowsEnumeratedXml implements Runnable{
if (!w.controlType.isEmpty())
win.setAttribute("type", w.controlType);
if (!w.isChild) {
+ //win.setAttribute("parent", "yes");
parentCount++;
if (w.processName != null && !w.processName.isEmpty()) {
if (!processList.containsKey(w.pid+""))
@@ -203,11 +204,20 @@ public class WindowsEnumeratedXml implements Runnable{
if (w.processName != null)
win.setAttribute("PROCESS", w.processName.toUpperCase());
}
+ if (w.pid != 0)
+ {
+ if (w.is64bit)
+ win.setAttribute("bits", "64");
+ else
+ win.setAttribute("bits", "32");
+ }
}
if (w.pid != 0)
win.setAttribute("pid", w.pid+"");
//else
//win.setAttribute("parent", w.parent + ""); // not really needed since child node is append to parent node
+
+
if (w.extra != null) {
for(String extraName: w.extra.keySet()) {
win.setAttribute(extraName, w.extra.get(extraName)+"");
diff --git a/src/org/synthuse/commands/WindowsCommands.java b/src/org/synthuse/commands/WindowsCommands.java
index 9fdf007..738aa1a 100644
--- a/src/org/synthuse/commands/WindowsCommands.java
+++ b/src/org/synthuse/commands/WindowsCommands.java
@@ -176,5 +176,23 @@ public class WindowsCommands extends BaseCommand {
return true;
}
+
+ public boolean cmdSendMessage(String[] args) {
+ if (!checkArgumentLength(args, 4))
+ return false;
+ WinPtr handle = findHandleWithXpath(args[0]); //xpath to HWND is first argument
+ if (handle.isEmpty())
+ return false;
+ int msg = Integer.parseInt(args[1]);
+ int id = Integer.parseInt(args[2]); //context menu id is supplied as second argument
+ int idLparam = Integer.parseInt(args[3]); //context menu id is supplied as second argument
+ handle.convertToNativeHwnd();
+ //LRESULT result =
+ //System.out.println("Send Message WM_COMMAND to " + handle.toString() + " PARAMS: " + id + ", " + idLparam);
+ //api.user32.PostMessage(handle.hWnd, Api.WM_COMMAND, new WPARAM(id), new LPARAM(0));
+ api.user32.SendMessage(handle.hWnd, msg, new WPARAM(id), new LPARAM(idLparam));
+
+ return true;
+ }
}
diff --git a/src/org/synthuse/img/document-open-folder.png b/src/org/synthuse/img/document-open-folder.png
new file mode 100644
index 0000000..98b8a94
Binary files /dev/null and b/src/org/synthuse/img/document-open-folder.png differ
diff --git a/src/org/synthuse/img/document-save-6.png b/src/org/synthuse/img/document-save-6.png
new file mode 100644
index 0000000..7229bb4
Binary files /dev/null and b/src/org/synthuse/img/document-save-6.png differ
diff --git a/src/org/synthuse/test/WpfMockTestAppx64.exe b/src/org/synthuse/test/WpfMockTestAppx64.exe
new file mode 100644
index 0000000..4b5b4ad
Binary files /dev/null and b/src/org/synthuse/test/WpfMockTestAppx64.exe differ