Win32-specific mouseover dll sources added, taken directly from StarDict

codebase with minimal modifications.
This commit is contained in:
Konstantin Isakov 2009-02-02 19:26:39 +00:00
parent 1a5a4daa52
commit 18b355cda3
12 changed files with 1071 additions and 0 deletions

View file

@ -0,0 +1,244 @@
#include "GetWord.h"
#include "TextOutHook.h"
TKnownWndClass GetWindowType(HWND WND, const char* WNDClass)
{
const char* StrKnownClasses[] = {
"RICHEDIT20A",
"RICHEDIT20W",
"RICHEDIT",
"EDIT",
"INTERNET EXPLORER_SERVER",
"CONSOLEWINDOWCLASS", // NT
"TTYGRAB", // 9x
};
TKnownWndClass KnownClasses[] = {
kwcRichEdit,
kwcRichEdit,
kwcRichEdit,
kwcMultiLineEdit,
kwcInternetExplorer_Server,
kwcConsole,
kwcConsole,
};
int i;
for (i=0; i<7; i++) {
if (_stricmp(WNDClass, StrKnownClasses[i])==0)
break;
}
if (i<7) {
if (KnownClasses[i] == kwcMultiLineEdit) {
if ((GetWindowLong(WND, GWL_STYLE) & ES_MULTILINE) == 0)
return kwcSingleLineEdit;
}
return KnownClasses[i];
} else
return kwcUnknown;
}
static char* ExtractWordFromRichEditPos(HWND WND, POINT Pt, int *BeginPos)
{
return ExtractFromEverything(WND, Pt, BeginPos);
}
/*
typedef struct TEditParams {
HWND WND;
POINT Pt;
char Buffer[256];
} TEditParams;
static int ExtractWordFromEditPosPack(TEditParams *params)
{
int Result = 0;
int BegPos;
BegPos = SendMessage(params->WND, EM_CHARFROMPOS, 0, params->Pt.x | params->Pt.y << 16);
if (BegPos == -1)
return Result;
int MaxLength;
MaxLength = SendMessage(params->WND, EM_LINELENGTH, BegPos & 0xFFFF, 0);
if (MaxLength <= 0)
return Result;
char *Buf;
Buf = GlobalAlloc(GMEM_FIXED, MaxLength + 1);
if (Buf) {
*Buf = MaxLength;
MaxLength = SendMessage(params->WND, EM_GETLINE, BegPos >> 16, (int)Buf);
Buf[MaxLength] = '\0';
BegPos = (BegPos & 0xFFFF) - SendMessage(params->WND, EM_LINEINDEX, BegPos >> 16, 0) - 1;
int EndPos;
EndPos = BegPos;
while ((BegPos >= 0) && IsCharAlpha(Buf[BegPos]))
BegPos--;
while ((EndPos < MaxLength) && IsCharAlpha(Buf[EndPos]))
EndPos++;
MaxLength = EndPos - BegPos - 1;
if (MaxLength >= 0) {
if (255 >= MaxLength) {
Buf[EndPos] = '\0';
lstrcpy(params->Buffer, Buf + BegPos + 1);
Result = MaxLength;
}
}
GlobalFree(Buf);
}
return Result;
}
*/
static char* ExtractWordFromEditPos(HWND hEdit, POINT Pt, int *BeginPos)
{
return ExtractFromEverything(hEdit, Pt, BeginPos);
/* TEditParams *TP;
TP = malloc(sizeof(TEditParams));
TP->WND = hEdit;
TP->Pt = Pt;
TP->Buffer[0] = '\0';
ScreenToClient(hEdit, &(TP->Pt));
int MaxLength;
MaxLength = ExtractWordFromEditPosPack(TP);
char *Result;
if (MaxLength>0) {
Result = strdup(TP->Buffer);
} else {
Result = NULL;
}
free(TP);
return Result;
*/
}
static char* ExtractWordFromIE(HWND WND, POINT Pt, int *BeginPos)
{
return ExtractFromEverything(WND, Pt, BeginPos);
}
typedef struct TConsoleParams {
HWND WND;
POINT Pt;
RECT ClientRect;
char Buffer[256];
} TConsoleParams;
static int GetWordFromConsolePack(TConsoleParams *params)
{
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdOut != INVALID_HANDLE_VALUE) {
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (GetConsoleScreenBufferInfo(hStdOut, &csbi)) {
COORD CurPos;
CurPos.X = csbi.srWindow.Left + (SHORT)(params->Pt.x * (csbi.srWindow.Right - csbi.srWindow.Left + 1) / params->ClientRect.right);
CurPos.Y = csbi.srWindow.Top + (SHORT)(params->Pt.y * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1) / params->ClientRect.bottom);
if ((CurPos.X >= 0) && (CurPos.X <= csbi.dwSize.X - 1) && (CurPos.Y >= 0) && (CurPos.Y <= csbi.dwSize.Y - 1)) {
int BegPos;
char *Buf;
BegPos = CurPos.X;
CurPos.X = 0;
Buf = GlobalAlloc(GMEM_FIXED, csbi.dwSize.X + 1);
if (Buf) {
DWORD ActualRead;
if ((ReadConsoleOutputCharacter(hStdOut, Buf, csbi.dwSize.X, CurPos, &ActualRead)) && (ActualRead == csbi.dwSize.X)) {
int WordLen;
OemToCharBuff(Buf, Buf, csbi.dwSize.X);
if (csbi.dwSize.X > 255)
WordLen = 255;
else
WordLen = csbi.dwSize.X;
strncpy(params->Buffer, Buf, WordLen);
GlobalFree(Buf);
return WordLen;
}
}
}
}
}
return 0;
}
static void GetWordFromConsolePackEnd() {}
static BOOL RemoteExecute(HANDLE hProcess, void *RemoteThread, size_t RemoteSize, void *Data, int DataSize, DWORD *dwReturn)
{
void *pRemoteThread = VirtualAllocEx(hProcess, NULL, RemoteSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
void *pData;
HANDLE hThread;
if (!pRemoteThread)
return FALSE;
if (!WriteProcessMemory(hProcess, pRemoteThread, RemoteThread, RemoteSize, 0)) {
VirtualFreeEx(hProcess, pRemoteThread, RemoteSize, MEM_RELEASE);
return FALSE;
}
pData = VirtualAllocEx(hProcess, NULL, DataSize, MEM_COMMIT, PAGE_READWRITE);
if (!pData) {
VirtualFreeEx(hProcess, pRemoteThread, RemoteSize, MEM_RELEASE);
return FALSE;
}
if (!WriteProcessMemory(hProcess, pData, Data, DataSize, 0)) {
VirtualFreeEx(hProcess, pRemoteThread, RemoteSize, MEM_RELEASE);
VirtualFreeEx(hProcess, pData, DataSize, MEM_RELEASE);
return FALSE;
}
// Bug: I don't know why the next line will fail in Windows XP, so get word from cmd.exe can't work presently.
hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)pRemoteThread, pData, 0, 0);
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, dwReturn);
ReadProcessMemory(hProcess, pData, Data, DataSize, 0);
VirtualFreeEx(hProcess, pRemoteThread, RemoteSize, MEM_RELEASE);
VirtualFreeEx(hProcess, pData, DataSize, MEM_RELEASE);
if (hThread) {
CloseHandle(hThread);
return TRUE;
} else {
return FALSE;
}
}
static char* GetWordFromConsole(HWND WND, POINT Pt, int *BeginPos)
{
TConsoleParams *TP;
DWORD pid;
DWORD MaxWordSize;
char *Result;
TP = malloc(sizeof(TConsoleParams));
TP->WND = WND;
TP->Pt = Pt;
ScreenToClient(WND, &(TP->Pt));
GetClientRect(WND, &(TP->ClientRect));
GetWindowThreadProcessId(GetParent(WND), &pid);
if (pid != GetCurrentProcessId()) {
// The next line will fail in Win2k, but OK in Windows XP.
HANDLE ph = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pid);
if (ph) {
if (!RemoteExecute(ph, GetWordFromConsolePack, (size_t)GetWordFromConsolePackEnd - (size_t)GetWordFromConsolePack, TP, sizeof(TConsoleParams), &MaxWordSize))
MaxWordSize = 0;
CloseHandle(ph);
}
} else {
MaxWordSize = GetWordFromConsolePack(TP);
}
if (MaxWordSize > 0) {
Result = _strdup(TP->Buffer);
} else {
Result = NULL;
}
free(TP);
return Result;
}
char* TryGetWordFromAnyWindow(TKnownWndClass WndType, HWND WND, POINT Pt, int *BeginPos)
{
typedef char* (*GetWordFunction_t)(HWND, POINT, int*);
const GetWordFunction_t GetWordFunction[]= {
ExtractFromEverything,
ExtractWordFromRichEditPos,
ExtractWordFromEditPos,
ExtractWordFromEditPos,
ExtractWordFromIE,
GetWordFromConsole,
};
return GetWordFunction[WndType](WND, Pt, BeginPos);
}

