#include #include #include "TextOutSpy.h" #include "ThTypes.h" #include "GDDataTranfer.h" #include "GetWordByIAccEx.h" const int MOUSEOVER_INTERVAL = 300; const int REQUEST_MESSAGE_INTERVAL = 500; const int WM_MY_SHOW_TRANSLATION = WM_USER + 301; HINSTANCE g_hInstance = NULL; HANDLE hSynhroMutex = 0; HINSTANCE hGetWordLib = 0; UINT_PTR TimerID = 0; typedef DWORD (*GetWordProc_t)(TCurrentMode *); GetWordProc_t GetWordProc = NULL; GDDataStruct gds; UINT uGdAskMessage; WCHAR Buffer[256]; DWORD ourProcessID, gdProcessID, winProcessID; static HWND GetWindowFromPoint(POINT pt) { HWND WndParent,WndChild; WndParent = WindowFromPoint(pt); if(WndParent == NULL) return WndParent; ScreenToClient(WndParent, &pt); WndChild = RealChildWindowFromPoint(WndParent, pt); if(WndChild == NULL) return WndParent; return WndChild; }; static void SendWordToServer() { DWORD_PTR SendMsgAnswer; DWORD flags; LRESULT lr; if( !IsWindow( GlobalData->ServerWND ) ) return; // Ask for needing to retrieve word - WPARAM = 1 lr = SendMessageTimeout(GlobalData->ServerWND, WM_MY_SHOW_TRANSLATION, 1, 0, SMTO_ABORTIFHUNG, MOUSEOVER_INTERVAL, &SendMsgAnswer); if( lr == 0 || SendMsgAnswer == 0) //No answer or no needing return; flags = SendMsgAnswer; if (hGetWordLib == 0 && ( flags & GD_FLAG_METHOD_STANDARD ) ) { hGetWordLib = LoadLibraryW(GlobalData->LibName); if (hGetWordLib) { GetWordProc = (GetWordProc_t)GetProcAddress(hGetWordLib, "__gdGetWord"); } else { hGetWordLib = INVALID_HANDLE_VALUE; } } GlobalData->CurMod.MatchedWord[0] = 0; GlobalData->CurMod.WordLen = 0; GlobalData->CurMod.BeginPos = 0; if( ( flags & GD_FLAG_METHOD_GD_MESSAGE ) != 0 && uGdAskMessage != 0 ) { int n; gds.dwSize = sizeof(gds); gds.cwData = Buffer; gds.dwMaxLength = sizeof(Buffer) / sizeof(Buffer[0]); Buffer[0] = 0; gds.hWnd = GlobalData->LastWND; gds.Pt = GlobalData->LastPt; lr = SendMessageTimeout(gds.hWnd, uGdAskMessage, 0, (LPARAM)&gds, SMTO_ABORTIFHUNG, REQUEST_MESSAGE_INTERVAL, &SendMsgAnswer); if(lr != 0 && SendMsgAnswer != 0) { n = WideCharToMultiByte(CP_UTF8, 0, gds.cwData, lstrlenW(gds.cwData), GlobalData->CurMod.MatchedWord, sizeof(GlobalData->CurMod.MatchedWord) - 1, 0, 0); GlobalData->CurMod.MatchedWord[n] = 0; GlobalData->CurMod.WordLen = n; GlobalData->CurMod.BeginPos = 0; if(n > 0) { if( IsWindow( GlobalData->ServerWND ) ) { #ifdef __WIN64 GlobalData32->LastWND = HandleToLong( GlobalData->LastWND ); GlobalData32->CurMod.WordLen = n; GlobalData32->CurMod.BeginPos = 0; lstrcpyn( GlobalData32->CurMod.MatchedWord, GlobalData->CurMod.MatchedWord, sizeof( GlobalData32->CurMod.MatchedWord ) ); #endif SendMessageTimeout(GlobalData->ServerWND, WM_MY_SHOW_TRANSLATION, 0, 1, SMTO_ABORTIFHUNG, MOUSEOVER_INTERVAL, &SendMsgAnswer); } } return; } } // Don't use other methods for GD own windows if( winProcessID == gdProcessID ) return; if( ( flags & GD_FLAG_METHOD_STANDARD ) != 0 && GetWordProc != 0 ) { GlobalData->CurMod.WND = GlobalData->LastWND; GlobalData->CurMod.Pt = GlobalData->LastPt; LPARAM lparam = GetWordProc(&(GlobalData->CurMod)); // lparam == 0 - need to reverse RTL text, else don't reverse if (GlobalData->CurMod.WordLen > 0) { if( IsWindow( GlobalData->ServerWND ) ) { #ifdef __WIN64 GlobalData32->LastWND = HandleToLong( GlobalData->LastWND ); GlobalData32->CurMod.WordLen = GlobalData->CurMod.WordLen; GlobalData32->CurMod.BeginPos = GlobalData->CurMod.BeginPos; lstrcpyn( GlobalData32->CurMod.MatchedWord, GlobalData->CurMod.MatchedWord, sizeof( GlobalData32->CurMod.MatchedWord ) ); #endif SendMessageTimeout(GlobalData->ServerWND, WM_MY_SHOW_TRANSLATION, 0, lparam, SMTO_ABORTIFHUNG, MOUSEOVER_INTERVAL, &SendMsgAnswer); } return; } } if( ( flags & GD_FLAG_METHOD_IACCESSIBLEEX ) != 0 ) { getWordByAccEx( GlobalData->LastPt ); if (GlobalData->CurMod.WordLen > 0 ) { if( IsWindow( GlobalData->ServerWND ) ) { #ifdef __WIN64 GlobalData32->LastWND = HandleToLong( GlobalData->LastWND ); GlobalData32->CurMod.WordLen = GlobalData->CurMod.WordLen; GlobalData32->CurMod.BeginPos = GlobalData->CurMod.BeginPos; lstrcpyn( GlobalData32->CurMod.MatchedWord, GlobalData->CurMod.MatchedWord, sizeof( GlobalData32->CurMod.MatchedWord ) ); #endif SendMessageTimeout(GlobalData->ServerWND, WM_MY_SHOW_TRANSLATION, 0, 1, SMTO_ABORTIFHUNG, MOUSEOVER_INTERVAL, &SendMsgAnswer); } return; } } if( ( flags & GD_FLAG_METHOD_UI_AUTOMATION ) != 0 && IsWindow( GlobalData->ServerWND ) ) { #ifdef __WIN64 GlobalData32->CurMod.MatchedWord[0] = 0; GlobalData32->CurMod.WordLen = 0; GlobalData32->CurMod.BeginPos = 0; GlobalData32->LastPt = GlobalData->LastPt; #endif PostMessage( GlobalData->ServerWND, WM_MY_SHOW_TRANSLATION, 0, 1 ); } } void CALLBACK TimerFunc(HWND hWnd,UINT nMsg,UINT_PTR nTimerid,DWORD dwTime) { (void) hWnd; (void) nMsg; (void) dwTime; DWORD wso; wso = WaitForSingleObject(hSynhroMutex, 0); if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) { KillTimer(0, nTimerid); TimerID = 0; while( 1 ) { POINT curPt; HWND targetWnd; winProcessID = 0; if( !GetCursorPos( &curPt ) ) break; if( GlobalData == NULL || GlobalData->LastPt.x != curPt.x || GlobalData->LastPt.y != curPt.y) break; if( ( targetWnd = GetWindowFromPoint( curPt ) ) == NULL ) break; if( GlobalData->LastWND != targetWnd ) break; GetWindowThreadProcessId( targetWnd, &winProcessID ); if( winProcessID != ourProcessID ) { char className[64]; if( !GetClassName( targetWnd, className, sizeof(className) ) ) break; if( lstrcmpi( className, "ConsoleWindowClass" ) != 0 ) break; } SendWordToServer(); break; } ReleaseMutex(hSynhroMutex); } } void HookProc( POINT *ppt ) { HWND WND; TCHAR wClassName[64]; DWORD winProcessID; WND = GetWindowFromPoint( *ppt ); if(WND == NULL) return; if ( !GetClassName(WND, wClassName, sizeof(wClassName) / sizeof(TCHAR)) ) return; GetWindowThreadProcessId( WND, &winProcessID ); if( winProcessID != ourProcessID && lstrcmpi( wClassName, _T("ConsoleWindowClass") ) != 0 ) return; if(TimerID && ( GlobalData->LastPt.x != ppt->x || GlobalData->LastPt.y != ppt->y ) ) { KillTimer(0, TimerID); TimerID = 0; } const char* DisableClasses[] = { "gdkWindowChild", "gdkWindowTemp", "Progman", "WorkerW", }; int i; for (i=0; i<4; i++) { if (lstrcmp(wClassName, DisableClasses[i])==0) break; } if (i<4) return; if(GlobalData->LastPt.x != ppt->x || GlobalData->LastPt.y != ppt->y || GlobalData->LastWND != WND ) { GlobalData->LastWND = WND; GlobalData->LastPt = *ppt; TimerID = SetTimer(0, TimerID, MOUSEOVER_INTERVAL, TimerFunc); } } #ifdef __WIN64 LRESULT CALLBACK GetMessageHookProc(int nCode, WPARAM wParam, LPARAM lParam) { PMSG pMsg; DWORD wso; if( nCode == HC_ACTION && wParam == PM_REMOVE ) { pMsg = (PMSG)lParam; if( pMsg && ( pMsg->message == WM_MOUSEMOVE || pMsg->message == WM_NCMOUSEMOVE ) ) { wso = WaitForSingleObject(hSynhroMutex, 0); if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) { POINT pt; pt.x = GET_X_LPARAM( pMsg->lParam ); pt.y = GET_Y_LPARAM( pMsg->lParam ); if( pMsg->message == WM_MOUSEMOVE && pMsg->hwnd != NULL ) ClientToScreen( pMsg->hwnd, &pt ); HookProc( &pt ); ReleaseMutex(hSynhroMutex); } } } return CallNextHookEx(GlobalData->g_hHook, nCode, wParam, lParam); } #else LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) { DWORD wso; if ( (nCode == HC_ACTION) && ((wParam == WM_MOUSEMOVE) || (wParam == WM_NCMOUSEMOVE)) ) { wso = WaitForSingleObject(hSynhroMutex, 0); if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) { HookProc( &(((PMOUSEHOOKSTRUCT)lParam)->pt) ); ReleaseMutex(hSynhroMutex); } } return CallNextHookEx(GlobalData->g_hHook, nCode, wParam, lParam); } #endif DLLIMPORT void ActivateTextOutSpying (int Activate) { // After call SetWindowsHookEx(), when you move mouse to a application's window, // this dll will load into this application automatically. And it is unloaded // after call UnhookWindowsHookEx(). if(GlobalData == NULL) return; if (Activate) { if (GlobalData->g_hHook != NULL) return; #ifdef __WIN64 GlobalData->g_hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMessageHookProc, g_hInstance, 0); #else GlobalData->g_hHook = SetWindowsHookEx(WH_MOUSE, MouseHookProc, g_hInstance, 0); #endif } else { if (GlobalData->g_hHook == NULL) return; WaitForSingleObject(hSynhroMutex, 2000); UnhookWindowsHookEx(GlobalData->g_hHook); if (TimerID) { KillTimer(0, TimerID); TimerID=0; } ReleaseMutex(hSynhroMutex); GlobalData->g_hHook = NULL; } } BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ , DWORD reason /* Reason this function is being called. */ , LPVOID reserved /* Not used. */ ) { (void) reserved; switch (reason) { case DLL_PROCESS_ATTACH: g_hInstance = hInst; ThTypes_Init(); #ifdef __WIN64 if( GlobalData == NULL || GlobalData32 == NULL ) { #else if( GlobalData == NULL ) { #endif ThTypes_End(); return FALSE; } ourProcessID = GetCurrentProcessId(); GetWindowThreadProcessId( GlobalData->ServerWND, &gdProcessID ); if(hSynhroMutex==0) { hSynhroMutex = CreateMutex(NULL, FALSE, "GoldenDictTextOutSpyMutex"); if(hSynhroMutex==0) { return(FALSE); } } uGdAskMessage = RegisterWindowMessage(GD_MESSAGE_NAME); FindGetPhysicalCursorPos(); break; case DLL_PROCESS_DETACH: // if(hSynhroMutex) WaitForSingleObject(hSynhroMutex, INFINITE); if(hSynhroMutex) WaitForSingleObject(hSynhroMutex, 2000); if (TimerID) { KillTimer(0, TimerID); TimerID=0; } if(hSynhroMutex) { ReleaseMutex(hSynhroMutex); CloseHandle(hSynhroMutex); hSynhroMutex=0; } { MSG msg ; while (PeekMessage (&msg, 0, WM_TIMER, WM_TIMER, PM_REMOVE)); } if ( (hGetWordLib != 0) && (hGetWordLib != INVALID_HANDLE_VALUE) ) { FreeLibrary(hGetWordLib); } ThTypes_End(); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; } /* Returns TRUE on success, FALSE on failure */ return TRUE; }