From d100d2325969b5ee464ae8fab2d2a1768017db15 Mon Sep 17 00:00:00 2001 From: Edward Jakubowski Date: Tue, 3 Jun 2014 06:28:14 -0400 Subject: [PATCH] Support for showing if app is 32bit vs 64bit, and support for doing message hooks on both Added support for message hook viewer to hook both 32 and 64 bit applications. Fixed filtering on the msg hook viewer Added custom filtering on msg hook viewer Added Process Id targetting on msg hook viewer Added SetMsgHook.exe command line app as an alternative way of starting msg hook viewer. --- .gitignore | 2 +- native/MsgHook.sln | 35 ++++ native/MsgHook/MsgHook.cpp | 146 ++++++++++++++- native/MsgHook/MsgHook.def | 5 + native/MsgHook/MsgHook.vcxproj | 9 + native/MsgHook/MsgHook.vcxproj.filters | 11 ++ native/MsgHook/MsgHookTest.aps | Bin 55012 -> 73208 bytes native/MsgHook/MsgHookTest.rc | Bin 11872 -> 12548 bytes native/MsgHook/MsgHookWindow.cpp | 141 +++++++++++++-- native/MsgHook/ResExtract.h | 86 +++++++++ native/MsgHook/bin/MsgHook32.dll | Bin 79360 -> 108032 bytes native/MsgHook/bin/MsgHook64.dll | Bin 81920 -> 111616 bytes native/MsgHook/dllmain.cpp | 12 ++ native/MsgHook/org_synthuse_MsgHook.cpp | 30 ++++ native/MsgHook/org_synthuse_MsgHook.h | 16 +- native/MsgHook/resource.h | Bin 4020 -> 4568 bytes native/MsgHook/stdafx.h | 16 ++ native/SetMsgHook/MsgHook.h | 129 +++++++++++++ native/SetMsgHook/ReadMe.txt | 40 +++++ native/SetMsgHook/SetMsgHook.cpp | 96 ++++++++++ native/SetMsgHook/SetMsgHook.vcxproj | 169 ++++++++++++++++++ native/SetMsgHook/SetMsgHook.vcxproj.filters | 39 ++++ native/SetMsgHook/SetMsgHook.vcxproj.user | 3 + native/SetMsgHook/bin/SetMsgHook32.exe | Bin 0 -> 10240 bytes native/SetMsgHook/bin/SetMsgHook64.exe | Bin 0 -> 11776 bytes native/SetMsgHook/build.bat | 6 + native/SetMsgHook/stdafx.cpp | 8 + native/SetMsgHook/stdafx.h | 23 +++ native/SetMsgHook/targetver.h | 8 + src/org/synthuse/Api.java | 35 ++++ src/org/synthuse/CommandPopupMenu.java | 5 + src/org/synthuse/CommandProcessor.java | 11 +- src/org/synthuse/MsgHook.java | 31 ++-- src/org/synthuse/SynthuseDlg.java | 13 +- src/org/synthuse/TestIdeFrame.java | 126 ++++++++++--- src/org/synthuse/WindowInfo.java | 25 ++- src/org/synthuse/WindowsEnumeratedXml.java | 10 ++ .../synthuse/commands/WindowsCommands.java | 18 ++ src/org/synthuse/img/document-open-folder.png | Bin 0 -> 852 bytes src/org/synthuse/img/document-save-6.png | Bin 0 -> 1254 bytes src/org/synthuse/test/WpfMockTestAppx64.exe | Bin 0 -> 55296 bytes 41 files changed, 1232 insertions(+), 72 deletions(-) create mode 100644 native/MsgHook.sln create mode 100644 native/MsgHook/MsgHook.def create mode 100644 native/MsgHook/ResExtract.h create mode 100644 native/SetMsgHook/MsgHook.h create mode 100644 native/SetMsgHook/ReadMe.txt create mode 100644 native/SetMsgHook/SetMsgHook.cpp create mode 100644 native/SetMsgHook/SetMsgHook.vcxproj create mode 100644 native/SetMsgHook/SetMsgHook.vcxproj.filters create mode 100644 native/SetMsgHook/SetMsgHook.vcxproj.user create mode 100644 native/SetMsgHook/bin/SetMsgHook32.exe create mode 100644 native/SetMsgHook/bin/SetMsgHook64.exe create mode 100644 native/SetMsgHook/build.bat create mode 100644 native/SetMsgHook/stdafx.cpp create mode 100644 native/SetMsgHook/stdafx.h create mode 100644 native/SetMsgHook/targetver.h create mode 100644 src/org/synthuse/img/document-open-folder.png create mode 100644 src/org/synthuse/img/document-save-6.png create mode 100644 src/org/synthuse/test/WpfMockTestAppx64.exe 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 ab709a62832d9828070044f0db8e70f9efb66a19..0f73f8487c5c01d13130d5523926a2b5414e4b13 100644 GIT binary patch delta 15472 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 diff --git a/native/MsgHook/MsgHookTest.rc b/native/MsgHook/MsgHookTest.rc index 8aaa3ec606cfcb751ffccfe8fa3493c1013cc5d3..585727403fa4a76354694a74f3ed12b4d6ac9e52 100644 GIT binary patch delta 514 zcmaD5(~`8IfSuKo!I{B-a-)Fw<{tJEw#j~cGOA__CJYJ;Ner0`B|tiWp@<=$A(1T%z8{-`28c^!|~W(B?)PEm9t zJQ-3LtR^=~%TK-|?xY;T;0QFp9jGw`Xp|>|3xf`WA%hVR>oAxDu_=S$WJP(y%{dYa z1i77n3jDwtA}0%SiV6lX!~^XEY4v6B0J&iDM0Uw~Bvn8cD*)yE8Nz_792uM#e1J5_ zSD`>lK`andV$cJ^7$6J=`mO}1zL+5$XkI=LW`o5+p^=AE1<2=mK%Espti-@8!N3Lf b2dd+Y8H@(RaX@>K9XGjIar0&#tq>Lf^lx3# delta 109 zcmZokdJwarfPHd{uGC}!4x`O`*j?B**YVBaln-afWXNMkVaR7FXHZ~pX2@YkWGDv0 zJRqIRkUCjWQgO1Mgp;f*gA0QvLkNQ*gANcIfoXFv+knAzvb? 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 c5b0807a91991960c7482c3d255d5aac2f44d200..493932a112c27ccbc1a8c556134d160585190c6a 100644 GIT binary patch literal 108032 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

wpq4CHqqv@{nEC@_LS{;+aAB|Rog*Zovp$4 ziS0An*S5dgezY;W%6^-Dq{IP?>&c8aZIy;>)t^uyWt`V*YF1^d;N_Tl(vt4DbZLa5BFS%ZI9d?~@opXKd zy6n2{>g!gyQ`}?RCii{rDen31#qP)40rzJ2^X`}3uesmzyX)N--OcXH?(1%b_pIAJ zsUC~R<;nEqc$Rv6o+ms{c_hzX&+DE;o)0}uoR^3S;zhr8r%@ZkX;)onDur zdr&u5C+b$~euV-2tnL-v?{&v?CozD((uH(gI)xrz>h)vvHoaRvO`okV)IXsw(f?ZS ze@S1he?xy<-=P0o-=hB(qdLZrY#45sXmA+rHOw+RY*=AfZ+O!1v|*>=H-J3g_#p0#0e@vEhGua!Z0C4&Y+;TtPskOP2%?ZL6bL?Hy|6(D2>ueG3{$L9*nw%bTc{Fhgj!*ruwOVR z92SlUb;3!ZQ8*(s3Fk5KnuQijzL3x^bO_gkPN7R+<`{FFS!Gt6lg!EHVdfM}$5it~ zOi7d3YId5_%mGV@rOdL`Qfb*?*=5;{*;Qky#SGhTIcPa-IpVg|Sx#CSEoUrEmh+ZN zmS#(frPUI`r0cL;!^G>dFl&r8&Z@Gitx48o>o9AIRclSPPPFQ*CaZPlj zeyM(w{w4h@`UCoA{a5;b>5~n27;J_~7-X9aHHH&dO20AuXt>=t0*k59Xft|@3yn*S zWyT8Qv&J`#?_yA$F`hGiDi5pgFsufc2AceXO%qHHn|5Mt{m^vT^n>XhVKbJ@-=G)2 z69!|6yu*B_Suig*uQvbE{EYc|^B!}(xzpTbW|kN%hboK9l5Ux4S!{XC60mHuykvRT zavW>l*Ou#+e%8TOhc(TbWzDy4wpLl+ww|_rZf&>zWKFQ8*&ek$X4_?Z(Qi9vyJ8z= zf6V?X`%_q(j@vKUzp{U0Z?`KQ366UlF2{pdjfxykVio$W;|Nxu2FITrt&R={bN0pZ zqjgSjx}7=B)lQ#ti}SZwZ0fPt{KI+O8I~8CWY>7t{jQm=m9C>$QjG4ESVA6mZ*&*C z%iWdkoo@e2?pNIV+y~t6xKFrGyU)45bbsS+cYo*Za>shqo?&utnLSR=B+nerLeDZR zD}GO@XP4(y&tcD5&)1#~4@<-AHG1$aok2HKH%FJOAFjU#3&kS+a{XETdHrWt8?NdT z438Lc4UZe1H~iLc04qT~)`Ct0vlvyzfyQL?nbtVLs58>5A)czNKwqV=!8-uUWsLU1 Y&CV8Qu1j>~W2vlh)w&K`ec7x0AK?tU1ONa4 diff --git a/native/MsgHook/bin/MsgHook64.dll b/native/MsgHook/bin/MsgHook64.dll index 780332f3d4752930f47bbf1fd2950941e9767437..7c1bd4c0474ee8a3f7f8f7eeaf80a5494d63be5b 100644 GIT binary patch literal 111616 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%0DKk?FQ;JirO!-C1wJH9Tn^S(Ba&OAR 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 PSKg*|h-l$YrGfts|0-;h delta 15931 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 B#}WVl 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 efdecfc5992a4f26a71d9d84340847c1b0238831..24aed165846e44f32464893c5268ca82040c75f4 100644 GIT binary patch delta 254 zcmdlYe?xgg6!RozK4wn_=gE$2>XR=pvTU|t)?gG2Vu)u5W^iQ)Ven<}U@&Gdn!J%o zd-4JnmdRc$C1|o{3??91RztA5kIb^XP7Iz5ehiKbK@5=)onSfR$&9SBlMk`P2!?>= z+`;At0M)uoW@Lg`{*OhCWpe|k8S`X2ZV_>y$qXQ~LKp&oX8AKX19b#51W*3RDLMHD zpV(vtE;eqM49FD+nYAYiFtSWe;9_I6nEanbe)BG#1B{F&lNI?iCokbMVzyu~2D6#? GHvs@}$~o-- delta 84 zcmcbiyhVOP6!YdS%v_9M3#8cbGX6rG$WC^GqkfYIaxJ_#^eO>h$cy^|Zj 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 0000000000000000000000000000000000000000..8f9ede1273d701b29398020bf67e9c21b8955f61 GIT binary patch literal 10240 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..98b8a9448a5756451eadce70af3772be1f543993 GIT binary patch literal 852 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE0z%d<2gY`4S99w&sfq~J`)5S5w;`Gv>-CoX)0=DVp@A8@$w+gyk zW?Ac-n7w$Ze1a7Bf29fX7vwoQ4Hb2pPwpZlyzw76$+xg?=UZ@v)2#b0dFKL^yir1f2 zt+>ggS-@fCtq(Ex_jLpt?sq=QxidndJz~ivPG#4%|6CrooJiGKz_z#ckGRXBLZ=S# z=AO+0v)?T_Dip_agq^3>;pDE8aM_iI*m+c6pSkz-@$0O_tezzH&kKY#UzwjTyf!m7 z^Zxy?Tjg_SuDX&L3oGvKvI+89`ut4Jd~asWlEpt6A96=DZ(*2U2MkHo64!{5 z9nO2Eg!<&1*zW_C)gPi1(nVgzeoXU_vn(|^KQ}i&uUId?C|y4XqNG?qsZzH%QQuh4KwlxhNP!p~KJEcN`bK(&`qBM1 z$uKuUoQD(&2FALEmLY})R;ET)ra(`b0X=n7{@W&?21$?`gY(l$$`gxH8OqDc^)mCa zi<1)zQbA6e{mw=Ts7M&1sI(|KmBGKFGCeg+JY4xi$eughb?W|5+ZoS;pM@};`%{MRl!x0;=U|<;3!ZP zkh5@U`R(p4CZQV{Z#xAB22A|YZ|d!H!J?tXbXYt!dVdYt_{eem8fq;YLI`y7B>9nu6pY98IzyHT4wsQ^) zG5)!QRS!R2=3AX*Dc#m`_`UwY>3?>$gGr+_@L#1qT%tsnaYk z!{Y!C567bbp28-E>3a8*7x28*F^cg1k-qBicRn-S)uDa0AKTAvvHJ7l_kHUo##8^# zu+4BHoaycHGXN zDGN7BFP!RBZ0793xhia9Wgn|>LvfS&3GSz7Zit2OGTXSBI?P(OWnOxV&E~vyVL$&| z=Mg^aicV3ggaUnwSE(b=UFptia@es;DLg@M|S61a5Xz6JeoIAOz^!| zgQ7?W$FjDWLdky9T%CME7q3cXEqYvdq-tBjy1BuV4%~Rb5V(0>Fptj^FAs~qXH_n* zecrMs+UBMIpG)V>(*7=c_T{K#U%&J`A+L7s{k5kqz4Bsl-~3m-ef!*_feYuRu?Sjk z{(j^9{Eic8hua$T*p#)ir(Qk%VC^lL-R8N=C+e`XZ@&9<&rSK2Y6313?!Aud|9)&; zjC|z9?VAJh0ys+-J?qd)V%5rh=VzC)YU*eCwR7A~@4F|h228xFC9V-A$wjG&C8@e8 zK!U-@z`#=1&`{UVEX2sj%Fx2f&|KHR+{(Zpn&IC;m~Lcq)L5bJp+A({2~P+l^f}q>UX!3VtQ&&YGO)d;mK4Rpdx9A zqSB(|R0cOkUkFkN&dkYH@Jt4Jps6b5H&B@|LRoxhkPpna<>lpiX^FWIqzCk~eokVN dekMqxelgGt{X<81d4bv)JYD@<);T3K0RT0l`g{NY literal 0 HcmV?d00001 diff --git a/src/org/synthuse/test/WpfMockTestAppx64.exe b/src/org/synthuse/test/WpfMockTestAppx64.exe new file mode 100644 index 0000000000000000000000000000000000000000..4b5b4ad1189d9e666b5455b68e19a3cd015af43a GIT binary patch literal 55296 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