View file

@ -0,0 +1,18 @@
#ifndef _GetWord_H_
#define _GetWord_H_
#include <windows.h>
typedef enum TKnownWndClass {
kwcUnknown,
kwcRichEdit,
kwcMultiLineEdit,
kwcSingleLineEdit,
kwcInternetExplorer_Server,
kwcConsole,
} TKnownWndClass;
TKnownWndClass GetWindowType(HWND WND, const char* WNDClass);
char* TryGetWordFromAnyWindow(TKnownWndClass WndType, HWND WND, POINT Pt, int *BeginPos);
#endif

View file

@ -0,0 +1,122 @@
#include "HookImportFunction.h"
#include <tlhelp32.h>
// These code come from: http://dev.csdn.net/article/2/2786.shtm
// I fixed a bug in it and improved it to hook all the modules of a program.
#define MakePtr(cast, ptr, AddValue) (cast)((size_t)(ptr)+(size_t)(AddValue))
static PIMAGE_IMPORT_DESCRIPTOR GetNamedImportDescriptor(HMODULE hModule, LPCSTR szImportModule)
{
PIMAGE_DOS_HEADER pDOSHeader;
PIMAGE_NT_HEADERS pNTHeader;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
if ((szImportModule == NULL) || (hModule == NULL))
return NULL;
pDOSHeader = (PIMAGE_DOS_HEADER) hModule;
if (IsBadReadPtr(pDOSHeader, sizeof(IMAGE_DOS_HEADER)) || (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)) {
return NULL;
}
pNTHeader = MakePtr(PIMAGE_NT_HEADERS, pDOSHeader, pDOSHeader->e_lfanew);
if (IsBadReadPtr(pNTHeader, sizeof(IMAGE_NT_HEADERS)) || (pNTHeader->Signature != IMAGE_NT_SIGNATURE))
return NULL;
if (pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)
return NULL;
pImportDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, pDOSHeader, pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while (pImportDesc->Name) {
PSTR szCurrMod = MakePtr(PSTR, pDOSHeader, pImportDesc->Name);
if (_stricmp(szCurrMod, szImportModule) == 0)
break;
pImportDesc++;
}
if (pImportDesc->Name == (DWORD)0)
return NULL;
return pImportDesc;
}
static BOOL IsNT()
{
OSVERSIONINFO stOSVI;
BOOL bRet;
memset(&stOSVI, 0, sizeof(OSVERSIONINFO));
stOSVI.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
bRet = GetVersionEx(&stOSVI);
if (FALSE == bRet) return FALSE;
return (VER_PLATFORM_WIN32_NT == stOSVI.dwPlatformId);
}
static BOOL HookImportFunction(HMODULE hModule, LPCSTR szImportModule, LPCSTR szFunc, PROC paHookFuncs, PROC* paOrigFuncs)
{
PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
PIMAGE_THUNK_DATA pOrigThunk;
PIMAGE_THUNK_DATA pRealThunk;
if (!IsNT() && ((size_t)hModule >= 0x80000000))
return FALSE;
pImportDesc = GetNamedImportDescriptor(hModule, szImportModule);
if (pImportDesc == NULL)
return FALSE;
pOrigThunk = MakePtr(PIMAGE_THUNK_DATA, hModule, pImportDesc->OriginalFirstThunk);
pRealThunk = MakePtr(PIMAGE_THUNK_DATA, hModule, pImportDesc->FirstThunk);
while (pOrigThunk->u1.Function) {
if (IMAGE_ORDINAL_FLAG != (pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)) {
PIMAGE_IMPORT_BY_NAME pByName = MakePtr(PIMAGE_IMPORT_BY_NAME, hModule, pOrigThunk->u1.AddressOfData);
BOOL bDoHook;
// When hook EditPlus, read pByName->Name[0] will case this dll terminate, so call IsBadReadPtr() here.
if (IsBadReadPtr(pByName, sizeof(IMAGE_IMPORT_BY_NAME))) {
pOrigThunk++;
pRealThunk++;
continue;
}
if ('\0' == pByName->Name[0]) {
pOrigThunk++;
pRealThunk++;
continue;
}
bDoHook = FALSE;
if ((szFunc[0] == pByName->Name[0]) && (_strcmpi(szFunc, (char*)pByName->Name) == 0)) {
if (paHookFuncs)
bDoHook = TRUE;
}
if (bDoHook) {
MEMORY_BASIC_INFORMATION mbi_thunk;
DWORD dwOldProtect;
VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION));
VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect);
if (paOrigFuncs)
*paOrigFuncs = (PROC)pRealThunk->u1.Function;
pRealThunk->u1.Function = (DWORD)paHookFuncs;
VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, mbi_thunk.Protect, &dwOldProtect);
return TRUE;
}
}
pOrigThunk++;
pRealThunk++;
}
return FALSE;
}
BOOL HookAPI(LPCSTR szImportModule, LPCSTR szFunc, PROC paHookFuncs, PROC* paOrigFuncs)
{
HANDLE hSnapshot;
MODULEENTRY32 me = {sizeof(MODULEENTRY32)};
BOOL bOk;
if ((szImportModule == NULL) || (szFunc == NULL)) {
return FALSE;
}
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0);
bOk = Module32First(hSnapshot,&me);
while (bOk) {
HookImportFunction(me.hModule, szImportModule, szFunc, paHookFuncs, paOrigFuncs);
bOk = Module32Next(hSnapshot,&me);
}
return TRUE;
}

