This commit is contained in:
恍兮惚兮 2024-11-14 20:32:39 +08:00
parent 0d3c839444
commit 0602a4c6a5
35 changed files with 266 additions and 168 deletions

View File

@ -4,9 +4,7 @@ public:
bool attach_function()
{
ConsoleOutput("IGNORE %s", getenginename());
// ConsoleOutput("IGNORE engine");
PcHooks::hooknormalfunctions();
return true;
return false;
}
};
class oldSystem40ini : public NoEngine

View File

@ -99,21 +99,10 @@ namespace
return NewHook(hp, "Anim3");
}
}
namespace
{
bool gdi()
{
HookParam hp;
hp.address = (DWORD)::GetGlyphOutlineA;
hp.offset = get_stack(2);
hp.type = CODEC_ANSI_BE;
return NewHook(hp, "Anim");
}
}
bool Anim::attach_function()
{
PcHooks::hookGDIFunctions(GetGlyphOutlineA);
auto b1 = InsertAnimHook() || InsertAnim2Hook();
b1 = InsertAnim3Hook() || b1;
return gdi() || b1;
return b1;
}

View File

@ -143,5 +143,6 @@ namespace
}
bool CodeX::attach_function()
{
PcHooks::hookGDIFunctions(GetGlyphOutlineA); // 对于部分游戏,文本分两段显示,会吞掉后半段。故此用这个兜底
return (hook3() | InsertCodeXHook()) || hook() || hook2();
}

View File

@ -138,7 +138,7 @@ void HIJACK()
if (!result)
{
PcHooks::hooknormalfunctions();
PcHooks::hookGdiGdiplusD3dxFunctions();
PcHooks::hookOtherPcFunctions();
}
}

View File

