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] = ‘