View file

@ -0,0 +1,9 @@
#ifndef _HookImportFunction_H_
#define _HookImportFunction_H_
#include <windows.h>
BOOL HookAPI(LPCSTR szImportModule, LPCSTR szFunc, PROC paHookFuncs, PROC* paOrigFuncs);
#endif

View file

@ -0,0 +1,29 @@
GCC:=i586-mingw32msvc-gcc -W -Wall
.PHONY: all clean
all: GdTextOutHook.dll libGdTextOutHook.a GdTextOutSpy.dll libGdTextOutSpy.a
clean:
rm -f *.o *.a *.dll
TextOutHook.o: TextOutHook.c
$(GCC) -DBUILDING_DLL -c $<
HookImportFunction.o: HookImportFunction.c
$(GCC) -c $<
GetWord.o: GetWord.c
$(GCC) -c $<
GdTextOutHook.dll libGdTextOutHook.a: TextOutHook.o HookImportFunction.o GetWord.o
$(GCC) -shared -o GdTextOutHook.dll $^ -lgdi32 -Wl,--out-implib,libGdTextOutHook.a
TextOutSpy.o: TextOutSpy.c
$(GCC) -DBUILDING_DLL -c $<
ThTypes.o: ThTypes.c
$(GCC) -c $<
GdTextOutSpy.dll libGdTextOutSpy.a: TextOutSpy.o ThTypes.o
$(GCC) -shared -o GdTextOutSpy.dll $^ -lgdi32 -Wl,--out-implib,libGdTextOutSpy.a

