mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-24 16:54:08 +00:00
245 lines
6.6 KiB
C
245 lines
6.6 KiB
C
|
#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);
|
||
|
}
|