mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-27 15:24:05 +00:00
Win32-specific mouseover dll sources added, taken directly from StarDict
codebase with minimal modifications.
This commit is contained in:
parent
1a5a4daa52
commit
18b355cda3
244
src/mouseover_win32/GetWord.c
Normal file
244
src/mouseover_win32/GetWord.c
Normal 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);
|
||||||
|
}
|
18
src/mouseover_win32/GetWord.h
Normal file
18
src/mouseover_win32/GetWord.h
Normal 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
|
122
src/mouseover_win32/HookImportFunction.c
Normal file
122
src/mouseover_win32/HookImportFunction.c
Normal 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;
|
||||||
|
}
|
9
src/mouseover_win32/HookImportFunction.h
Normal file
9
src/mouseover_win32/HookImportFunction.h
Normal 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
|
29
src/mouseover_win32/Makefile
Normal file
29
src/mouseover_win32/Makefile
Normal 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
|
395
src/mouseover_win32/TextOutHook.c
Normal file
395
src/mouseover_win32/TextOutHook.c
Normal 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;
|
||||||
|
}
|
17
src/mouseover_win32/TextOutHook.h
Normal file
17
src/mouseover_win32/TextOutHook.h
Normal 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_ */
|
153
src/mouseover_win32/TextOutSpy.c
Normal file
153
src/mouseover_win32/TextOutSpy.c
Normal 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;
|
||||||
|
}
|
14
src/mouseover_win32/TextOutSpy.h
Normal file
14
src/mouseover_win32/TextOutSpy.h
Normal 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_ */
|
24
src/mouseover_win32/ThTypes.c
Normal file
24
src/mouseover_win32/ThTypes.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
39
src/mouseover_win32/ThTypes.h
Normal file
39
src/mouseover_win32/ThTypes.h
Normal 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
|
7
src/mouseover_win32/readme.txt
Normal file
7
src/mouseover_win32/readme.txt
Normal 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.
|
Loading…
Reference in a new issue