View file

@ -0,0 +1,395 @@
#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->WordLen>0) {
int BeginPos;
if (!TP->Unicode) {
BeginPos = TP->BeginPos;
if (BeginPos) {
TP->BeginPos = MultiByteToWideChar(CP_ACP, 0, TP->MatchedWordA, BeginPos, TP->MatchedWordW, sizeof(TP->MatchedWordW)/sizeof(TP->MatchedWordW[0]) - 1);
if (TP->BeginPos == 0) {
TP->WordLen=0;
TP->MatchedWordA[0] = '\0';
return;
}
}
TP->WordLen = MultiByteToWideChar(CP_ACP, 0, TP->MatchedWordA + BeginPos, TP->WordLen - BeginPos, TP->MatchedWordW + TP->BeginPos, sizeof(TP->MatchedWordW)/sizeof(TP->MatchedWordW[0]) - 1 - TP->BeginPos);
if (TP->WordLen == 0) {
TP->WordLen=TP->BeginPos;
TP->MatchedWordA[TP->WordLen] = '\0';
return;
}
TP->WordLen += TP->BeginPos;
}
BeginPos = TP->BeginPos;
if (BeginPos) {
wchar_t temp = TP->MatchedWordW[BeginPos];
TP->MatchedWordW[BeginPos] = 0;
TP->BeginPos = WideCharToMultiByte(CP_UTF8, 0, TP->MatchedWordW, BeginPos + 1, TP->MatchedWordA, sizeof(TP->MatchedWordA), NULL, NULL);
TP->MatchedWordW[BeginPos] = temp;
TP->BeginPos--;
if (TP->BeginPos<=0) {
TP->WordLen=0;
TP->MatchedWordA[0] = '\0';
return;
} else if (TP->BeginPos == sizeof(TP->MatchedWordA)-1) {
TP->WordLen=sizeof(TP->MatchedWordA)-1;
TP->MatchedWordA[sizeof(TP->MatchedWordA)-1] = '\0';
return;
}
}
TP->MatchedWordW[TP->WordLen] = 0;
TP->WordLen = WideCharToMultiByte(CP_UTF8, 0, TP->MatchedWordW + BeginPos, TP->WordLen - BeginPos + 1, TP->MatchedWordA + TP->BeginPos, sizeof(TP->MatchedWordA) - TP->BeginPos, NULL, NULL);
TP->WordLen--;
if (TP->WordLen<=0) {
TP->WordLen=TP->BeginPos;
TP->MatchedWordA[TP->WordLen] = '\0';
return;
}
TP->WordLen += TP->BeginPos;
TP->MatchedWordA[TP->WordLen] = '\0';
} else {
TP->MatchedWordA[0] = '\0';
}
}
static int MyCopyMemory(char *a, const char *b, int len)
{
int count = 0;
int i;
for (i=0; i<len; i++) {
if (*b != '&') {
count++;
*a = *b;
a++;
}
b++;
}
return count;
}
static void IterateThroughItems(HWND WND, HMENU menu, POINT *p)
{
int count = GetMenuItemCount(menu);
RECT rec;
MENUITEMINFO info;
int i;
for (i=0; i<count; i++) {
if (GetMenuItemRect(WND, menu, i, &rec) && (rec.left<=p->x) && (p->x<=rec.right) && (rec.top<=p->y) && (p->y<=rec.bottom)) {
ZeroMemory(&info, sizeof(info));
info.cbSize = sizeof(info);
info.fMask = MIIM_TYPE | MIIM_SUBMENU;
info.cch = 256;
info.dwTypeData = malloc(256);
GetMenuItemInfo(menu, i, TRUE, &info);
if (info.cch>0) {
if (info.cch > 255)
CurParams->WordLen = 255;
else
CurParams->WordLen = info.cch;
CurParams->Unicode = FALSE;
CurParams->WordLen = MyCopyMemory(CurParams->MatchedWordA, info.dwTypeData, CurParams->WordLen);
CurParams->BeginPos = 0;
}
free(info.dwTypeData);
break;
}
}
}
static void GetWordTextOutHook (TEverythingParams *TP)
{
CurParams = TP;
ScreenToClient(TP->WND, &(TP->Pt));
if (TP->Pt.y<0) {
char buffer[256];
HMENU menu;
char buffer2[256];
GetWindowText(TP->WND, buffer, sizeof(buffer)-1);
SetWindowText(TP->WND, "");
GetWindowText(TP->WND, buffer2, sizeof(buffer2)-1);
if (buffer2[0]) { // MDI window.
char *p = strstr(buffer, buffer2);
if (p) {
if (p == buffer) { // FWS_PREFIXTITLE
strcpy(buffer, buffer+strlen(buffer2));
} else {
*p = '\0';
}
}
}
CurParams->Active = TRUE;
SetWindowText(TP->WND, buffer);
CurParams->Active = FALSE;
menu = GetMenu(TP->WND);
if (menu) {
ClientToScreen(TP->WND, &(TP->Pt));
IterateThroughItems(TP->WND, menu, &(TP->Pt));
}
}
else {
RECT UpdateRect;
GetClientRect(TP->WND, &UpdateRect);
UpdateRect.top = TP->Pt.y;
UpdateRect.bottom = TP->Pt.y + 1;
CurParams->Active = TRUE;
InvalidateRect(TP->WND, &UpdateRect, FALSE);
UpdateWindow(TP->WND);
CurParams->Active = FALSE;
}
CurParams = NULL;
}
char* ExtractFromEverything(HWND WND, POINT Pt, int *BeginPos)
{
TEverythingParams CParams;
ZeroMemory(&CParams, sizeof(CParams));
CParams.WND = WND;
CParams.Pt = Pt;
GetWordTextOutHook(&CParams);
ConvertToMatchedWordA(&CParams);
*BeginPos = CParams.BeginPos;
return _strdup(CParams.MatchedWordA);
}
static void IsInsidePointA(const HDC DC, int X, int Y, LPCSTR Str, int Count)
{
SIZE Size;
if ((Count > 0) && GetTextExtentPoint32A(DC, Str, Count, &Size)) {
DWORD Flags = GetTextAlign(DC);
POINT Pt;
RECT Rect;
if (Flags & TA_UPDATECP) {
GetCurrentPositionEx(DC, &Pt);
} else {
Pt.x = X;
Pt.y = Y;
}
if (Flags & TA_CENTER) {
Pt.x-=(Size.cx/2);
} else if (Flags & TA_RIGHT) {
Pt.x-=Size.cx;
}
if (Flags & TA_BASELINE) {
TEXTMETRIC tm;
GetTextMetricsA(DC, &tm);
Pt.y-=tm.tmAscent;
} else if (Flags & TA_BOTTOM) {
Pt.y-=Size.cy;
}
LPtoDP(DC, &Pt, 1);
Rect.left = Pt.x;
Rect.right = Pt.x + Size.cx;
Rect.top = Pt.y;
Rect.bottom = Pt.y + Size.cy;
if (((Rect.left <= Rect.right) && (CurParams->Pt.x >= Rect.left) && (CurParams->Pt.x <= Rect.right)) ||
((Rect.left > Rect.right) && (CurParams->Pt.x <= Rect.left) && (CurParams->Pt.x >= Rect.right))) {
int BegPos;
//if (PtInRect(&Rect, CurParams->Pt)) {
CurParams->Active = !PtInRect(&Rect, CurParams->Pt);
//CurParams->Active = FALSE;
BegPos = (int)((abs((CurParams->Pt.x - Rect.left) / (Rect.right - Rect.left)) * (Count - 1)) + 0.5);
while ((BegPos < Count - 1) && GetTextExtentPoint32A(DC, Str, BegPos + 1, &Size) && (Size.cx < CurParams->Pt.x - Rect.left))
BegPos++;
while ((BegPos >= 0) && GetTextExtentPoint32A(DC, Str, BegPos + 1, &Size) && (Size.cx > CurParams->Pt.x - Rect.left))
BegPos--;
if (BegPos < Count - 1)
BegPos++;
CurParams->BeginPos = BegPos;
if (Count > 255)
CurParams->WordLen = 255;
else
CurParams->WordLen = Count;
CurParams->Unicode = FALSE;
CopyMemory(CurParams->MatchedWordA, Str, CurParams->WordLen);
}
}
}
static void IsInsidePointW(const HDC DC, int X, int Y, LPCWSTR Str, int Count)
{
SIZE Size;
if ((Count > 0) && GetTextExtentPoint32W(DC, Str, Count, &Size)) {
DWORD Flags = GetTextAlign(DC);
POINT Pt;
RECT Rect;
if (Flags & TA_UPDATECP) {
GetCurrentPositionEx(DC, &Pt);
} else {
Pt.x = X;
Pt.y = Y;
}
if (Flags & TA_CENTER) {
Pt.x-=(Size.cx/2);
} else if (Flags & TA_RIGHT) {
Pt.x-=Size.cx;
}
if (Flags & TA_BASELINE) {
TEXTMETRICW tm;
GetTextMetricsW(DC, &tm);
Pt.y-=tm.tmAscent;
} else if (Flags & TA_BOTTOM) {
Pt.y-=Size.cy;
}
LPtoDP(DC, &Pt, 1);
Rect.left = Pt.x;
Rect.right = Pt.x + Size.cx;
Rect.top = Pt.y;
Rect.bottom = Pt.y + Size.cy;
// Bug: We don't check Pt.y here, as don't call PtInRect() directly, because
// in Title bar, Start Menu, IE, FireFox, Opera etc., the Rect.top and Rect.bottom will be wrong.
// I try to use GetDCOrgEx(DC, &Pt), but they are not normal HDC that Pt.x and Pt.y will equal to 0 in these cases.
// And use GetWindowRect() then get Rect.left and Rect.top is only useful on Title bar.
if (((Rect.left <= Rect.right) && (CurParams->Pt.x >= Rect.left) && (CurParams->Pt.x <= Rect.right)) ||
((Rect.left > Rect.right) && (CurParams->Pt.x <= Rect.left) && (CurParams->Pt.x >= Rect.right))) {
int BegPos;
//if (PtInRect(&Rect, CurParams->Pt)) {
CurParams->Active = !PtInRect(&Rect, CurParams->Pt);
//CurParams->Active = FALSE;
BegPos = (int)((abs((CurParams->Pt.x - Rect.left) / (Rect.right - Rect.left)) * (Count - 1)) + 0.5);
while ((BegPos < Count - 1) && GetTextExtentPoint32W(DC, Str, BegPos + 1, &Size) && (Size.cx < CurParams->Pt.x - Rect.left))
BegPos++;
while ((BegPos >= 0) && GetTextExtentPoint32W(DC, Str, BegPos + 1, &Size) && (Size.cx > CurParams->Pt.x - Rect.left))
BegPos--;
if (BegPos < Count - 1)
BegPos++;
CurParams->BeginPos = BegPos;
if (Count > 255)
CurParams->WordLen = 255;
else
CurParams->WordLen = Count;
CurParams->Unicode = TRUE;
CopyMemory(CurParams->MatchedWordW, Str, CurParams->WordLen * sizeof(wchar_t));
}
}
}
BOOL WINAPI TextOutACallbackProc(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString, int cbString)
{
if (CurParams && CurParams->Active)
IsInsidePointA(hdc, nXStart, nYStart, lpszString, cbString);
return TextOutANextHook(hdc, nXStart, nYStart, lpszString, cbString);
}
BOOL WINAPI TextOutWCallbackProc(HDC hdc, int nXStart, int nYStart, LPCWSTR lpszString, int cbString)
{
if (CurParams && CurParams->Active)
IsInsidePointW(hdc, nXStart, nYStart, lpszString, cbString);
return TextOutWNextHook(hdc, nXStart, nYStart, lpszString, cbString);
}
BOOL WINAPI ExtTextOutACallbackProc(HDC hdc, int nXStart, int nYStart, UINT fuOptions, CONST RECT *lprc, LPCSTR lpszString, UINT cbString, CONST INT *lpDx)
{
if (CurParams && CurParams->Active)
IsInsidePointA(hdc, nXStart, nYStart, lpszString, cbString);
return ExtTextOutANextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
}
BOOL WINAPI ExtTextOutWCallbackProc(HDC hdc, int nXStart, int nYStart, UINT fuOptions, CONST RECT *lprc, LPCWSTR lpszString, UINT cbString, CONST INT *lpDx)
{
if (CurParams && CurParams->Active)
IsInsidePointW(hdc, nXStart, nYStart, lpszString, cbString);
return ExtTextOutWNextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
}
static void InstallTextOutHooks()
{
HookAPI("gdi32.dll", "TextOutA", (PROC)TextOutACallbackProc, (PROC*)&TextOutANextHook);
HookAPI("gdi32.dll", "TextOutW", (PROC)TextOutWCallbackProc, (PROC*)&TextOutWNextHook);
HookAPI("gdi32.dll", "ExtTextOutA", (PROC)ExtTextOutACallbackProc, (PROC*)&ExtTextOutANextHook);
HookAPI("gdi32.dll", "ExtTextOutW", (PROC)ExtTextOutWCallbackProc, (PROC*)&ExtTextOutWNextHook);
}
static void UninstallTextOutHooks()
{
if (TextOutANextHook)
HookAPI("gdi32.dll", "TextOutA", (PROC)TextOutANextHook, NULL);
if (TextOutWNextHook)
HookAPI("gdi32.dll", "TextOutW", (PROC)TextOutWNextHook, NULL);
if (ExtTextOutANextHook)
HookAPI("gdi32.dll", "ExtTextOutA", (PROC)ExtTextOutANextHook, NULL);
if (ExtTextOutWNextHook)
HookAPI("gdi32.dll", "ExtTextOutW", (PROC)ExtTextOutWNextHook, NULL);
}
DLLIMPORT void __gdGetWord (TCurrentMode *P)
{
TCHAR wClassName[64];
TKnownWndClass WndClass;
char *p;
if (GetClassName(P->WND, wClassName, sizeof(wClassName) / sizeof(TCHAR))==0)
wClassName[0] = '\0';
WndClass = GetWindowType(P->WND, wClassName);
p = TryGetWordFromAnyWindow(WndClass, P->WND, P->Pt, &(P->BeginPos));
if (p) {
P->WordLen = strlen(p);
strcpy(P->MatchedWord, p);
free(p);
} else {
P->WordLen = 0;
}
}
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:
//ThTypes_Init();
InstallTextOutHooks();
break;
case DLL_PROCESS_DETACH:
UninstallTextOutHooks();
//Thtypes_End();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
/* Returns TRUE on success, FALSE on failure */
return TRUE;
}

