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; i<2; i++) {
if (strcmp(wClassName, DisableClasses[i])==0)
break;
}
if (i<2) {
ReleaseMutex(hSynhroMutex);
return CallNextHookEx(GlobalData->g_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 <windows.h>
#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 (*Tex
星际译王(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; i<2; i++) {
if (strcmp(wClassName, DisableClasses[i])==0)
break;
}
if (i<2) {
ReleaseMutex(hSynhroMutex);
return CallNextHookEx(GlobalData->g_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 <windows.h>
#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 (*Tex