19/03/2006 | jiangws2002 http://reciteword.cosoft.org.cn/yaoguang/showarticle.php?category=myarticle&&docpage=0&&newsid=24 星际译王(StarDict)的2.4.6版新增加了Windows下屏幕取词的功能。在开发这个功能时参考了Mueller Electronic Dicionary(一个用Delphi编的词典软件)的源代码,以及网上的文档。开发语言是C,用Dev-cpp编译。 这个功能现在还不太完善,目前有以下问题: 1. 在Win2k系统下,对桌面上的英文取词时为乱码。Windows XP则没有问题。 2. 在标题栏,开始菜单及IE, FireFox, Opear等软件上取词时,获取的Y坐标值不正确。见源码包里的src/win32/TextOutHook.c的IsInsidePointW()里的注释。 3. cmd.exe(命令提示符)无法取词。见源码包里的src/win32/GetWord.c的RemoteExecute()里的注释。 4. Adobe Reader无法取词。可能要像金山词霸那样编个Adobe Reader的插件。 希望高手能帮忙解决。 现在把完整源代码贴到这里: TextOutSpy.c ============================= #include “TextOutSpy.h” #include “ThTypes.h” const int MOUSEOVER_INTERVAL = 300; const int WM_MY_SHOW_TRANSLATION = WM_USER + 300; HINSTANCE g_hInstance = NULL; HANDLE hSynhroMutex = 0; HINSTANCE hGetWordLib = 0; typedef void (*GetWordProc_t)(TCurrentMode *); GetWordProc_t GetWordProc = NULL; static void SendWordToServer() { if (hGetWordLib == 0) { hGetWordLib = LoadLibrary(GlobalData->LibName); if (hGetWordLib) { GetWordProc = (GetWordProc_t)GetProcAddress(hGetWordLib, “GetWord”); } else { hGetWordLib = (HINSTANCE)-1; } } if (GetWordProc) { GlobalData->CurMod.WND = GlobalData->LastWND; GlobalData->CurMod.Pt = GlobalData->LastPt; GetWordProc(&(GlobalData->CurMod)); if (GlobalData->CurMod.WordLen > 0) { DWORD SendMsgAnswer; SendMessageTimeout(GlobalData->ServerWND, WM_MY_SHOW_TRANSLATION, 0, 0, SMTO_ABORTIFHUNG, MOUSEOVER_INTERVAL, &SendMsgAnswer); } } } void CALLBACK TimerFunc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime) { if (WaitForSingleObject(hSynhroMutex, 0) == WAIT_OBJECT_0) { if (GlobalData->TimerID) { if (KillTimer(0, GlobalData->TimerID)) GlobalData->TimerID=0; } ReleaseMutex(hSynhroMutex); } if ((GlobalData->LastWND!=0)&&(GlobalData->LastWND == WindowFromPoint(GlobalData->LastPt))) { if (WaitForSingleObject(hSynhroMutex, 0) == WAIT_OBJECT_0) { SendWordToServer(); ReleaseMutex(hSynhroMutex); } } } LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) { if ((nCode == HC_ACTION) && ((wParam == WM_MOUSEMOVE) || (wParam == WM_NCMOUSEMOVE))) { if (WaitForSingleObject(hSynhroMutex, 0) == WAIT_OBJECT_0) { if (GlobalData->TimerID) { if (KillTimer(0, GlobalData->TimerID)) GlobalData->TimerID=0; } HWND WND = WindowFromPoint(((PMOUSEHOOKSTRUCT)lParam)->pt); TCHAR wClassName[64]; if (GetClassName(WND, wClassName, sizeof(wClassName) / sizeof(TCHAR))) { const char* DisableClasses[] = { “gdkWindowChild”, “gdkWindowTemp”, }; int i; for (i=0; ig_hHookMouse, nCode, wParam, lParam); } } GlobalData->TimerID = SetTimer(0, 0, MOUSEOVER_INTERVAL, TimerFunc); GlobalData->LastWND = WND; GlobalData->LastPt = ((PMOUSEHOOKSTRUCT)lParam)->pt; ReleaseMutex(hSynhroMutex); } } return CallNextHookEx(GlobalData->g_hHookMouse, nCode, wParam, lParam); } 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 (Activate) { if (GlobalData->g_hHookMouse != NULL) return; GlobalData->g_hHookMouse = SetWindowsHookEx(WH_MOUSE, MouseHookProc, g_hInstance, 0); } else { if (GlobalData->g_hHookMouse == NULL) return; if (WaitForSingleObject(hSynhroMutex, 0) == WAIT_OBJECT_0) { if (GlobalData->TimerID) { if (KillTimer(0, GlobalData->TimerID)) GlobalData->TimerID=0; } ReleaseMutex(hSynhroMutex); } UnhookWindowsHookEx(GlobalData->g_hHookMouse); GlobalData->g_hHookMouse = NULL; } } BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ , DWORD reason /* Reason this function is being called. */ , LPVOID reserved /* Not used. */ ) { switch (reason) { case DLL_PROCESS_ATTACH: g_hInstance = hInst; hSynhroMutex = CreateMutex(NULL, FALSE, “StarDictTextOutSpyMutex”); ThTypes_Init(); break; case DLL_PROCESS_DETACH: WaitForSingleObject(hSynhroMutex, INFINITE); if (GlobalData->TimerID) { if (KillTimer(0, GlobalData->TimerID)) GlobalData->TimerID=0; } ReleaseMutex(hSynhroMutex); CloseHandle(hSynhroMutex); { MSG msg ; while (PeekMessage (&msg, 0, WM_TIMER, WM_TIMER, PM_REMOVE)) {} } if ((hGetWordLib != 0)&&(hGetWordLib != (HINSTANCE)(-1))) { FreeLibrary(hGetWordLib); } Thtypes_End(); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; } /* Returns TRUE on success, FALSE on failure */ return TRUE; } ============================= TextOutSpy.h ============================= #ifndef _TextOutSpy_H_ #define _TextOutSpy_H_ #if BUILDING_DLL # define DLLIMPORT __declspec (dllexport) #else /* Not BUILDING_DLL */ # define DLLIMPORT __declspec (dllimport) #endif /* Not BUILDING_DLL */ DLLIMPORT void ActivateTextOutSpying (int Activate); #endif /* _TextOutSpy_H_ */ ============================= ThTypes.c ============================= #include “ThTypes.h” HANDLE MMFHandle = 0; TGlobalDLLData *GlobalData = NULL; void ThTypes_Init() { if (!MMFHandle) MMFHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(TGlobalDLLData), “StarDictTextOutHookSharedMem”); if (!GlobalData) GlobalData = MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0); } void Thtypes_End() { if (GlobalData) { UnmapViewOfFile(GlobalData); GlobalData = NULL; } if (MMFHandle) { CloseHandle(MMFHandle); MMFHandle = 0; } } ============================= ThTypes.h ============================= #ifndef _ThTypes_H_ #define _ThTypes_H_ #include #ifdef __cplusplus extern “C” { #endif /* __cplusplus */ typedef struct TCurrentMode { HWND WND; POINT Pt; int WordLen; char MatchedWord[256]; int BeginPos; } TCurrentMode; typedef struct TGlobalDLLData { HWND ServerWND; HHOOK g_hHookMouse; DWORD TimerID; HWND LastWND; POINT LastPt; TCurrentMode CurMod; char LibName[256]; } TGlobalDLLData; extern TGlobalDLLData *GlobalData; void ThTypes_Init(); void Thtypes_End(); #ifdef __cplusplus } #endif /* __cplusplus */ #endif ============================= TextOutHook.c ============================= #include “TextOutHook.h” #include “GetWord.h” #include “HookImportFunction.h” typedef BOOL WINAPI (*TextOutANextHook_t)(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString,int cbString); TextOutANextHook_t TextOutANextHook = NULL; typedef BOOL WINAPI (*TextOutWNextHook_t)(HDC hdc, int nXStart, int nYStart, LPCWSTR lpszString,int cbString); TextOutWNextHook_t TextOutWNextHook = NULL; typedef BOOL WINAPI (*ExtTextOutANextHook_t)(HDC hdc, int nXStart, int nYStart, UINT fuOptions, CONST RECT *lprc, LPCSTR lpszString, UINT cbString, CONST INT *lpDx); ExtTextOutANextHook_t ExtTextOutANextHook = NULL; typedef BOOL WINAPI (*ExtTextOutWNextHook_t)(HDC hdc, int nXStart, int nYStart, UINT fuOptions, CONST RECT *lprc, LPCWSTR lpszString, UINT cbString, CONST INT *lpDx); ExtTextOutWNextHook_t ExtTextOutWNextHook = NULL; typedef struct TEverythingParams { HWND WND; POINT Pt; int Active; int WordLen; int Unicode; int BeginPos; char MatchedWordA[256]; wchar_t MatchedWordW[256]; } TEverythingParams; TEverythingParams *CurParams = NULL; static void ConvertToMatchedWordA(TEverythingParams *TP) { if (TP->Unicode) { if (TP->WordLen>0) { int BeginPos = TP->BeginPos; TP->BeginPos = WideCharToMultiByte(CP_ACP, 0, TP->MatchedWordW, BeginPos, TP->MatchedWordA, sizeof(TP->MatchedWordA)-1, NULL, NULL); TP->WordLen = WideCharToMultiByte(CP_ACP, 0, TP->MatchedWordW + BeginPos, TP->WordLen - BeginPos, TP->MatchedWordA + TP->BeginPos, sizeof(TP->MatchedWordA)-1 - TP->BeginPos, NULL, NULL); TP->WordLen += TP->BeginPos; TP->MatchedWordA[TP->WordLen] = ‘