View file

@ -0,0 +1,17 @@
#ifndef _TextOutHook_H_
#define _TextOutHook_H_
#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */
#include "ThTypes.h"
char* ExtractFromEverything(HWND WND, POINT Pt, int *BeginPos);
DLLIMPORT void GetWord (TCurrentMode *P);
#endif /* _TextOutHook_H_ */

View file

@ -0,0 +1,153 @@
#include "TextOutSpy.h"
#include "ThTypes.h"
const int MOUSEOVER_INTERVAL = 300;
const int WM_MY_SHOW_TRANSLATION = WM_USER + 301;
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, "__gdGetWord");
}
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) {
HWND WND;
TCHAR wClassName[64];
if (GlobalData->TimerID) {
if (KillTimer(0, GlobalData->TimerID))
GlobalData->TimerID=0;
}
WND = WindowFromPoint(((PMOUSEHOOKSTRUCT)lParam)->pt);
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, "GoldenDictTextOutSpyMutex");
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;
}

View file

@ -0,0 +1,14 @@
#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_ */

View file

@ -0,0 +1,24 @@
#include "ThTypes.h"
HANDLE MMFHandle = 0;
TGlobalDLLData *GlobalData = NULL;
void ThTypes_Init()
{
if (!MMFHandle)
MMFHandle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(TGlobalDLLData), "GoldenDictTextOutHookSharedMem");
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;
}
}

View file

@ -0,0 +1,39 @@
#ifndef _ThTypes_H_
#define _ThTypes_H_
#include <windows.h>
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
typedef struct TCurrentMode {
HWND WND;
POINT Pt;
size_t WordLen;
char MatchedWord[256];
int BeginPos;
} TCurrentMode;
typedef struct TGlobalDLLData {
HWND ServerWND;
HHOOK g_hHookMouse;
UINT_PTR 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

View file

@ -0,0 +1,7 @@
These files were taken straight from StarDict 3.0.1. They didn't seem to
bear any copyright notices, and as such, no new notices were added.
The only changes made were renaming some global ids to make sure that running
StarDict and GoldenDict simultaneously wouldn't interfere with each other.
The Makefile is made for mingw32 cross-compilation, and is completely separate
from the main program.