mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-24 08:34:08 +00:00
630 lines
20 KiB
C
630 lines
20 KiB
C
/*
|
|
* February 2, 2009: Konstantin Isakov <ikm@goldendict.org>
|
|
* Support for ETO_GLYPH_INDEX in ExtTextOutW() function added. This makes
|
|
* Firefox 3 work.
|
|
*/
|
|
|
|
#define _WIN32_WINNT 0x0500
|
|
|
|
#include "TextOutHook.h"
|
|
#include "GetWord.h"
|
|
#include "HookImportFunction.h"
|
|
|
|
typedef BOOL (WINAPI *TextOutANextHook_t)(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString,int cbString);
|
|
typedef BOOL (WINAPI *TextOutWNextHook_t)(HDC hdc, int nXStart, int nYStart, LPCWSTR lpszString,int cbString);
|
|
typedef BOOL (WINAPI *ExtTextOutANextHook_t)(HDC hdc, int nXStart, int nYStart, UINT fuOptions, CONST RECT *lprc, LPCSTR lpszString, UINT cbString, CONST INT *lpDx);
|
|
typedef BOOL (WINAPI *ExtTextOutWNextHook_t)(HDC hdc, int nXStart, int nYStart, UINT fuOptions, CONST RECT *lprc, LPCWSTR lpszString, UINT cbString, CONST INT *lpDx);
|
|
#ifdef __WIN64
|
|
TextOutANextHook_t TextOutANextHook __attribute__ ((aligned (8))) = NULL;
|
|
TextOutWNextHook_t TextOutWNextHook __attribute__ ((aligned (8))) = NULL;
|
|
ExtTextOutANextHook_t ExtTextOutANextHook __attribute__ ((aligned (8))) = NULL;
|
|
ExtTextOutWNextHook_t ExtTextOutWNextHook __attribute__ ((aligned (8))) = NULL;
|
|
#else
|
|
TextOutANextHook_t TextOutANextHook __attribute__ ((aligned (4))) = NULL;
|
|
TextOutWNextHook_t TextOutWNextHook __attribute__ ((aligned (4))) = NULL;
|
|
ExtTextOutANextHook_t ExtTextOutANextHook __attribute__ ((aligned (4))) = NULL;
|
|
ExtTextOutWNextHook_t ExtTextOutWNextHook __attribute__ ((aligned (4))) = NULL;
|
|
#endif
|
|
|
|
#define HOOKS_NUM 4
|
|
|
|
TEverythingParams *CurParams = NULL;
|
|
HANDLE installEvent = 0;
|
|
volatile long hookCounts[HOOKS_NUM] __attribute__ ((aligned (4))) = { 0, 0, 0, 0 };
|
|
CRITICAL_SECTION hookCS;
|
|
|
|
void ConvertToMatchedWordA(TEverythingParams *TP)
|
|
{
|
|
if (TP->WordLen > 0 && TP->WordLen < (int)sizeof(TP->MatchedWordA) && TP->BeginPos >= 0 && TP->BeginPos < (int)sizeof(TP->MatchedWordA)) {
|
|
int BeginPos;
|
|
int BufSize;
|
|
if (!TP->Unicode) {
|
|
BeginPos = TP->BeginPos;
|
|
if (BeginPos > 0) {
|
|
BufSize = sizeof(TP->MatchedWordW)/sizeof(TP->MatchedWordW[0]) - 1;
|
|
TP->BeginPos = MultiByteToWideChar(CP_ACP, 0, TP->MatchedWordA, BeginPos, TP->MatchedWordW, BufSize);
|
|
if (TP->BeginPos == 0) {
|
|
TP->WordLen=0;
|
|
TP->MatchedWordA[0] = '\0';
|
|
return;
|
|
}
|
|
}
|
|
BufSize = sizeof(TP->MatchedWordW)/sizeof(TP->MatchedWordW[0]) - 1 - TP->BeginPos;
|
|
if(BufSize > 0)
|
|
TP->WordLen = MultiByteToWideChar(CP_ACP, 0, TP->MatchedWordA + BeginPos, TP->WordLen - BeginPos, TP->MatchedWordW + TP->BeginPos, BufSize);
|
|
else TP->WordLen = 0;
|
|
if (TP->WordLen == 0) {
|
|
TP->WordLen=TP->BeginPos;
|
|
TP->MatchedWordA[TP->WordLen] = '\0';
|
|
return;
|
|
}
|
|
TP->WordLen += TP->BeginPos;
|
|
if(TP->WordLen >= (int)sizeof(TP->MatchedWordA)) TP->WordLen = sizeof(TP->MatchedWordA) - 1;
|
|
}
|
|
BeginPos = TP->BeginPos;
|
|
if (BeginPos > 0) {
|
|
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) - 1, NULL, NULL);
|
|
TP->MatchedWordW[BeginPos] = temp;
|
|
TP->BeginPos--;
|
|
if (TP->BeginPos<=0) {
|
|
TP->WordLen=0;
|
|
TP->MatchedWordA[0] = '\0';
|
|
return;
|
|
} else if (TP->BeginPos >= (int)sizeof(TP->MatchedWordA)-1) {
|
|
TP->WordLen=sizeof(TP->MatchedWordA)-1;
|
|
TP->MatchedWordA[sizeof(TP->MatchedWordA)-1] = '\0';
|
|
return;
|
|
}
|
|
}
|
|
TP->MatchedWordW[TP->WordLen] = 0;
|
|
BufSize = sizeof(TP->MatchedWordA) - TP->BeginPos;
|
|
if( BufSize > 0)
|
|
TP->WordLen = WideCharToMultiByte(CP_UTF8, 0, TP->MatchedWordW + BeginPos, TP->WordLen - BeginPos + 1, TP->MatchedWordA + TP->BeginPos, BufSize, NULL, NULL);
|
|
else TP->WordLen = 0;
|
|
TP->WordLen--;
|
|
if (TP->WordLen<=0) {
|
|
TP->WordLen=TP->BeginPos;
|
|
TP->MatchedWordA[TP->WordLen] = '\0';
|
|
return;
|
|
}
|
|
TP->WordLen += TP->BeginPos;
|
|
if(TP->WordLen >= (int)sizeof(TP->MatchedWordA)) TP->WordLen = sizeof(TP->MatchedWordA) - 1;
|
|
TP->MatchedWordA[TP->WordLen] = '\0';
|
|
} else {
|
|
TP->WordLen = 0;
|
|
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)
|
|
{
|
|
RECT rec;
|
|
MENUITEMINFO info;
|
|
int i;
|
|
int count = GetMenuItemCount(menu);
|
|
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_STRING | MIIM_SUBMENU;
|
|
if( !GetMenuItemInfo(menu, i, TRUE, &info) )
|
|
break;
|
|
if (info.cch > 0 && info.cch < 255) {
|
|
char buf[256];
|
|
ZeroMemory(buf, sizeof(buf));
|
|
info.cch += 1;
|
|
info.dwTypeData = buf;
|
|
info.fMask = MIIM_STRING | MIIM_SUBMENU;
|
|
if( GetMenuItemInfo(menu, i, TRUE, &info) ) {
|
|
if( info.cch > 255 )
|
|
break;
|
|
CurParams->WordLen = info.cch;
|
|
CurParams->Unicode = FALSE;
|
|
CurParams->WordLen = MyCopyMemory(CurParams->MatchedWordA, buf, CurParams->WordLen + 1);
|
|
CurParams->BeginPos = 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void GetWordTextOutHook (TEverythingParams *TP)
|
|
{
|
|
EnterCriticalSection(&hookCS);
|
|
CurParams = TP;
|
|
ScreenToClient(TP->WND, &(TP->Pt));
|
|
if (TP->Pt.y<0) {
|
|
char buffer[256];
|
|
HMENU menu=NULL;
|
|
char buffer2[256];
|
|
int n, n2;
|
|
ZeroMemory(buffer, sizeof(buffer));
|
|
ZeroMemory(buffer2, sizeof(buffer2));
|
|
|
|
if( ( n = GetWindowText(TP->WND, buffer, sizeof(buffer)-1) ) > 0 ) {
|
|
SetWindowText(TP->WND, "");
|
|
if ( ( n2 = GetWindowText(TP->WND, buffer2, sizeof(buffer2)-1) ) > 0 ) { // MDI window.
|
|
char *p = strstr(buffer, buffer2);
|
|
if (p) {
|
|
if (p == buffer) { // FWS_PREFIXTITLE
|
|
if( n > n2 && n - n2 < (int)sizeof( buffer ) )
|
|
memmove( buffer, buffer + n2, n - n2 + 1 );
|
|
// strncpy(buffer, buffer+strlen(buffer2), sizeof(buffer)-1);
|
|
} else {
|
|
*p = '\0';
|
|
}
|
|
}
|
|
}
|
|
CurParams->Active = TRUE;
|
|
SetWindowText(TP->WND, buffer);
|
|
CurParams->Active = FALSE;
|
|
}
|
|
menu = GetMenu(TP->WND);
|
|
if (menu && IsMenu( 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;
|
|
if(!GetUpdateRect(TP->WND, NULL, FALSE)) {
|
|
CurParams->Active = TRUE;
|
|
InvalidateRect(TP->WND, &UpdateRect, FALSE);
|
|
UpdateWindow(TP->WND);
|
|
CurParams->Active = FALSE;
|
|
}
|
|
}
|
|
CurParams = NULL;
|
|
LeaveCriticalSection(&hookCS);
|
|
}
|
|
|
|
char* ExtractFromEverything(HWND WND, POINT Pt, DWORD *BeginPos)
|
|
{
|
|
TEverythingParams CParams;
|
|
|
|
ZeroMemory(&CParams, sizeof(CParams));
|
|
CParams.WND = WND;
|
|
CParams.Pt = Pt;
|
|
GetWordTextOutHook(&CParams);
|
|
ConvertToMatchedWordA(&CParams);
|
|
*BeginPos = CParams.BeginPos;
|
|
if(CParams.WordLen>0) {
|
|
return _strdup(CParams.MatchedWordA);
|
|
} else {
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
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;
|
|
int Shift = 0;
|
|
|
|
//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++;
|
|
if( Count > 255 ) {
|
|
Shift = BegPos - 127;
|
|
if( Shift <= 0 )
|
|
Shift = 0;
|
|
else {
|
|
if( Shift > Count - 255 )
|
|
Shift = Count - 255;
|
|
}
|
|
BegPos -= Shift;
|
|
Count -= Shift;
|
|
if( Count > 255 )
|
|
Count = 255;
|
|
}
|
|
if (BegPos>255) BegPos=255;
|
|
CurParams->BeginPos = BegPos;
|
|
CurParams->WordLen = Count;
|
|
CurParams->Unicode = FALSE;
|
|
CopyMemory(CurParams->MatchedWordA, Str + Shift, 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;
|
|
int Shift = 0;
|
|
|
|
//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++;
|
|
if( Count > 255 ) {
|
|
Shift = BegPos - 127;
|
|
if( Shift <= 0 )
|
|
Shift = 0;
|
|
else {
|
|
if( Shift > Count - 255 )
|
|
Shift = Count - 255;
|
|
}
|
|
BegPos -= Shift;
|
|
Count -= Shift;
|
|
if( Count > 255 )
|
|
Count = 255;
|
|
}
|
|
if (BegPos>255) BegPos=255;
|
|
CurParams->BeginPos = BegPos;
|
|
CurParams->WordLen = Count;
|
|
CurParams->Unicode = TRUE;
|
|
CopyMemory(CurParams->MatchedWordW, Str + Shift, CurParams->WordLen * sizeof(wchar_t));
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL WINAPI TextOutACallbackProc(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString, int cbString)
|
|
{
|
|
BOOL res = FALSE;
|
|
WaitForSingleObject(installEvent, INFINITE);
|
|
InterlockedIncrement(hookCounts + 0);
|
|
if(TryEnterCriticalSection(&hookCS)) {
|
|
if (CurParams && CurParams->Active)
|
|
IsInsidePointA(hdc, nXStart, nYStart, lpszString, cbString);
|
|
LeaveCriticalSection(&hookCS);
|
|
}
|
|
if(TextOutANextHook)
|
|
res = TextOutANextHook(hdc, nXStart, nYStart, lpszString, cbString);
|
|
InterlockedDecrement(hookCounts + 0);
|
|
return res;
|
|
}
|
|
|
|
BOOL WINAPI TextOutWCallbackProc(HDC hdc, int nXStart, int nYStart, LPCWSTR lpszString, int cbString)
|
|
{
|
|
BOOL res = FALSE;
|
|
WaitForSingleObject(installEvent, INFINITE);
|
|
InterlockedIncrement(hookCounts + 1);
|
|
if(TryEnterCriticalSection(&hookCS)) {
|
|
if (CurParams && CurParams->Active)
|
|
IsInsidePointW(hdc, nXStart, nYStart, lpszString, cbString);
|
|
LeaveCriticalSection(&hookCS);
|
|
}
|
|
if(TextOutWNextHook)
|
|
res = TextOutWNextHook(hdc, nXStart, nYStart, lpszString, cbString);
|
|
InterlockedDecrement(hookCounts + 1);
|
|
return res;
|
|
}
|
|
|
|
BOOL WINAPI ExtTextOutACallbackProc(HDC hdc, int nXStart, int nYStart, UINT fuOptions, CONST RECT *lprc, LPCSTR lpszString, UINT cbString, CONST INT *lpDx)
|
|
{
|
|
BOOL res = FALSE;
|
|
WaitForSingleObject(installEvent, INFINITE);
|
|
InterlockedIncrement(hookCounts + 2);
|
|
if(TryEnterCriticalSection(&hookCS)) {
|
|
if (CurParams && CurParams->Active)
|
|
IsInsidePointA(hdc, nXStart, nYStart, lpszString, cbString);
|
|
LeaveCriticalSection(&hookCS);
|
|
}
|
|
if(ExtTextOutANextHook)
|
|
res = ExtTextOutANextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
|
|
InterlockedDecrement(hookCounts + 2);
|
|
return res;
|
|
}
|
|
|
|
BOOL WINAPI ExtTextOutWCallbackProc(HDC hdc, int nXStart, int nYStart, UINT fuOptions, CONST RECT *lprc, LPCWSTR lpszString, UINT cbString, CONST INT *lpDx)
|
|
{
|
|
BOOL res = FALSE;
|
|
WaitForSingleObject(installEvent, INFINITE);
|
|
InterlockedIncrement(hookCounts + 3);
|
|
if(TryEnterCriticalSection(&hookCS)) {
|
|
if (CurParams && CurParams->Active)
|
|
{
|
|
if ( fuOptions & ETO_GLYPH_INDEX )
|
|
{
|
|
LPGLYPHSET ranges = NULL;
|
|
WCHAR * allChars, * ptr, * restoredString = NULL;
|
|
WORD * allIndices;
|
|
unsigned x;
|
|
|
|
// Here we have to decode glyph indices back to chars. We do this
|
|
// by tedious and ineffective iteration.
|
|
|
|
x = GetFontUnicodeRanges( hdc, 0 );
|
|
if(x != 0) ranges = malloc(x);
|
|
if(ranges == NULL) {
|
|
LeaveCriticalSection(&hookCS);
|
|
if(ExtTextOutWNextHook)
|
|
res = ExtTextOutWNextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
|
|
InterlockedDecrement(hookCounts + 3);
|
|
return res;
|
|
}
|
|
x = GetFontUnicodeRanges( hdc, ranges );
|
|
if(x == 0) {
|
|
free(ranges);
|
|
LeaveCriticalSection(&hookCS);
|
|
if(ExtTextOutWNextHook)
|
|
res = ExtTextOutWNextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
|
|
InterlockedDecrement(hookCounts + 3);
|
|
return res;
|
|
}
|
|
|
|
// Render up all available chars into one ridiculously big string
|
|
|
|
allChars = malloc( ( ranges->cGlyphsSupported ) * sizeof( WCHAR ) );
|
|
allIndices = malloc( ( ranges->cGlyphsSupported ) * sizeof( WORD ) );
|
|
|
|
if(allChars == NULL || allIndices == NULL) {
|
|
if(allChars != NULL) free(allChars);
|
|
if(allIndices != NULL) free(allIndices);
|
|
free(ranges);
|
|
LeaveCriticalSection(&hookCS);
|
|
if(ExtTextOutWNextHook)
|
|
res = ExtTextOutWNextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
|
|
InterlockedDecrement(hookCounts + 3);
|
|
return res;
|
|
}
|
|
|
|
ptr = allChars;
|
|
|
|
for( x = 0; x < ranges->cRanges; ++x ) {
|
|
WCHAR c = ranges->ranges[ x ].wcLow;
|
|
unsigned y = ranges->ranges[ x ].cGlyphs;
|
|
|
|
while( y-- )
|
|
*ptr++ = c++;
|
|
}
|
|
|
|
// Amazing. Now get glyph indices for this one nice string.
|
|
|
|
if(GetGlyphIndicesW(hdc, allChars, ranges->cGlyphsSupported, allIndices, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR) {
|
|
|
|
// Fascinating. Now translate our original input string back into
|
|
// its readable form.
|
|
|
|
restoredString = malloc( cbString * sizeof( WCHAR ) );
|
|
|
|
if(restoredString != NULL) {
|
|
for( x = 0; x < cbString; ++x ) {
|
|
unsigned y;
|
|
WORD idx = lpszString[ x ];
|
|
|
|
for( y = 0; y < ranges->cGlyphsSupported; ++y )
|
|
if ( allIndices[ y ] == idx ) {
|
|
restoredString[ x ] = allChars[ y ];
|
|
break;
|
|
}
|
|
if ( y == ranges->cGlyphsSupported ) {
|
|
// Not found
|
|
restoredString[ x ] = L'?';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// And we're done.
|
|
|
|
free( allIndices );
|
|
free( allChars );
|
|
free( ranges );
|
|
|
|
if(restoredString != NULL) {
|
|
IsInsidePointW( hdc, nXStart, nYStart, restoredString, cbString );
|
|
free( restoredString );
|
|
}
|
|
}
|
|
else // fuOptions & ETO_GLYPH_INDEX
|
|
IsInsidePointW(hdc, nXStart, nYStart, lpszString, cbString);
|
|
}
|
|
|
|
LeaveCriticalSection(&hookCS);
|
|
}
|
|
if(ExtTextOutWNextHook)
|
|
res = ExtTextOutWNextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
|
|
InterlockedDecrement(hookCounts + 3);
|
|
return res;
|
|
}
|
|
|
|
void WaitForAllHooks()
|
|
{
|
|
HANDLE hTimer;
|
|
LARGE_INTEGER waitTime;
|
|
waitTime.LowPart = 50000000; // 5 s
|
|
waitTime.HighPart = 0;
|
|
waitTime.QuadPart = -waitTime.QuadPart; // RelativeTime
|
|
hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
|
|
if(hTimer)
|
|
SetWaitableTimer(hTimer, &waitTime, 0, NULL, NULL, FALSE);
|
|
|
|
while((hookCounts[0] > 0 || hookCounts[1] > 0 || hookCounts[2] > 0 || hookCounts[3] > 0) &&
|
|
(!hTimer || WaitForSingleObject(hTimer, 0) != WAIT_OBJECT_0)) {
|
|
SwitchToThread();
|
|
}
|
|
if(hTimer)
|
|
CloseHandle(hTimer);
|
|
}
|
|
|
|
static void InstallTextOutHooks()
|
|
{
|
|
if (TextOutANextHook==NULL)
|
|
HookAPI("gdi32.dll", "TextOutA", (PROC)TextOutACallbackProc, (PROC*)&TextOutANextHook);
|
|
if (TextOutWNextHook==NULL)
|
|
HookAPI("gdi32.dll", "TextOutW", (PROC)TextOutWCallbackProc, (PROC*)&TextOutWNextHook);
|
|
if (ExtTextOutANextHook==NULL)
|
|
HookAPI("gdi32.dll", "ExtTextOutA", (PROC)ExtTextOutACallbackProc, (PROC*)&ExtTextOutANextHook);
|
|
if (ExtTextOutWNextHook==NULL)
|
|
HookAPI("gdi32.dll", "ExtTextOutW", (PROC)ExtTextOutWCallbackProc, (PROC*)&ExtTextOutWNextHook);
|
|
SetEvent(installEvent);
|
|
}
|
|
|
|
static void UninstallTextOutHooks()
|
|
{
|
|
if (TextOutANextHook) {
|
|
HookAPI("gdi32.dll", "TextOutA", (PROC)TextOutANextHook, NULL);
|
|
// TextOutANextHook=NULL;
|
|
}
|
|
if (TextOutWNextHook) {
|
|
HookAPI("gdi32.dll", "TextOutW", (PROC)TextOutWNextHook, NULL);
|
|
// TextOutWNextHook=NULL;
|
|
}
|
|
if (ExtTextOutANextHook) {
|
|
HookAPI("gdi32.dll", "ExtTextOutA", (PROC)ExtTextOutANextHook, NULL);
|
|
// ExtTextOutANextHook=NULL;
|
|
}
|
|
if (ExtTextOutWNextHook) {
|
|
HookAPI("gdi32.dll", "ExtTextOutW", (PROC)ExtTextOutWNextHook, NULL);
|
|
// ExtTextOutWNextHook=NULL;
|
|
}
|
|
}
|
|
|
|
DLLIMPORT DWORD __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;
|
|
}
|
|
if(WndClass == kwcConsole || WndClass == kwcConEmu)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
|
|
DWORD reason /* Reason this function is being called. */ ,
|
|
LPVOID reserved /* Not used. */ )
|
|
{
|
|
(void) hInst;
|
|
(void) reserved;
|
|
switch (reason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
if((installEvent = CreateEvent(0, TRUE, FALSE, 0)) == 0)
|
|
return FALSE;
|
|
InitializeCriticalSection(&hookCS);
|
|
InstallTextOutHooks();
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
UninstallTextOutHooks();
|
|
WaitForAllHooks();
|
|
CloseHandle(installEvent);
|
|
DeleteCriticalSection(&hookCS);
|
|
break;
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
break;
|
|
|
|
case DLL_THREAD_DETACH:
|
|
break;
|
|
}
|
|
|
|
/* Returns TRUE on success, FALSE on failure */
|
|
return TRUE;
|
|
}
|