2024-05-06 23:30:27 +08:00
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
#pragma intrinsic(_ReturnAddress)
|
|
|
|
|
|
|
|
// Disable only for debugging purpose
|
2024-07-21 21:04:12 +08:00
|
|
|
// #define HIJACK_GDI_FONT
|
|
|
|
// #define HIJACK_GDI_TEXT
|
2024-02-07 20:59:24 +08:00
|
|
|
|
|
|
|
#define DEF_FUN(_f) Hijack::_f##_fun_t Hijack::old##_f = ::_f;
|
2024-07-21 21:04:12 +08:00
|
|
|
DEF_FUN(CreateFontA)
|
|
|
|
DEF_FUN(CreateFontW)
|
|
|
|
DEF_FUN(CreateFontIndirectA)
|
|
|
|
DEF_FUN(CreateFontIndirectW)
|
|
|
|
DEF_FUN(GetGlyphOutlineA)
|
|
|
|
DEF_FUN(GetGlyphOutlineW)
|
|
|
|
DEF_FUN(GetTextExtentPoint32A)
|
|
|
|
DEF_FUN(GetTextExtentPoint32W)
|
|
|
|
DEF_FUN(GetTextExtentExPointA)
|
|
|
|
DEF_FUN(GetTextExtentExPointW)
|
|
|
|
DEF_FUN(GetCharABCWidthsA)
|
|
|
|
DEF_FUN(GetCharABCWidthsW)
|
|
|
|
DEF_FUN(TextOutA)
|
|
|
|
DEF_FUN(TextOutW)
|
|
|
|
DEF_FUN(ExtTextOutA)
|
|
|
|
DEF_FUN(ExtTextOutW)
|
|
|
|
DEF_FUN(DrawTextA)
|
|
|
|
DEF_FUN(DrawTextW)
|
|
|
|
DEF_FUN(DrawTextExA)
|
|
|
|
DEF_FUN(DrawTextExW)
|
|
|
|
DEF_FUN(CharNextA)
|
|
|
|
// DEF_FUN(CharNextW)
|
|
|
|
// DEF_FUN(CharNextExA)
|
|
|
|
// DEF_FUN(CharNextExW)
|
|
|
|
DEF_FUN(CharPrevA)
|
|
|
|
// DEF_FUN(CharPrevW)
|
|
|
|
DEF_FUN(MultiByteToWideChar)
|
|
|
|
DEF_FUN(WideCharToMultiByte)
|
2024-02-07 20:59:24 +08:00
|
|
|
#undef DEF_FUN
|
|
|
|
|
|
|
|
/** Helper */
|
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
namespace
|
|
|
|
{ // unnamed
|
|
|
|
UINT8 systemCharSet()
|
|
|
|
{
|
|
|
|
enum CodePage
|
|
|
|
{
|
|
|
|
NullCodePage = 0,
|
|
|
|
Utf8CodePage = 65001 // UTF-8
|
|
|
|
,
|
|
|
|
Utf16CodePage = 1200 // UTF-16
|
|
|
|
,
|
|
|
|
SjisCodePage = 932 // SHIFT-JIS
|
|
|
|
,
|
|
|
|
GbkCodePage = 936 // GB2312
|
|
|
|
,
|
|
|
|
KscCodePage = 949 // EUC-KR
|
|
|
|
,
|
|
|
|
Big5CodePage = 950 // BIG5
|
|
|
|
,
|
|
|
|
TisCodePage = 874 // TIS-620
|
|
|
|
,
|
|
|
|
Koi8CodePage = 866 // KOI8-R
|
|
|
|
};
|
|
|
|
auto systemCodePage = ::GetACP();
|
|
|
|
switch (systemCodePage)
|
|
|
|
{
|
|
|
|
case TisCodePage:
|
|
|
|
return THAI_CHARSET;
|
|
|
|
case Koi8CodePage:
|
|
|
|
return RUSSIAN_CHARSET;
|
|
|
|
case SjisCodePage:
|
|
|
|
return SHIFTJIS_CHARSET;
|
|
|
|
case GbkCodePage:
|
|
|
|
return GB2312_CHARSET;
|
|
|
|
case Big5CodePage:
|
|
|
|
return CHINESEBIG5_CHARSET;
|
|
|
|
|
|
|
|
case KscCodePage:
|
|
|
|
return HANGUL_CHARSET;
|
|
|
|
case 1361:
|
|
|
|
return JOHAB_CHARSET; // alternative Korean character set
|
|
|
|
|
|
|
|
case 1250:
|
|
|
|
return EASTEUROPE_CHARSET;
|
|
|
|
case 1251:
|
|
|
|
return RUSSIAN_CHARSET; // cyrillic
|
|
|
|
case 1253:
|
|
|
|
return GREEK_CHARSET;
|
|
|
|
case 1254:
|
|
|
|
return TURKISH_CHARSET;
|
|
|
|
|
|
|
|
case 862:
|
|
|
|
return HEBREW_CHARSET; // obsolete
|
|
|
|
case 1255:
|
|
|
|
return HEBREW_CHARSET;
|
|
|
|
|
|
|
|
case 1256:
|
|
|
|
return ARABIC_CHARSET;
|
|
|
|
case 1257:
|
|
|
|
return BALTIC_CHARSET;
|
|
|
|
case 1258:
|
|
|
|
return VIETNAMESE_CHARSET;
|
|
|
|
|
|
|
|
// default: return DEFAULT_CHARSET;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
void customizeLogFontA(LOGFONTA *lplf)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (embedsharedmem->fontCharSetEnabled)
|
|
|
|
{
|
|
|
|
auto charSet = embedsharedmem->fontCharSet;
|
|
|
|
if (!charSet)
|
|
|
|
charSet = systemCharSet();
|
|
|
|
if (charSet)
|
|
|
|
lplf->lfCharSet = charSet;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
if (s->fontWeight)
|
|
|
|
lplf->lfWeight = s->fontWeight;
|
|
|
|
if (s->isFontScaled()) {
|
|
|
|
lplf->lfWidth *= s->fontScale;
|
|
|
|
lplf->lfHeight *= s->fontScale;
|
|
|
|
}
|
|
|
|
*/
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
void customizeLogFontW(LOGFONTW *lplf)
|
|
|
|
{
|
|
|
|
customizeLogFontA((LOGFONTA *)lplf);
|
2024-02-07 20:59:24 +08:00
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
std::wstring s = embedsharedmem->fontFamily;
|
|
|
|
if (!s.empty())
|
|
|
|
{
|
|
|
|
lplf->lfFaceName[s.size()] = 0;
|
|
|
|
// s->fontFamily.toWCharArray(lplf->lfFaceName);
|
|
|
|
memcpy(lplf->lfFaceName, s.c_str(), s.size());
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
// LogFont manager
|
2024-02-07 20:59:24 +08:00
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
class LogFontManager
|
|
|
|
{
|
|
|
|
typedef std::pair<HFONT, LOGFONTW> font_pair;
|
|
|
|
std::list<font_pair> fonts_;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
static bool eq(const LOGFONTW &x, const LOGFONTW &y);
|
2024-02-07 20:59:24 +08:00
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
public:
|
|
|
|
HFONT get(const LOGFONTW &lf) const;
|
|
|
|
void add(HFONT hf, const LOGFONTW &lf);
|
|
|
|
void remove(HFONT hf);
|
|
|
|
void remove(const LOGFONTW &lf);
|
|
|
|
};
|
2024-02-07 20:59:24 +08:00
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
bool LogFontManager::eq(const LOGFONTW &x, const LOGFONTW &y)
|
|
|
|
{ // I assume there is no padding
|
|
|
|
return ::wcscmp(x.lfFaceName, y.lfFaceName) == 0 && ::memcmp(&x, &y, sizeof(x) - sizeof(x.lfFaceName)) == 0;
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
void LogFontManager::add(HFONT hf, const LOGFONTW &lf)
|
|
|
|
{
|
|
|
|
fonts_.push_back(std::make_pair(hf, lf));
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
void LogFontManager::remove(HFONT hf)
|
|
|
|
{
|
|
|
|
auto _ = std::remove_if(fonts_.begin(), fonts_.end(), [&hf](const font_pair &it)
|
|
|
|
{ return it.first == hf; });
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
void LogFontManager::remove(const LOGFONTW &lf)
|
|
|
|
{
|
|
|
|
auto _ = std::remove_if(fonts_.begin(), fonts_.end(), [&lf](const font_pair &it)
|
|
|
|
{ return eq(it.second, lf); });
|
|
|
|
}
|
|
|
|
|
|
|
|
HFONT LogFontManager::get(const LOGFONTW &lf) const
|
|
|
|
{
|
|
|
|
for each (const font_pair &it in fonts_)
|
|
|
|
if (eq(it.second, lf))
|
|
|
|
return it.first;
|
|
|
|
return nullptr;
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
// GDI font switcher
|
|
|
|
|
|
|
|
class DCFontSwitcher
|
|
|
|
{
|
|
|
|
static LogFontManager fonts_;
|
|
|
|
|
|
|
|
HDC hdc_;
|
|
|
|
HFONT oldFont_,
|
2024-02-07 20:59:24 +08:00
|
|
|
newFont_;
|
2024-07-21 21:04:12 +08:00
|
|
|
std::wstring newfontname;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
public:
|
|
|
|
explicit DCFontSwitcher(HDC hdc); // pass 0 to disable this class
|
|
|
|
~DCFontSwitcher();
|
|
|
|
};
|
2024-02-07 20:59:24 +08:00
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
LogFontManager DCFontSwitcher::fonts_;
|
|
|
|
|
|
|
|
DCFontSwitcher::~DCFontSwitcher()
|
|
|
|
{
|
|
|
|
// No idea why selecting old font will crash Mogeko Castle
|
|
|
|
// if (oldFont_ && oldFont_ != HGDI_ERROR)
|
|
|
|
// ::SelectObject(hdc_, oldFont_);
|
|
|
|
|
|
|
|
// Never delete new font but cache them
|
|
|
|
// This could result in bad font after game is reset and deleted my font
|
|
|
|
// if (newFont_)
|
|
|
|
// ::DeleteObject(newFont_);
|
|
|
|
}
|
|
|
|
bool isFontCustomized()
|
|
|
|
{
|
|
|
|
return embedsharedmem->fontCharSetEnabled || wcslen(embedsharedmem->fontFamily);
|
|
|
|
}
|
|
|
|
DCFontSwitcher::DCFontSwitcher(HDC hdc)
|
|
|
|
: hdc_(hdc), oldFont_(nullptr), newFont_(nullptr), newfontname(L"")
|
|
|
|
{
|
|
|
|
if (!hdc_)
|
|
|
|
return;
|
2024-02-07 20:59:24 +08:00
|
|
|
/*
|
|
|
|
auto p = HijackHelper::instance();
|
|
|
|
if (!p)
|
|
|
|
return;
|
|
|
|
auto s = p->settings();
|
|
|
|
if (!s->deviceContextFontEnabled || !s->isFontCustomized())
|
|
|
|
return;
|
|
|
|
*/
|
2024-07-21 21:04:12 +08:00
|
|
|
TEXTMETRICW tm;
|
|
|
|
if (!::GetTextMetricsW(hdc, &tm))
|
|
|
|
return;
|
|
|
|
|
|
|
|
LOGFONTW lf = {};
|
|
|
|
lf.lfHeight = tm.tmHeight;
|
|
|
|
lf.lfWeight = tm.tmWeight;
|
|
|
|
lf.lfItalic = tm.tmItalic;
|
|
|
|
lf.lfUnderline = tm.tmUnderlined;
|
|
|
|
lf.lfStrikeOut = tm.tmStruckOut;
|
|
|
|
lf.lfCharSet = tm.tmCharSet;
|
|
|
|
lf.lfPitchAndFamily = tm.tmPitchAndFamily;
|
|
|
|
|
|
|
|
customizeLogFontW(&lf);
|
|
|
|
|
|
|
|
if (std::wstring(embedsharedmem->fontFamily).empty())
|
|
|
|
::GetTextFaceW(hdc_, LF_FACESIZE, lf.lfFaceName);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wcscpy(lf.lfFaceName, embedsharedmem->fontFamily);
|
|
|
|
}
|
|
|
|
newFont_ = fonts_.get(lf);
|
|
|
|
if ((!newFont_) || (newfontname != std::wstring(embedsharedmem->fontFamily)))
|
|
|
|
{
|
|
|
|
newFont_ = Hijack::oldCreateFontIndirectW(&lf);
|
|
|
|
fonts_.add(newFont_, lf);
|
|
|
|
newfontname = std::wstring(embedsharedmem->fontFamily);
|
|
|
|
}
|
|
|
|
oldFont_ = (HFONT)SelectObject(hdc_, newFont_);
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // unnamed namespace
|
|
|
|
|
|
|
|
/** Fonts */
|
|
|
|
|
|
|
|
// http://forums.codeguru.com/showthread.php?500522-Need-clarification-about-CreateFontIndirect
|
|
|
|
// The font creation functions will never fail
|
|
|
|
HFONT WINAPI Hijack::newCreateFontIndirectA(const LOGFONTA *lplf)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
|
|
|
// DOUT("width:" << lplf->lfWidth << ", height:" << lplf->lfHeight << ", weight:" << lplf->lfWeight);
|
|
|
|
// if (auto p = HijackHelper::instance()) {
|
|
|
|
// auto s = p->settings();
|
|
|
|
std::wstring fontFamily = embedsharedmem->fontFamily;
|
|
|
|
if (lplf && isFontCustomized())
|
|
|
|
{
|
|
|
|
union
|
|
|
|
{
|
|
|
|
LOGFONTA a;
|
|
|
|
LOGFONTW w;
|
|
|
|
} lf = {*lplf}; // only initialize the first member of LOGFONTA
|
|
|
|
customizeLogFontA(&lf.a);
|
|
|
|
if (!fontFamily.empty())
|
|
|
|
{
|
|
|
|
if (all_ascii(fontFamily.c_str(), fontFamily.size()))
|
|
|
|
::strcpy(lf.a.lfFaceName, WideStringToString(fontFamily, CP_ACP).c_str());
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lf.w.lfFaceName[fontFamily.size()] = 0;
|
|
|
|
// s->fontFamily.toWCharArray(lf.w.lfFaceName);
|
|
|
|
memcpy(lf.w.lfFaceName, fontFamily.c_str(), fontFamily.size());
|
|
|
|
return oldCreateFontIndirectW(&lf.w);
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
return oldCreateFontIndirectA(&lf.a);
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
//}
|
|
|
|
return oldCreateFontIndirectA(lplf);
|
|
|
|
}
|
|
|
|
|
|
|
|
HFONT WINAPI Hijack::newCreateFontIndirectW(const LOGFONTW *lplf)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
|
|
|
// DOUT("width:" << lplf->lfWidth << ", height:" << lplf->lfHeight << ", weight:" << lplf->lfWeight);
|
|
|
|
// if (auto p = HijackHelper::instance()) {
|
|
|
|
// auto s = p->settings();
|
|
|
|
if (lplf && isFontCustomized())
|
|
|
|
{
|
|
|
|
LOGFONTW lf(*lplf);
|
|
|
|
customizeLogFontW(&lf);
|
|
|
|
return oldCreateFontIndirectW(&lf);
|
|
|
|
}
|
|
|
|
// }
|
2024-02-07 20:59:24 +08:00
|
|
|
return oldCreateFontIndirectW(lplf);
|
|
|
|
}
|
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
#define CREATE_FONT_ARGS nHeight, nWidth, nEscapement, nOrientation, fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet, fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily, lpszFace
|
2024-02-07 20:59:24 +08:00
|
|
|
HFONT WINAPI Hijack::newCreateFontA(int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight, DWORD fdwItalic, DWORD fdwUnderline, DWORD fdwStrikeOut, DWORD fdwCharSet, DWORD fdwOutputPrecision, DWORD fdwClipPrecision, DWORD fdwQuality, DWORD fdwPitchAndFamily, LPCSTR lpszFace)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
|
|
|
if (isFontCustomized())
|
|
|
|
{
|
|
|
|
if (embedsharedmem->fontCharSetEnabled)
|
|
|
|
{
|
|
|
|
auto charSet = embedsharedmem->fontCharSet;
|
|
|
|
if (!charSet)
|
|
|
|
charSet = systemCharSet();
|
|
|
|
if (charSet)
|
|
|
|
fdwCharSet = charSet;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
if (s->fontWeight)
|
|
|
|
fnWeight = s->fontWeight;
|
|
|
|
if (s->isFontScaled()) {
|
|
|
|
nWidth *= s->fontScale;
|
|
|
|
nHeight *= s->fontScale;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
std::wstring fontFamily = embedsharedmem->fontFamily;
|
|
|
|
if (!fontFamily.empty())
|
|
|
|
{
|
|
|
|
if (all_ascii(fontFamily.c_str(), fontFamily.size()))
|
|
|
|
{
|
|
|
|
lpszFace = WideStringToString(fontFamily, CP_ACP).c_str();
|
|
|
|
return oldCreateFontA(CREATE_FONT_ARGS);
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
auto lpszFace = (LPCWSTR)fontFamily.c_str();
|
|
|
|
return oldCreateFontW(CREATE_FONT_ARGS);
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
}
|
|
|
|
return oldCreateFontA(CREATE_FONT_ARGS);
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
HFONT WINAPI Hijack::newCreateFontW(int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight, DWORD fdwItalic, DWORD fdwUnderline, DWORD fdwStrikeOut, DWORD fdwCharSet, DWORD fdwOutputPrecision, DWORD fdwClipPrecision, DWORD fdwQuality, DWORD fdwPitchAndFamily, LPCWSTR lpszFace)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
|
|
|
if (isFontCustomized())
|
|
|
|
{
|
|
|
|
if (embedsharedmem->fontCharSetEnabled)
|
|
|
|
{
|
|
|
|
auto charSet = embedsharedmem->fontCharSet;
|
|
|
|
if (!charSet)
|
|
|
|
charSet = systemCharSet();
|
|
|
|
if (charSet)
|
|
|
|
fdwCharSet = charSet;
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
/*
|
|
|
|
if (s->fontWeight)
|
|
|
|
fnWeight = s->fontWeight;
|
|
|
|
if (s->isFontScaled()) {
|
|
|
|
nWidth *= s->fontScale;
|
|
|
|
nHeight *= s->fontScale;
|
|
|
|
}*/
|
|
|
|
if (!std::wstring(embedsharedmem->fontFamily).empty())
|
|
|
|
lpszFace = (LPCWSTR)embedsharedmem;
|
|
|
|
}
|
|
|
|
return oldCreateFontW(CREATE_FONT_ARGS);
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
|
|
|
#undef CREATE_FONT_ARGS
|
|
|
|
|
|
|
|
/** Encoding */
|
|
|
|
|
|
|
|
LPSTR WINAPI Hijack::newCharNextA(LPCSTR lpString)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
|
|
|
// if (::GetACP() == 932)
|
2024-02-07 20:59:24 +08:00
|
|
|
return const_cast<char *>(dynsjis::nextchar(lpString));
|
2024-07-21 21:04:12 +08:00
|
|
|
// return oldCharNextA(lpString);
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
LPSTR WINAPI Hijack::newCharPrevA(LPCSTR lpStart, LPCSTR lpCurrent)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
|
|
|
// if (::GetACP() == 932)
|
2024-02-07 20:59:24 +08:00
|
|
|
return const_cast<char *>(dynsjis::prevchar(lpCurrent, lpStart));
|
2024-07-21 21:04:12 +08:00
|
|
|
// return oldCharNextA(lpStart, lpCurrent);
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
extern DynamicShiftJISCodec *dynamiccodec;
|
2024-02-07 20:59:24 +08:00
|
|
|
int WINAPI Hijack::newMultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar)
|
|
|
|
{
|
|
|
|
//
|
2024-07-21 21:04:12 +08:00
|
|
|
/* if (auto p = HijackHelper::instance())
|
|
|
|
if (p->settings()->localeEmulationEnabled)
|
|
|
|
if (CodePage == CP_THREAD_ACP || CodePage == CP_OEMCP)
|
|
|
|
CodePage = CP_ACP;
|
|
|
|
*/
|
|
|
|
if (CodePage == CP_THREAD_ACP || CodePage == CP_OEMCP)
|
|
|
|
CodePage = CP_ACP;
|
|
|
|
// CP_ACP(0), CP_MACCP(1), CP_OEMCP(2), CP_THREAD_ACP(3)
|
|
|
|
if ((CodePage <= 3 || CodePage == 932) && cchWideChar > 0 && cbMultiByte > 1)
|
|
|
|
{
|
|
|
|
bool dynamic;
|
|
|
|
std::string data(lpMultiByteStr, cbMultiByte);
|
|
|
|
auto text = dynamiccodec->decode(data, &dynamic);
|
|
|
|
if (dynamic && !text.empty())
|
|
|
|
{
|
|
|
|
int size = min(text.size() + 1, cchWideChar);
|
|
|
|
::memcpy(lpWideCharStr, text.c_str(), size * 2);
|
|
|
|
// lpWideCharStr[size - 1] = 0; // enforce trailing zero
|
|
|
|
return size - 1;
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
return oldMultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, lpWideCharStr, cchWideChar);
|
|
|
|
}
|
|
|
|
|
|
|
|
int WINAPI Hijack::newWideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
if (CodePage == CP_THREAD_ACP || CodePage == CP_OEMCP)
|
2024-07-21 21:04:12 +08:00
|
|
|
CodePage = CP_ACP;
|
|
|
|
|
|
|
|
if ((CodePage <= 3 || CodePage == 932) && cchWideChar > 0 && cbMultiByte >= 0)
|
|
|
|
{
|
|
|
|
bool dynamic;
|
|
|
|
auto text = std::wstring(lpWideCharStr, cchWideChar);
|
|
|
|
auto data = dynamiccodec->encodeSTD(text, &dynamic);
|
|
|
|
if (dynamic && !data.empty())
|
|
|
|
{
|
|
|
|
|
|
|
|
int size = data.size() + 1;
|
|
|
|
if (cbMultiByte && cbMultiByte < size)
|
|
|
|
size = cbMultiByte;
|
|
|
|
::memcpy(lpMultiByteStr, data.c_str(), size);
|
|
|
|
// lpMultiByteStr[size - 1] = 0; // enforce trailing zero
|
|
|
|
return size - 1;
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
return oldWideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Text */
|
2024-07-21 21:04:12 +08:00
|
|
|
UINT decodeChar(UINT ch, bool *dynamic)
|
2024-02-07 20:59:24 +08:00
|
|
|
{
|
|
|
|
if (dynamic)
|
|
|
|
*dynamic = false;
|
2024-07-21 21:04:12 +08:00
|
|
|
if (ch > 0xff)
|
|
|
|
{
|
2024-02-07 20:59:24 +08:00
|
|
|
bool t;
|
2024-07-21 21:04:12 +08:00
|
|
|
char data[3] = {(BYTE)(ch >> 8) & 0xff, (BYTE)ch & 0xff, 0};
|
2024-02-07 20:59:24 +08:00
|
|
|
auto text = dynamiccodec->decode(data, &t);
|
2024-07-21 21:04:12 +08:00
|
|
|
if (t && text.size() == 1)
|
|
|
|
{
|
2024-02-07 20:59:24 +08:00
|
|
|
if (dynamic)
|
2024-07-21 21:04:12 +08:00
|
|
|
*dynamic = true;
|
|
|
|
return text[0];
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ch;
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
#define DECODE_CHAR(uChar, ...) \
|
|
|
|
{ \
|
|
|
|
if (uChar > 0xff) \
|
|
|
|
if (1) \
|
|
|
|
{ \
|
|
|
|
bool dynamic; \
|
|
|
|
UINT ch = decodeChar(uChar, &dynamic); \
|
|
|
|
if (dynamic && ch) \
|
|
|
|
{ \
|
|
|
|
uChar = ch; \
|
|
|
|
return (__VA_ARGS__); \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
#define DECODE_TEXT(lpString, cchString, ...) \
|
|
|
|
{ \
|
|
|
|
if (cchString == -1 || cchString > 1) \
|
|
|
|
if (1) \
|
|
|
|
{ \
|
|
|
|
bool dynamic; \
|
|
|
|
auto data = std::string(lpString, cchString == -1 ? ::strlen(lpString) : cchString); \
|
|
|
|
if (data.size() > 1) \
|
|
|
|
{ \
|
|
|
|
auto text = dynamiccodec->decode(data, &dynamic); \
|
|
|
|
if (dynamic && !text.empty()) \
|
|
|
|
{ \
|
|
|
|
LPCWSTR lpString = (LPCWSTR)text.c_str(); \
|
|
|
|
cchString = text.size(); \
|
|
|
|
return (__VA_ARGS__); \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
#define TRANSLATE_TEXT_A(lpString, cchString, ...) \
|
|
|
|
{ \
|
|
|
|
if (auto q = EngineController::instance()) \
|
|
|
|
{ \
|
2024-02-07 20:59:24 +08:00
|
|
|
auto data = std::string(lpString, cchString == -1 ? ::strlen(lpString) : cchString); \
|
2024-07-21 21:04:12 +08:00
|
|
|
std::wstring oldText = q->decode(data); \
|
|
|
|
if (!oldText.empty()) \
|
|
|
|
{ \
|
|
|
|
enum \
|
|
|
|
{ \
|
|
|
|
role = Engine::OtherRole \
|
|
|
|
}; \
|
|
|
|
ULONG split = (ULONG)_ReturnAddress(); \
|
|
|
|
auto sig = Engine::hashThreadSignature(role, split); \
|
|
|
|
auto newText = q->dispatchTextWSTD(oldText, role, sig); \
|
|
|
|
if (newText != oldText) \
|
|
|
|
{ \
|
|
|
|
LPCWSTR lpString = (LPCWSTR)newText.c_str(); \
|
|
|
|
cchString = newText.size(); \
|
|
|
|
return (__VA_ARGS__); \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
#define TRANSLATE_TEXT_W(lpString, cchString, ...) \
|
|
|
|
{ \
|
|
|
|
if (auto q = EngineController::instance()) \
|
|
|
|
{ \
|
|
|
|
auto text = std::wstring(lpString, cchString); \
|
|
|
|
if (!text.empty()) \
|
|
|
|
{ \
|
|
|
|
enum \
|
|
|
|
{ \
|
|
|
|
role = Engine::OtherRole \
|
|
|
|
}; \
|
|
|
|
ULONG split = (ULONG)_ReturnAddress(); \
|
|
|
|
auto sig = Engine::hashThreadSignature(role, split); \
|
|
|
|
text = q->dispatchTextWSTD(text, role, sig); \
|
|
|
|
LPCWSTR lpString = (LPCWSTR)text.c_str(); \
|
|
|
|
cchString = text.size(); \
|
|
|
|
return (__VA_ARGS__); \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
|
|
|
DWORD WINAPI Hijack::newGetGlyphOutlineA(HDC hdc, UINT uChar, UINT uFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpvBuffer, const MAT2 *lpmat2)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
DCFontSwitcher fs(hdc);
|
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
DECODE_CHAR(uChar, oldGetGlyphOutlineW(hdc, ch, uFormat, lpgm, cbBuffer, lpvBuffer, lpmat2))
|
|
|
|
return oldGetGlyphOutlineA(hdc, uChar, uFormat, lpgm, cbBuffer, lpvBuffer, lpmat2);
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD WINAPI Hijack::newGetGlyphOutlineW(HDC hdc, UINT uChar, UINT uFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpvBuffer, const MAT2 *lpmat2)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
DCFontSwitcher fs(hdc);
|
|
|
|
return oldGetGlyphOutlineW(hdc, uChar, uFormat, lpgm, cbBuffer, lpvBuffer, lpmat2);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI Hijack::newGetTextExtentPoint32A(HDC hdc, LPCSTR lpString, int cchString, LPSIZE lpSize)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
|
|
|
DCFontSwitcher fs(hdc);
|
|
|
|
// TRANSLATE_TEXT_A(lpString, cchString, oldGetTextExtentPoint32W(hdc, lpString, cchString, lpSize))
|
|
|
|
DECODE_TEXT(lpString, cchString, oldGetTextExtentPoint32W(hdc, lpString, cchString, lpSize))
|
2024-02-07 20:59:24 +08:00
|
|
|
return oldGetTextExtentPoint32A(hdc, lpString, cchString, lpSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI Hijack::newGetTextExtentPoint32W(HDC hdc, LPCWSTR lpString, int cchString, LPSIZE lpSize)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
DCFontSwitcher fs(hdc);
|
2024-07-21 21:04:12 +08:00
|
|
|
// TRANSLATE_TEXT_W(lpString, cchString, oldGetTextExtentPoint32W(hdc, lpString, cchString, lpSize))
|
2024-02-07 20:59:24 +08:00
|
|
|
return oldGetTextExtentPoint32W(hdc, lpString, cchString, lpSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI Hijack::newGetTextExtentExPointA(HDC hdc, LPCSTR lpString, int cchString, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
|
|
|
// DCFontSwitcher fs(hdc);
|
|
|
|
// TRANSLATE_TEXT_A(lpString, cchString, oldGetTextExtentExPointW(hdc, lpString, cchString, nMaxExtent, lpnFit, alpDx, lpSize))
|
2024-02-07 20:59:24 +08:00
|
|
|
DECODE_TEXT(lpString, cchString, oldGetTextExtentExPointW(hdc, lpString, cchString, nMaxExtent, lpnFit, alpDx, lpSize))
|
|
|
|
return oldGetTextExtentExPointA(hdc, lpString, cchString, nMaxExtent, lpnFit, alpDx, lpSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI Hijack::newGetTextExtentExPointW(HDC hdc, LPCWSTR lpString, int cchString, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
DCFontSwitcher fs(hdc);
|
2024-07-21 21:04:12 +08:00
|
|
|
// TRANSLATE_TEXT_W(lpString, cchString, oldGetTextExtentExPointW(hdc, lpString, cchString, nMaxExtent, lpnFit, alpDx, lpSize))
|
2024-02-07 20:59:24 +08:00
|
|
|
return oldGetTextExtentExPointW(hdc, lpString, cchString, nMaxExtent, lpnFit, alpDx, lpSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
int WINAPI Hijack::newDrawTextA(HDC hdc, LPCSTR lpString, int cchString, LPRECT lpRect, UINT uFormat)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
DCFontSwitcher fs(hdc);
|
|
|
|
// if (HijackManager::instance()->isFunctionTranslated((uintptr_t)::DrawTextA))
|
|
|
|
// TRANSLATE_TEXT_A(lpString, cchString, oldDrawTextW(hdc, lpString, cchString, lpRect, uFormat))
|
|
|
|
// else
|
2024-07-21 21:04:12 +08:00
|
|
|
DECODE_TEXT(lpString, cchString, oldDrawTextW(hdc, lpString, cchString, lpRect, uFormat))
|
2024-02-07 20:59:24 +08:00
|
|
|
return oldDrawTextA(hdc, lpString, cchString, lpRect, uFormat);
|
|
|
|
}
|
|
|
|
|
|
|
|
int WINAPI Hijack::newDrawTextW(HDC hdc, LPCWSTR lpString, int cchString, LPRECT lpRect, UINT uFormat)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
DCFontSwitcher fs(hdc);
|
|
|
|
// if (HijackManager::instance()->isFunctionTranslated((ULONG)::DrawTextW))
|
|
|
|
// TRANSLATE_TEXT_W(lpString, cchString, oldDrawTextW(hdc, lpString, cchString, lpRect, uFormat))
|
|
|
|
return oldDrawTextW(hdc, lpString, cchString, lpRect, uFormat);
|
|
|
|
}
|
|
|
|
|
|
|
|
int WINAPI Hijack::newDrawTextExA(HDC hdc, LPSTR lpString, int cchString, LPRECT lpRect, UINT dwDTFormat, LPDRAWTEXTPARAMS lpDTParams)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
DCFontSwitcher fs(hdc);
|
2024-07-21 21:04:12 +08:00
|
|
|
if (!(dwDTFormat & DT_MODIFYSTRING))
|
|
|
|
{
|
2024-02-07 20:59:24 +08:00
|
|
|
// if (HijackManager::instance()->isFunctionTranslated((uintptr_t)::DrawTextExA))
|
|
|
|
// TRANSLATE_TEXT_A(lpString, cchString, oldDrawTextExW(hdc, const_cast<LPWSTR>(lpString), cchString, lpRect, dwDTFormat, lpDTParams))
|
|
|
|
// else
|
2024-07-21 21:04:12 +08:00
|
|
|
DECODE_TEXT(lpString, cchString, oldDrawTextExW(hdc, const_cast<LPWSTR>(lpString), cchString, lpRect, dwDTFormat, lpDTParams))
|
2024-02-07 20:59:24 +08:00
|
|
|
}
|
|
|
|
return oldDrawTextExA(hdc, lpString, cchString, lpRect, dwDTFormat, lpDTParams);
|
|
|
|
}
|
|
|
|
|
|
|
|
int WINAPI Hijack::newDrawTextExW(HDC hdc, LPWSTR lpString, int cchString, LPRECT lpRect, UINT dwDTFormat, LPDRAWTEXTPARAMS lpDTParams)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
DCFontSwitcher fs(hdc);
|
|
|
|
// if (!(dwDTFormat & DT_MODIFYSTRING) && HijackManager::instance()->isFunctionTranslated((ULONG)::DrawTextExW))
|
|
|
|
// TRANSLATE_TEXT_W(lpString, cchString, oldDrawTextExW(hdc, const_cast<LPWSTR>(lpString), cchString, lpRect, dwDTFormat, lpDTParams))
|
|
|
|
return oldDrawTextExW(hdc, lpString, cchString, lpRect, dwDTFormat, lpDTParams);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI Hijack::newTextOutA(HDC hdc, int nXStart, int nYStart, LPCSTR lpString, int cchString)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
DCFontSwitcher fs(hdc);
|
|
|
|
// if (HijackManager::instance()->isFunctionTranslated((uintptr_t)::TextOutA))
|
|
|
|
// TRANSLATE_TEXT_A(lpString, cchString, oldTextOutW(hdc, nXStart, nYStart, lpString, cchString))
|
|
|
|
// else
|
2024-07-21 21:04:12 +08:00
|
|
|
DECODE_TEXT(lpString, cchString, oldTextOutW(hdc, nXStart, nYStart, lpString, cchString))
|
2024-02-07 20:59:24 +08:00
|
|
|
return oldTextOutA(hdc, nXStart, nYStart, lpString, cchString);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI Hijack::newTextOutW(HDC hdc, int nXStart, int nYStart, LPCWSTR lpString, int cchString)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
DCFontSwitcher fs(hdc);
|
|
|
|
// if (HijackManager::instance()->isFunctionTranslated((ULONG)::TextOutW))
|
|
|
|
// TRANSLATE_TEXT_W(lpString, cchString, oldTextOutW(hdc, nXStart, nYStart, lpString, cchString))
|
|
|
|
return oldTextOutW(hdc, nXStart, nYStart, lpString, cchString);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI Hijack::newExtTextOutA(HDC hdc, int X, int Y, UINT fuOptions, const RECT *lprc, LPCSTR lpString, UINT cchString, const INT *lpDx)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
DCFontSwitcher fs(hdc);
|
|
|
|
// if (HijackManager::instance()->isFunctionTranslated((uintptr_t)::ExtTextOutA))
|
|
|
|
// TRANSLATE_TEXT_A(lpString, cchString, oldExtTextOutW(hdc, X, Y, fuOptions, lprc, lpString, cchString, lpDx))
|
|
|
|
// else
|
2024-07-21 21:04:12 +08:00
|
|
|
DECODE_TEXT(lpString, cchString, oldExtTextOutW(hdc, X, Y, fuOptions, lprc, lpString, cchString, lpDx))
|
2024-02-07 20:59:24 +08:00
|
|
|
return oldExtTextOutA(hdc, X, Y, fuOptions, lprc, lpString, cchString, lpDx);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI Hijack::newExtTextOutW(HDC hdc, int X, int Y, UINT fuOptions, const RECT *lprc, LPCWSTR lpString, UINT cchString, const INT *lpDx)
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
DCFontSwitcher fs(hdc);
|
|
|
|
// if (HijackManager::instance()->isFunctionTranslated((ULONG)::ExtTextOutW))
|
|
|
|
// TRANSLATE_TEXT_W(lpString, cchString, oldExtTextOutW(hdc, X, Y, fuOptions, lprc, lpString, cchString, lpDx))
|
|
|
|
return oldExtTextOutW(hdc, X, Y, fuOptions, lprc, lpString, cchString, lpDx);
|
|
|
|
}
|
|
|
|
|
|
|
|
// EOF
|