@ -11,18 +11,22 @@
// http://bytes.com/topic/c/answers/135834-defining-wide-character-strings-macros
// #define LPASTE(s) L##s
// #define L(s) LPASTE(s)
#define NEW_HOOK(_dll, _fun, _data, _data_ind, _split_off, _split_ind, _type, _len_off) \
{ \
HookParam hp; \
wcsncpy_s(hp.module, _dll, MAX_MODULE_SIZE - 1); \
strncpy_s(hp.function, #_fun, MAX_MODULE_SIZE - 1); \
hp.offset = _data; \
hp.index = _data_ind; \
hp.split = _split_off; \
hp.split_index = _split_ind; \
hp.type = _type | MODULE_OFFSET | FUNCTION_OFFSET; \
hp.length_offset = _len_off; \
NewHook(hp, #_fun); \
#define NEW_HOOK(ptr, _dll, _fun, _data, _data_ind, _split_off, _split_ind, _type, _len_off) \
{ \
HookParam hp; \
wcsncpy_s(hp.module, _dll, MAX_MODULE_SIZE - 1); \
strncpy_s(hp.function, #_fun, MAX_MODULE_SIZE - 1); \
hp.offset = _data; \
hp.index = _data_ind; \
hp.split = _split_off; \
hp.split_index = _split_ind; \
hp.type = _type | MODULE_OFFSET | FUNCTION_OFFSET; \
hp.length_offset = _len_off; \
if ((!ptr) || \
(GetModuleHandle(hp.module) && \
GetProcAddress(GetModuleHandle(hp.module), hp.function) && \
GetProcAddress(GetModuleHandle(hp.module), hp.function) == ptr)) \
NewHook(hp, #_fun); \
}
#define NEW_MODULE_HOOK(_module, _fun, _data, _data_ind, _split_off, _split_ind, _type, _len_off) \
@ -45,18 +49,12 @@
enum args
{
s_retaddr = 0,
s_arg1 = 4 * 1 // 0x4
,
s_arg2 = 4 * 2 // 0x8
,
s_arg3 = 4 * 3 // 0xc
,
s_arg4 = 4 * 4 // 0x10
,
s_arg5 = 4 * 5 // 0x14
,
s_arg6 = 4 * 6 // 0x18
,
s_arg1 = 4 * 1, // 0x4
s_arg2 = 4 * 2, // 0x8
s_arg3 = 4 * 3, // 0xc
s_arg4 = 4 * 4, // 0x10
s_arg5 = 4 * 5, // 0x14
s_arg6 = 4 * 6, // 0x18
s_arg7 = 4 * 7
};
#else // _WIN32
@ -73,8 +71,18 @@ enum args
};
#endif // _WIN64
bool once_hookGDIFunctions = false;
bool once_hookGDIPlusFunctions = false;
bool once_hookD3DXFunctions = false;
bool once_hookOtherPcFunctions = false;
#define once_run_pchooks(x) \
{ \
if (once_##x) \
return; \
once_##x = true; \
}
constexpr short arg_sz = (short)sizeof(void *);
void PcHooks::hooknormalfunctions()
void PcHooks::hookGdiGdiplusD3dxFunctions()
{
for (std::wstring DXVersion : {L"d3dx9", L"d3dx10"})
if (HMODULE module = GetModuleHandleW(DXVersion.c_str()))
@ -88,78 +96,50 @@ void PcHooks::hooknormalfunctions()
PcHooks::hookGDIPlusFunctions();
}
// jichi 7/17/2014: Renamed from InitDefaultHook
void PcHooks::hookGDIFunctions()
void PcHooks::hookGDIFunctions(void *ptr)
{
// int TextHook::InitHook(LPVOID addr, DWORD data, DWORD data_ind, DWORD split_off, DWORD split_ind, WORD type, DWORD len_off)
//
// jichi 9/8/2013: Guessed meaning
// - data(off): 4 * the n-th (base 1) parameter representing the data of the string
// - len_off:
// - the n-th (base 1) parameter representing the length of the string
// - or 1 if is char
// - or 0 if detect on run time
// - type: USING_STRING if len_off != 1 else CODEC_ANSI_BE or CODEC_UTF16
//
// Examples:
// int WINAPI lstrlenA(LPCSTR lpString)
// - data: 4 * 1 = 4, as lpString is the first
// - len_off: 0, as no parameter representing string length
// - type: CODEC_ANSI_BE, since len_off == 1
// BOOL GetTextExtentPoint32(HDC hdc, LPCTSTR lpString, int c, LPSIZE lpSize);
// - data: 4 * 2 = 0x8, as lpString is the second
// - len_off: 3, as nCount is the 3rd parameter
// - type: USING_STRING, since len_off != 1
//
// Note: All functions does not have NO_CONTEXT attribute and will be filtered.
//#define _(Name, ...) \
// hookman[HF_##Name].InitHook(Name, __VA_ARGS__); \
// hookman[HF_##Name].SetHookName(names[HF_##Name]);
// Always use s_arg1 = hDC as split_off
// 7/26/2014 jichi: Why there is no USING_SPLIT type?
once_run_pchooks(hookGDIFunctions);
// gdi32.dll
NEW_HOOK(L"gdi32.dll", GetTextExtentPoint32A, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz) // BOOL GetTextExtentPoint32(HDC hdc, LPCTSTR lpString, int c, LPSIZE lpSize);
NEW_HOOK(L"gdi32.dll", GetTextExtentExPointA, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz) // BOOL GetTextExtentExPoint(HDC hdc, LPCTSTR lpszStr, int cchString, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize);
NEW_HOOK(L"gdi32.dll", GetCharacterPlacementA, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz) // DWORD GetCharacterPlacement(HDC hdc, LPCTSTR lpString, int nCount, int nMaxExtent, LPGCP_RESULTS lpResults, DWORD dwFlags);
NEW_HOOK(L"gdi32.dll", GetGlyphIndicesA, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz) // DWORD GetGlyphIndices( HDC hdc, LPCTSTR lpstr, int c, LPWORD pgi, DWORD fl);
NEW_HOOK(L"gdi32.dll", GetGlyphOutlineA, s_arg2, 0, s_arg1, 0, CODEC_ANSI_BE, 0) // DWORD GetGlyphOutline(HDC hdc, UINT uChar, UINT uFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpvBuffer, const MAT2 *lpmat2);
NEW_HOOK(L"gdi32.dll", ExtTextOutA, s_arg6, 0, s_arg1, 0, USING_STRING, s_arg7 / arg_sz) // BOOL ExtTextOut(HDC hdc, int X, int Y, UINT fuOptions, const RECT *lprc, LPCTSTR lpString, UINT cbCount, const INT *lpDx);
NEW_HOOK(L"gdi32.dll", TextOutA, s_arg4, 0, s_arg1, 0, USING_STRING, s_arg5 / arg_sz) // BOOL TextOut(HDC hdc, int nXStart, int nYStart, LPCTSTR lpString, int cchString);
NEW_HOOK(L"gdi32.dll", GetCharABCWidthsA, s_arg2, 0, s_arg1, 0, CODEC_ANSI_BE, 0) // BOOL GetCharABCWidths(HDC hdc, UINT uFirstChar, UINT uLastChar, LPABC lpabc);
NEW_HOOK(L"gdi32.dll", GetCharABCWidthsFloatA, s_arg2, 0, s_arg1, 0, CODEC_ANSI_BE, 0) // BOOL GetCharABCWidthsFloat(HDC hdc, UINT iFirstChar, UINT iLastChar, LPABCFLOAT lpABCF);
NEW_HOOK(L"gdi32.dll", GetCharWidth32A, s_arg2, 0, s_arg1, 0, CODEC_ANSI_BE, 0) // BOOL GetCharWidth32(HDC hdc, UINT iFirstChar, UINT iLastChar, LPINT lpBuffer);
NEW_HOOK(L"gdi32.dll", GetCharWidthFloatA, s_arg2, 0, s_arg1, 0, CODEC_ANSI_BE, 0) // BOOL GetCharWidthFloat(HDC hdc, UINT iFirstChar, UINT iLastChar, PFLOAT pxBuffer);
NEW_HOOK(ptr, L"gdi32.dll", GetTextExtentPoint32A, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"gdi32.dll", GetTextExtentExPointA, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"gdi32.dll", GetCharacterPlacementA, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"gdi32.dll", GetGlyphIndicesA, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"gdi32.dll", GetGlyphOutlineA, s_arg2, 0, s_arg1, 0, CODEC_ANSI_BE, 0)
NEW_HOOK(ptr, L"gdi32.dll", ExtTextOutA, s_arg6, 0, s_arg1, 0, USING_STRING, s_arg7 / arg_sz)
NEW_HOOK(ptr, L"gdi32.dll", TextOutA, s_arg4, 0, s_arg1, 0, USING_STRING, s_arg5 / arg_sz)
NEW_HOOK(ptr, L"gdi32.dll", GetCharABCWidthsA, s_arg2, 0, s_arg1, 0, CODEC_ANSI_BE, 0)
NEW_HOOK(ptr, L"gdi32.dll", GetCharABCWidthsFloatA, s_arg2, 0, s_arg1, 0, CODEC_ANSI_BE, 0)
NEW_HOOK(ptr, L"gdi32.dll", GetCharWidth32A, s_arg2, 0, s_arg1, 0, CODEC_ANSI_BE, 0)
NEW_HOOK(ptr, L"gdi32.dll", GetCharWidthFloatA, s_arg2, 0, s_arg1, 0, CODEC_ANSI_BE, 0)
NEW_HOOK(L"gdi32.dll", GetTextExtentPoint32W, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(L"gdi32.dll", GetTextExtentExPointW, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(L"gdi32.dll", GetCharacterPlacementW, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(L"gdi32.dll", GetGlyphIndicesW, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(L"gdi32.dll", GetGlyphOutlineW, s_arg2, 0, s_arg1, 0, CODEC_UTF16, 0)
NEW_HOOK(ptr, L"gdi32.dll", GetTextExtentPoint32W, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"gdi32.dll", GetTextExtentExPointW, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"gdi32.dll", GetCharacterPlacementW, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"gdi32.dll", GetGlyphIndicesW, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"gdi32.dll", GetGlyphOutlineW, s_arg2, 0, s_arg1, 0, CODEC_UTF16, 0)
// ExtTextOutW全是乱码没卵用
// NEW_HOOK(L"gdi32.dll", ExtTextOutW, s_arg6, 0,s_arg1,0, CODEC_UTF16|USING_STRING, s_arg7 / arg_sz)
NEW_HOOK(L"gdi32.dll", TextOutW, s_arg4, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg5 / arg_sz)
NEW_HOOK(L"gdi32.dll", GetCharABCWidthsW, s_arg2, 0, s_arg1, 0, CODEC_UTF16, 0)
NEW_HOOK(L"gdi32.dll", GetCharABCWidthsFloatW, s_arg2, 0, s_arg1, 0, CODEC_UTF16, 0)
NEW_HOOK(L"gdi32.dll", GetCharWidth32W, s_arg2, 0, s_arg1, 0, CODEC_UTF16, 0)
NEW_HOOK(L"gdi32.dll", GetCharWidthFloatW, s_arg2, 0, s_arg1, 0, CODEC_UTF16, 0)
// NEW_HOOK(ptr, L"gdi32.dll", ExtTextOutW, s_arg6, 0,s_arg1,0, CODEC_UTF16|USING_STRING, s_arg7 / arg_sz)
NEW_HOOK(ptr, L"gdi32.dll", TextOutW, s_arg4, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg5 / arg_sz)
NEW_HOOK(ptr, L"gdi32.dll", GetCharABCWidthsW, s_arg2, 0, s_arg1, 0, CODEC_UTF16, 0)
NEW_HOOK(ptr, L"gdi32.dll", GetCharABCWidthsFloatW, s_arg2, 0, s_arg1, 0, CODEC_UTF16, 0)
NEW_HOOK(ptr, L"gdi32.dll", GetCharWidth32W, s_arg2, 0, s_arg1, 0, CODEC_UTF16, 0)
NEW_HOOK(ptr, L"gdi32.dll", GetCharWidthFloatW, s_arg2, 0, s_arg1, 0, CODEC_UTF16, 0)
// user32.dll
NEW_HOOK(L"user32.dll", DrawTextA, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz) // int DrawText(HDC hDC, LPCTSTR lpchText, int nCount, LPRECT lpRect, UINT uFormat);
NEW_HOOK(L"user32.dll", DrawTextExA, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz) // int DrawTextEx(HDC hdc, LPTSTR lpchText,int cchText, LPRECT lprc, UINT dwDTFormat, LPDRAWTEXTPARAMS lpDTParams);NEW_HOOK(L"gdi32.dll", GetTabbedTextExtentA, s_arg2, 0,s_arg1,0, USING_STRING, s_arg3 / arg_sz) // DWORD GetTabbedTextExtent(HDC hDC, LPCTSTR lpString, int nCount, int nTabPositions, const LPINT lpnTabStopPositions);
NEW_HOOK(L"user32.dll", TabbedTextOutA, s_arg4, 0, s_arg1, 0, USING_STRING, s_arg5 / arg_sz) // LONG TabbedTextOut(HDC hDC, int X, int Y, LPCTSTR lpString, int nCount, int nTabPositions, const LPINT lpnTabStopPositions, int nTabOrigin);
NEW_HOOK(L"user32.dll", GetTabbedTextExtentA, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz) // DWORD GetTabbedTextExtent(HDC hDC, LPCTSTR lpString, int nCount, int nTabPositions, const LPINT lpnTabStopPositions);
NEW_HOOK(L"user32.dll", DrawTextW, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(L"user32.dll", DrawTextExW, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(L"user32.dll", TabbedTextOutW, s_arg4, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg5 / arg_sz)
NEW_HOOK(L"user32.dll", GetTabbedTextExtentW, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"user32.dll", DrawTextA, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"user32.dll", DrawTextExA, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"user32.dll", TabbedTextOutA, s_arg4, 0, s_arg1, 0, USING_STRING, s_arg5 / arg_sz)
NEW_HOOK(ptr, L"user32.dll", GetTabbedTextExtentA, s_arg2, 0, s_arg1, 0, USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"user32.dll", DrawTextW, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"user32.dll", DrawTextExW, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"user32.dll", TabbedTextOutW, s_arg4, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg5 / arg_sz)
NEW_HOOK(ptr, L"user32.dll", GetTabbedTextExtentW, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
}
// jichi 6/18/2015: GDI+ functions
void PcHooks::hookGDIPlusFunctions()
{
once_run_pchooks(hookGDIPlusFunctions);
HMODULE hModule = ::GetModuleHandleA("gdiplus.dll");
if (!hModule)
return;
@ -171,17 +151,18 @@ void PcHooks::hookGDIPlusFunctions()
// Use arg1 pionter to GpGraphics as split
// using namespace Gdiplus::DllExports;
// Use arg5 style as split
NEW_MODULE_HOOK(hModule, GdipAddPathString, s_arg2, 0, s_arg5, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz) // GpStatus WINGDIPAPI GdipAddPathString(GpPath *path, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFontFamily *family, INT style, REAL emSize, GDIPCONST RectF *layoutRect, GDIPCONST GpStringFormat *format)
NEW_MODULE_HOOK(hModule, GdipAddPathStringI, s_arg2, 0, s_arg5, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz) // GpStatus WINGDIPAPI GdipAddPathStringI(GpPath *path, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFontFamily *family, INT style, REAL emSize, GDIPCONST Rect *layoutRect, GDIPCONST GpStringFormat *format)
NEW_MODULE_HOOK(hModule, GdipMeasureCharacterRanges, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz) // GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics *graphics, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF &layoutRect, GDIPCONST GpStringFormat *stringFormat, INT regionCount, GpRegion **regions)
NEW_MODULE_HOOK(hModule, GdipDrawString, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz) // GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF *layoutRect, GDIPCONST GpStringFormat *stringFormat, GDIPCONST GpBrush *brush);
NEW_MODULE_HOOK(hModule, GdipMeasureString, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz) // GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF *layoutRect, GDIPCONST GpStringFormat *stringFormat, RectF *boundingBox, INT *codepointsFitted, INT *linesFilled )
NEW_MODULE_HOOK(hModule, GdipAddPathString, s_arg2, 0, s_arg5, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_MODULE_HOOK(hModule, GdipAddPathStringI, s_arg2, 0, s_arg5, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_MODULE_HOOK(hModule, GdipMeasureCharacterRanges, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_MODULE_HOOK(hModule, GdipDrawString, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_MODULE_HOOK(hModule, GdipMeasureString, s_arg2, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_MODULE_HOOK(hModule, GdipDrawDriverString, s_arg1, 0, s_arg3, 0, CODEC_UTF16 | USING_STRING, s_arg2 / arg_sz)
NEW_MODULE_HOOK(hModule, GdipMeasureDriverString, s_arg1, 0, s_arg3, 0, CODEC_UTF16 | USING_STRING, s_arg2 / arg_sz)
}
bool PcHooks::hookD3DXFunctions(HMODULE d3dxModule)
void PcHooks::hookD3DXFunctions(HMODULE d3dxModule)
{
once_run_pchooks(hookD3DXFunctions);
if (GetProcAddress(d3dxModule, "D3DXCreateTextA"))
{
NEW_MODULE_HOOK(d3dxModule, D3DXCreateTextA, s_arg3, 0, 0, 0, USING_STRING, 0)
@ -196,7 +177,7 @@ bool PcHooks::hookD3DXFunctions(HMODULE d3dxModule)
if (!createFont)
{
ConsoleOutput("D3DX failed: couldn't find entry function");
return false;
return;
}
struct D3DXFont
@ -227,17 +208,18 @@ bool PcHooks::hookD3DXFunctions(HMODULE d3dxModule)
hp.address = (*font.vtable)[15];
hp.type = USING_STRING | CODEC_UTF16;
suc |= NewHook(hp, "ID3DXFont::DrawTextW");
return suc;
return;
}
}
ConsoleOutput("D3DX failed: couldn't find vtable");
return false;
return;
}
// jichi 10/2/2013
// Note: All functions does not have NO_CONTEXT attribute and will be filtered.
void PcHooks::hookOtherPcFunctions()
void PcHooks::hookOtherPcFunctions(void *ptr)
{
once_run_pchooks(hookOtherPcFunctions);
// int TextHook::InitHook(LPVOID addr, DWORD data, DWORD data_ind, DWORD split_off, DWORD split_ind, WORD type, DWORD len_off)
// http://msdn.microsoft.com/en-us/library/78zh94ax.aspx
@ -245,13 +227,13 @@ void PcHooks::hookOtherPcFunctions()
// Lstr functions usually extracts rubbish, and might crash certain games like 「Magical Marriage Lunatics!!」
// Needed by Gift
// Use arg1 address for both split and data
NEW_HOOK(L"kernel32.dll", lstrlenA, s_arg1, 0, s_arg1, 0, USING_STRING, 0) // 9/8/2013 jichi: int WINAPI lstrlen(LPCTSTR lpString);
NEW_HOOK(L"kernel32.dll", lstrcpyA, s_arg2, 0, 0, 0, USING_STRING, 0)
NEW_HOOK(L"kernel32.dll", lstrcpynA, s_arg2, 0, 0, 0, USING_STRING, 0)
NEW_HOOK(ptr, L"kernel32.dll", lstrlenA, s_arg1, 0, s_arg1, 0, USING_STRING, 0)
NEW_HOOK(ptr, L"kernel32.dll", lstrcpyA, s_arg2, 0, 0, 0, USING_STRING, 0)
NEW_HOOK(ptr, L"kernel32.dll", lstrcpynA, s_arg2, 0, 0, 0, USING_STRING, 0)
NEW_HOOK(L"kernel32.dll", lstrlenW, s_arg1, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, 0) // 9/8/2013 jichi: add lstrlen
NEW_HOOK(L"kernel32.dll", lstrcpyW, s_arg2, 0, 0, 0, CODEC_UTF16 | USING_STRING, 0)
NEW_HOOK(L"kernel32.dll", lstrcpynW, s_arg2, 0, 0, 0, CODEC_UTF16 | USING_STRING, 0)
NEW_HOOK(ptr, L"kernel32.dll", lstrlenW, s_arg1, 0, s_arg1, 0, CODEC_UTF16 | USING_STRING, 0)
NEW_HOOK(ptr, L"kernel32.dll", lstrcpyW, s_arg2, 0, 0, 0, CODEC_UTF16 | USING_STRING, 0)
NEW_HOOK(ptr, L"kernel32.dll", lstrcpynW, s_arg2, 0, 0, 0, CODEC_UTF16 | USING_STRING, 0)
// size_t strlen(const char *str);
// size_t strlen_l(const char *str, _locale_t locale);
@ -306,26 +288,26 @@ void PcHooks::hookOtherPcFunctions()
// 2/29/2020 Artikash: TODO: Sort out what to do for string comparison functions
// http://sakuradite.com/topic/159
NEW_HOOK(L"kernel32.dll", MultiByteToWideChar, s_arg3, 0, 4, 0, USING_STRING, s_arg4 / arg_sz)
NEW_HOOK(L"kernel32.dll", WideCharToMultiByte, s_arg3, 0, 4, 0, CODEC_UTF16 | USING_STRING, s_arg4 / arg_sz)
NEW_HOOK(ptr, L"kernel32.dll", MultiByteToWideChar, s_arg3, 0, 4, 0, USING_STRING, s_arg4 / arg_sz)
NEW_HOOK(ptr, L"kernel32.dll", WideCharToMultiByte, s_arg3, 0, 4, 0, CODEC_UTF16 | USING_STRING, s_arg4 / arg_sz)
NEW_HOOK(L"kernel32.dll", GetStringTypeA, s_arg3, 0, 0, 0, USING_STRING, s_arg4 / arg_sz)
NEW_HOOK(L"kernel32.dll", GetStringTypeExA, s_arg3, 0, 0, 0, USING_STRING, s_arg4 / arg_sz)
NEW_HOOK(L"kernel32.dll", FoldStringA, s_arg2, 0, 0, 0, USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(L"kernel32.dll", GetStringTypeW, s_arg2, 0, 0, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(L"kernel32.dll", GetStringTypeExW, s_arg3, 0, 0, 0, CODEC_UTF16 | USING_STRING, s_arg4 / arg_sz)
NEW_HOOK(L"kernel32.dll", FoldStringW, s_arg2, 0, 0, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"kernel32.dll", GetStringTypeA, s_arg3, 0, 0, 0, USING_STRING, s_arg4 / arg_sz)
NEW_HOOK(ptr, L"kernel32.dll", GetStringTypeExA, s_arg3, 0, 0, 0, USING_STRING, s_arg4 / arg_sz)
NEW_HOOK(ptr, L"kernel32.dll", FoldStringA, s_arg2, 0, 0, 0, USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"kernel32.dll", GetStringTypeW, s_arg2, 0, 0, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(ptr, L"kernel32.dll", GetStringTypeExW, s_arg3, 0, 0, 0, CODEC_UTF16 | USING_STRING, s_arg4 / arg_sz)
NEW_HOOK(ptr, L"kernel32.dll", FoldStringW, s_arg2, 0, 0, 0, CODEC_UTF16 | USING_STRING, s_arg3 / arg_sz)
NEW_HOOK(L"user32.dll", CharNextA, s_arg1, 0, 0, 0, DATA_INDIRECT, 0) // LPTSTR WINAPI CharNext(_In_ LPCTSTR lpsz);
NEW_HOOK(L"user32.dll", CharNextW, s_arg1, 0, 0, 0, CODEC_UTF16 | DATA_INDIRECT, 0)
NEW_HOOK(L"user32.dll", CharPrevA, s_arg1, 0, 0, 0, DATA_INDIRECT, 0) // LPTSTR WINAPI CharPrev(_In_ LPCTSTR lpszStart, _In_ LPCTSTR lpszCurrent);
NEW_HOOK(L"user32.dll", CharPrevW, s_arg1, 0, 0, 0, CODEC_UTF16 | DATA_INDIRECT, 0)
NEW_HOOK(L"user32.dll", CharNextExA, s_arg2, 0, 0, 0, DATA_INDIRECT, 0) // LPSTR WINAPI CharNextExA(_In_ WORD CodePage, _In_ LPCSTR lpCurrentChar, _In_ DWORD dwFlags);
NEW_HOOK(L"user32.dll", CharPrevExA, s_arg2, 0, 0, 0, CODEC_UTF16 | DATA_INDIRECT, 0)
NEW_HOOK(ptr, L"user32.dll", CharNextA, s_arg1, 0, 0, 0, DATA_INDIRECT, 0)
NEW_HOOK(ptr, L"user32.dll", CharNextW, s_arg1, 0, 0, 0, CODEC_UTF16 | DATA_INDIRECT, 0)
NEW_HOOK(ptr, L"user32.dll", CharPrevA, s_arg1, 0, 0, 0, DATA_INDIRECT, 0)
NEW_HOOK(ptr, L"user32.dll", CharPrevW, s_arg1, 0, 0, 0, CODEC_UTF16 | DATA_INDIRECT, 0)
NEW_HOOK(ptr, L"user32.dll", CharNextExA, s_arg2, 0, 0, 0, DATA_INDIRECT, 0)
NEW_HOOK(ptr, L"user32.dll", CharPrevExA, s_arg2, 0, 0, 0, CODEC_UTF16 | DATA_INDIRECT, 0)
// トキノ戦華
NEW_HOOK(L"user32.dll", wvsprintfA, s_arg2, 0, 0, 0, USING_STRING, 0)
NEW_HOOK(L"user32.dll", wvsprintfW, s_arg2, 0, 0, 0, CODEC_UTF16 | USING_STRING, 0)
NEW_HOOK(ptr, L"user32.dll", wvsprintfA, s_arg2, 0, 0, 0, USING_STRING, 0)
NEW_HOOK(ptr, L"user32.dll", wvsprintfW, s_arg2, 0, 0, 0, CODEC_UTF16 | USING_STRING, 0)
if (HMODULE module = GetModuleHandleW(L"OLEAUT32.dll"))
{

View File

@ -7,11 +7,11 @@
namespace PcHooks
{
void hookGDIFunctions();
void hookGDIFunctions(void *ptr = 0);
void hookGDIPlusFunctions();
bool hookD3DXFunctions(HMODULE d3dxModule);
void hookOtherPcFunctions();
void hooknormalfunctions();
void hookD3DXFunctions(HMODULE d3dxModule);
void hookOtherPcFunctions(void *ptr = 0);
void hookGdiGdiplusD3dxFunctions();
} // namespace PcHooks
// EOF

View File

@ -34,7 +34,7 @@ DWORD WINAPI Pipe(LPVOID)
*(DWORD *)buffer = GetCurrentProcessId();
WriteFile(hookPipe, buffer, sizeof(DWORD), &count, nullptr);
WORD hookversion[4]=LUNA_VERSION;
WORD hookversion[4] = LUNA_VERSION;
WriteFile(hookPipe, hookversion, sizeof(hookversion), &count, nullptr);
ConsoleOutput(PIPE_CONNECTED);
@ -50,6 +50,15 @@ DWORD WINAPI Pipe(LPVOID)
NewHook(info.hp, ("UserHook" + std::to_string(userHooks += 1)).c_str());
}
break;
case HOST_COMMAND_INSERT_PC_HOOKS:
{
auto info = *(InsertPCHooksCmd *)buffer;
if (info.which == 0)
PcHooks::hookGdiGdiplusD3dxFunctions();
else if (info.which == 1)
PcHooks::hookOtherPcFunctions();
}
break;
case HOST_COMMAND_REMOVE_HOOK:
{
auto info = *(RemoveHookCmd *)buffer;

View File

@ -72,6 +72,10 @@ C_LUNA_API void Luna_Settings(int flushDelay, bool filterRepetition, int default
TextThread::maxHistorySize = maxHistorySize;
}
C_LUNA_API void Luna_InsertPCHooks(DWORD pid, int which)
{
Host::InsertPCHooks(pid, which);
}
C_LUNA_API bool Luna_InsertHookCode(DWORD pid, LPCWSTR hookcode)
{
auto hp = HookCode::Parse(hookcode);

View File

@ -350,6 +350,13 @@ namespace Host
prs.at(processId).Send(HOST_COMMAND_DETACH);
}
void InsertPCHooks(DWORD processId, int which)
{
auto &prs = processRecordsByIds.Acquire().contents;
if (prs.find(processId) == prs.end())
return;
prs.at(processId).Send(InsertPCHooksCmd(which));
}
void InsertHook(DWORD processId, HookParam hp)
{
auto &prs = processRecordsByIds.Acquire().contents;

View File

@ -17,6 +17,7 @@ namespace Host
void DetachProcess(DWORD processId);
void InsertHook(DWORD processId, HookParam hp);
void InsertPCHooks(DWORD processId, int which);
void RemoveHook(DWORD processId, uint64_t address);
void FindHooks(DWORD processId, SearchParam sp, HookEventHandler HookFound = {});
CommonSharedMem *GetCommonSharedMem(DWORD pid);

View File

@ -26,7 +26,8 @@ enum HostCommandType
HOST_COMMAND_FIND_HOOK,
HOST_COMMAND_MODIFY_HOOK,
HOST_COMMAND_HIJACK_PROCESS,
HOST_COMMAND_DETACH
HOST_COMMAND_DETACH,
HOST_COMMAND_INSERT_PC_HOOKS,
};
enum HostNotificationType

View File

@ -157,7 +157,12 @@ struct SearchParam
wchar_t text[PATTERN_SIZE] = {}; // text to search for
JITTYPE jittype;
};
struct InsertPCHooksCmd
{
InsertPCHooksCmd(int _which) : which(_which) {}
HostCommandType command = HOST_COMMAND_INSERT_PC_HOOKS;
int which;
};
struct InsertHookCmd // From host
{
InsertHookCmd(HookParam hp) : hp(hp) {}

View File

@ -16,7 +16,7 @@ from myutils.config import (
)
from myutils.localetools import getgamecamptools, maycreatesettings
from myutils.hwnd import getExeIcon
from myutils.wrapper import Singleton, Singleton_close
from myutils.wrapper import Singleton, Singleton_close, trypass
from myutils.utils import (
gamdidchangedtask,
checkpostlangmatch,
@ -58,6 +58,7 @@ from gui.dynalang import (
LAction,
LLabel,
LDialog,
LGroupBox,
)
from gui.dialog_savedgame_common import tagitem
@ -1005,8 +1006,33 @@ class dialog_setting_game_internal(QWidget):
"延迟注入_(ms)",
getspinbox(0, 1000000, savehook_new_data[gameuid], "inserthooktimeout"),
)
box = LGroupBox()
box.setTitle("额外的钩子")
settinglayout = LFormLayout()
box.setLayout(settinglayout)
formLayout.addRow(box)
settinglayout.addRow(
"Win32文字绘制函数钩子",
getsimpleswitch(
savehook_new_data[gameuid],
"insertpchooks_GdiGdiplusD3dx",
callback=lambda _: (
gobject.baseobject.textsource.InsertPCHooks(0) if _ else None
),
),
)
settinglayout.addRow(
"Win32字符串函数钩子",
getsimpleswitch(
savehook_new_data[gameuid],
"insertpchooks_string",
callback=lambda _: (
gobject.baseobject.textsource.InsertPCHooks(1) if _ else None
),
),
)
formLayout.addRow(
settinglayout.addRow(
"特殊码",
listediterline(
("特殊码"),
@ -1014,7 +1040,10 @@ class dialog_setting_game_internal(QWidget):
savehook_new_data[gameuid]["needinserthookcode"],
),
)
box = QGroupBox()
settinglayout = LFormLayout()
box.setLayout(settinglayout)
formLayout.addRow(box)
for k in [
"codepage_index",
"textthreaddelay",
@ -1028,7 +1057,7 @@ class dialog_setting_game_internal(QWidget):
formLayout2 = self.createfollowdefault(
savehook_new_data[gameuid],
"hooksetting_follow_default",
formLayout,
settinglayout,
lambda: gobject.baseobject.textsource.setsettings(),
)
formLayout2.addRow(

View File

@ -139,7 +139,9 @@ def getdefaultsavehook(title=None):
"statistic_wordcount_nodump": 0,
# "leuse": True, 废弃
"hook": [],
"inserthooktimeout": 1000,
"inserthooktimeout": 500,
"insertpchooks_GdiGdiplusD3dx": False,
"insertpchooks_string": False,
"needinserthookcode": [],
# "allow_tts_auto_names": "",#->v4
# "allow_tts_auto_names_v4": [],

View File

@ -192,6 +192,8 @@ class texthook(basetext):
)
self.Luna_SyncThread = LunaHost.Luna_SyncThread
self.Luna_SyncThread.argtypes = ThreadParam, c_bool
self.Luna_InsertPCHooks = LunaHost.Luna_InsertPCHooks
self.Luna_InsertPCHooks.argtypes = (DWORD, c_int)
self.Luna_Settings = LunaHost.Luna_Settings
self.Luna_Settings.argtypes = c_int, c_bool, c_int, c_int, c_int
self.Luna_Start = LunaHost.Luna_Start
@ -438,11 +440,19 @@ class texthook(basetext):
pass
for hookcode in self.needinserthookcode:
self.Luna_InsertHookCode(pid, hookcode)
if savehook_new_data[self.gameuid]["insertpchooks_GdiGdiplusD3dx"]:
self.Luna_InsertPCHooks(pid, 0)
if savehook_new_data[self.gameuid]["insertpchooks_string"]:
self.Luna_InsertPCHooks(pid, 1)
gobject.baseobject.displayinfomessage(
savehook_new_data[self.gameuid]["title"], "<msg_info_refresh>"
)
self.flashembedsettings(pid)
def InsertPCHooks(self, which):
for pid in self.pids:
self.Luna_InsertPCHooks(pid, which)
def newhookinsert(self, pid, addr, hcode):
for _hc, _addr, _ctx1, _ctx2 in savehook_new_data[self.gameuid][
"embedablehook"
@ -490,7 +500,7 @@ class texthook(basetext):
trans = kanjitrans(zhconv.convert(trans, "zh-tw"))
self.embedcallback(text, trans, tp)
def embedcallback(self, text: str, trans: str, tp:ThreadParam):
def embedcallback(self, text: str, trans: str, tp: ThreadParam):
trans = splitembedlines(trans)
self.Luna_embedcallback(tp, text, trans)

View File

@ -789,5 +789,8 @@
"延迟": "تأخر",
"开始": "بداية .",
"最长等待时间": "أقصى وقت الانتظار",
"截取行数": "اعتراض عدد الصفوف"
"截取行数": "اعتراض عدد الصفوف",
"Win32文字绘制函数钩子": "win32 وظيفة رسم النص هوك",
"Win32字符串函数钩子": "win32 سلسلة هوك",
"额外的钩子": "خطاف إضافية"
}

View File

@ -789,5 +789,8 @@
"延迟": "延遲",
"开始": "開始",
"最长等待时间": "最長等待時間",
"截取行数": "截取行數"
"截取行数": "截取行數",
"Win32文字绘制函数钩子": "Win32文字繪製函數鉤子",
"Win32字符串函数钩子": "Win32字串函數鉤子",
"额外的钩子": "額外的鉤子"
}

View File

@ -789,5 +789,8 @@
"延迟": "zpoždění",
"开始": "start",
"最长等待时间": "Maximální čekací doba",
"截取行数": "Snížit počet řádků"
"截取行数": "Snížit počet řádků",
"Win32文字绘制函数钩子": "Win32 funkce kreslení textu",
"Win32字符串函数钩子": "Win32 řetězcový funkční hák",
"额外的钩子": "Extra háčky"
}

View File

@ -789,5 +789,8 @@
"延迟": "Verzögerung",
"开始": "Start",
"最长等待时间": "Maximale Wartezeit",
"截取行数": "Anzahl der Zeilen abschneiden"
"截取行数": "Anzahl der Zeilen abschneiden",
"Win32文字绘制函数钩子": "Win32 Text Zeichenfunktion Hook",
"Win32字符串函数钩子": "Win32 String Function Hook",
"额外的钩子": "Zusätzliche Haken"
}

View File

@ -789,5 +789,8 @@
"延迟": "delay",
"开始": "start",
"最长等待时间": "Maximum waiting time",
"截取行数": "Cut the number of lines"
"截取行数": "Cut the number of lines",
"Win32文字绘制函数钩子": "Win32 text drawing function hook",
"Win32字符串函数钩子": "Win32 string function hook",
"额外的钩子": "Extra hooks"
}

View File

@ -789,5 +789,8 @@
"延迟": "Retraso",
"开始": "Empezar",
"最长等待时间": "Tiempo máximo de espera",
"截取行数": "Número de líneas interceptadas"
"截取行数": "Número de líneas interceptadas",
"Win32文字绘制函数钩子": "Gancho de función de dibujo de texto Win32",
"Win32字符串函数钩子": "Gancho de función de cadena Win32",
"额外的钩子": "Ganchos adicionales"
}

View File

@ -789,5 +789,8 @@
"延迟": "Retard",
"开始": "Commencer",
"最长等待时间": "Temps d'attente maximum",
"截取行数": "Nombre de lignes interceptées"
"截取行数": "Nombre de lignes interceptées",
"Win32文字绘制函数钩子": "Win32 crochet de fonction de dessin de texte",
"Win32字符串函数钩子": "Crochet de fonction de chaîne Win32",
"额外的钩子": "Crochets supplémentaires"
}

View File

@ -789,5 +789,8 @@
"延迟": "ritardo",
"开始": "inizio",
"最长等待时间": "Tempo massimo di attesa",
"截取行数": "Taglia il numero di righe"
"截取行数": "Taglia il numero di righe",
"Win32文字绘制函数钩子": "Gancio della funzione di disegno del testo Win32",
"Win32字符串函数钩子": "Aggancio della funzione stringa Win32",
"额外的钩子": "Ganci supplementari"
}

View File

@ -789,5 +789,8 @@
"延迟": "遅延",
"开始": "スタート",
"最长等待时间": "最長待ち時間",
"截取行数": "切り取り行数"
"截取行数": "切り取り行数",
"Win32文字绘制函数钩子": "Win 32文字描画関数フック",
"Win32字符串函数钩子": "Win 32文字列関数フック",
"额外的钩子": "エクストラフック"
}

View File

@ -789,5 +789,8 @@
"延迟": "지연",
"开始": "시작",
"最长等待时间": "최대 대기 시간",
"截取行数": "행 수 캡처"
"截取行数": "행 수 캡처",
"Win32文字绘制函数钩子": "Win32 텍스트 그리기 함수 갈고리",
"Win32字符串函数钩子": "Win32 문자열 함수 후크",
"额外的钩子": "추가 갈고리"
}

View File

@ -789,5 +789,8 @@
"延迟": "vertraging",
"开始": "start",
"最长等待时间": "Maximale wachttijd",
"截取行数": "Aantal regels snijden"
"截取行数": "Aantal regels snijden",
"Win32文字绘制函数钩子": "Win32 teksttekenfunctiehook",
"Win32字符串函数钩子": "Win32 tekenfunctiehook",
"额外的钩子": "Extra haken"
}

View File

@ -789,5 +789,8 @@
"延迟": "opóźnienie",
"开始": "uruchomić",
"最长等待时间": "Maksymalny czas oczekiwania",
"截取行数": "Wyciąć liczbę linii"
"截取行数": "Wyciąć liczbę linii",
"Win32文字绘制函数钩子": "Hook funkcji rysowania tekstu Win32",
"Win32字符串函数钩子": "Hook funkcji ciągów Win32",
"额外的钩子": "Dodatkowe haki"
}

View File

@ -789,5 +789,8 @@
"延迟": "atraso",
"开始": "iniciar",
"最长等待时间": "Tempo máximo de espera",
"截取行数": "Cortar o número de linhas"
"截取行数": "Cortar o número de linhas",
"Win32文字绘制函数钩子": "Gancho de função de desenho de texto Win32",
"Win32字符串函数钩子": "Gancho de função de cadeia Win32",
"额外的钩子": "Ganchos extra"
}

View File

@ -789,5 +789,8 @@
"延迟": "Задержка",
"开始": "Начинаем.",
"最长等待时间": "Максимальное время ожидания",
"截取行数": "Количество перехваченных строк"
"截取行数": "Количество перехваченных строк",
"Win32文字绘制函数钩子": "Win32 Графический крюк",
"Win32字符串函数钩子": "Win32 Строчный крюк",
"额外的钩子": "Дополнительный крюк"
}

View File

@ -789,5 +789,8 @@
"延迟": "fördröjning",
"开始": "start",
"最长等待时间": "Maximal väntetid",
"截取行数": "Klipp av antalet rader"
"截取行数": "Klipp av antalet rader",
"Win32文字绘制函数钩子": "Win32 textritfunktionskrok",
"Win32字符串函数钩子": "Win32 strängfunktionskrok",
"额外的钩子": "Extra krokar"
}

View File

@ -789,5 +789,8 @@
"延迟": "ความล่าช้า",
"开始": "เริ่มต้นใช้งาน",
"最长等待时间": "ระยะเวลารอคอยนานที่สุด",
"截取行数": "จำนวนแถวที่ถูกสกัดกั้น"
"截取行数": "จำนวนแถวที่ถูกสกัดกั้น",
"Win32文字绘制函数钩子": "Win32 วาดคำฟังก์ชันตะขอ",
"Win32字符串函数钩子": "Win32 ฟังก์ชั่นสตริงตะขอ",
"额外的钩子": "ตะขอเพิ่มเติม"
}

View File

@ -789,5 +789,8 @@
"延迟": "gecikme",
"开始": "başlat",
"最长等待时间": "Maksimum bekleme zamanı",
"截取行数": "Çizgi sayısını kesin"
"截取行数": "Çizgi sayısını kesin",
"Win32文字绘制函数钩子": "Win32 metin çizim fonksiyonu çubuğu",
"Win32字符串函数钩子": "Win32 string fonksiyonu",
"额外的钩子": "Ekstra hücreler"
}

View File

@ -789,5 +789,8 @@
"延迟": "затримка",
"开始": "початок",
"最长等待时间": "Максимальний час чекання",
"截取行数": "Вирізати кількість рядків"
"截取行数": "Вирізати кількість рядків",
"Win32文字绘制函数钩子": "Хук функції малювання тексту Win32",
"Win32字符串函数钩子": "Хук функції рядка Win32",
"额外的钩子": "Додаткові хаки"
}

View File

@ -789,5 +789,8 @@
"延迟": "Trì hoãn",
"开始": "Bắt đầu",
"最长等待时间": "Thời gian chờ tối đa",
"截取行数": "Số dòng bị chặn"
"截取行数": "Số dòng bị chặn",
"Win32文字绘制函数钩子": "Win32 Chức năng vẽ văn bản Hook",
"Win32字符串函数钩子": "Win32 Chuỗi chức năng Hook",
"额外的钩子": "Thêm móc"
}

View File

@ -789,5 +789,8 @@
"核心设置": "",
"开始": "",
"截取行数": "",
"最长等待时间": ""
"最长等待时间": "",
"Win32文字绘制函数钩子": "",
"Win32字符串函数钩子": "",
"额外的钩子": ""
}