From d60bbd8b5ac72a2dfb749c1e22c7232dc2de2795 Mon Sep 17 00:00:00 2001 From: mingkuang Date: Mon, 27 May 2024 15:15:42 +0800 Subject: [PATCH] =?UTF-8?q?Fea=20#71,=20=E4=BC=98=E5=8C=96DrawThemeTextEx?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=EF=BC=8C=E4=B8=8D=E5=AD=98=E5=9C=A8=E6=97=B6?= =?UTF-8?q?=E4=BC=98=E5=85=88=E8=B0=83=E7=94=A8uxtheme=E5=86=85=E9=83=A8?= =?UTF-8?q?=E9=9D=9E=E5=AF=BC=E5=87=BA=E5=87=BD=E6=95=B0=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ThunksList.md | 2 +- src/Thunks/YY_Thunks.cpp | 41 +++++++++++++++++++++-------------- src/Thunks/YY_Thunks.h | 46 ++++++++++++++++++++++++++++------------ src/Thunks/uxtheme.hpp | 40 ++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 31 deletions(-) diff --git a/ThunksList.md b/ThunksList.md index 44e743f..9d23f43 100644 --- a/ThunksList.md +++ b/ThunksList.md @@ -565,7 +565,7 @@ ## uxtheme.dll | 函数 | Fallback | ---- | ----------- -| DrawThemeTextEx | 不存在时,调用DrawThemeText。 +| DrawThemeTextEx | 不存在时,尝试获取非导出DrawThemeTextEx。如果任然获取失败则调用DrawThemeText。 | GetThemeTransitionDuration | 不存在时,返回E_NOTIMPL。 | SetWindowThemeAttribute | 不存在时,返回E_NOTIMPL。 diff --git a/src/Thunks/YY_Thunks.cpp b/src/Thunks/YY_Thunks.cpp index 083b9e2..8618d6c 100644 --- a/src/Thunks/YY_Thunks.cpp +++ b/src/Thunks/YY_Thunks.cpp @@ -165,19 +165,7 @@ RtlCutoverTimeToSystemTime( #define __DEFINE_THUNK(_MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) \ __APPLY_UNIT_TEST_BOOL(_FUNCTION); \ EXTERN_C _RETURN_ _CONVENTION_ _FUNCTION(__VA_ARGS__); \ - static decltype(_FUNCTION)* __cdecl _CRT_CONCATENATE(try_get_, _FUNCTION)() noexcept \ - { \ - __CHECK_UNIT_TEST_BOOL(_FUNCTION); \ - __declspec(allocate(".YYThr$AAA")) static void* _CRT_CONCATENATE(pInit_ ,_FUNCTION) = \ - reinterpret_cast(&_CRT_CONCATENATE(try_get_, _FUNCTION)); \ - /*为了避免编译器将 YYThr$AAA 节优化掉*/ \ - __foreinclude(_CRT_CONCATENATE(pInit_ ,_FUNCTION)); \ - __declspec(allocate(".YYThu$AAB")) static void* _CRT_CONCATENATE(pFun_, _FUNCTION); \ - return reinterpret_cast(try_get_function( \ - &_CRT_CONCATENATE(pFun_ ,_FUNCTION), \ - _CRT_STRINGIZE(_FUNCTION), \ - &_CRT_CONCATENATE(try_get_module_, _MODULE))); \ - } \ + static decltype(_FUNCTION)* __cdecl _CRT_CONCATENATE(try_get_, _FUNCTION)() noexcept; \ __if_not_exists(_CRT_CONCATENATE(try_get_, _FUNCTION)) @@ -770,9 +758,30 @@ namespace YY::Thunks::internal //导入实际的实现 #define YY_Thunks_Implemented -#define __DEFINE_THUNK(_MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) \ - _LCRT_DEFINE_IAT_SYMBOL(_FUNCTION, _SIZE); \ - _YY_THUNKS_DEFINE_RUST_RAW_DYLIB_IAT_SYMBOL(_FUNCTION, _SIZE); \ +#define __DEFINE_THUNK(_MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) \ + static decltype(_FUNCTION)* __cdecl _CRT_CONCATENATE(try_get_, _FUNCTION)() noexcept \ + { \ + __CHECK_UNIT_TEST_BOOL(_FUNCTION); \ + __declspec(allocate(".YYThr$AAA")) static void* _CRT_CONCATENATE(pInit_ ,_FUNCTION) = \ + reinterpret_cast(&_CRT_CONCATENATE(try_get_, _FUNCTION)); \ + /*为了避免编译器将 YYThr$AAA 节优化掉*/ \ + __foreinclude(_CRT_CONCATENATE(pInit_ ,_FUNCTION)); \ + __declspec(allocate(".YYThu$AAB")) static void* _CRT_CONCATENATE(pFun_, _FUNCTION); \ + static const ProcInfo _ProcInfo = \ + { \ + _CRT_STRINGIZE(_FUNCTION), \ + &_CRT_CONCATENATE(try_get_module_, _MODULE), \ +__if_exists(YY::Thunks::Fallback::_CRT_CONCATENATE(try_get_, _FUNCTION)) \ +{ \ + &YY::Thunks::Fallback::_CRT_CONCATENATE(try_get_, _FUNCTION) \ +} \ + }; \ + return reinterpret_cast(try_get_function( \ + &_CRT_CONCATENATE(pFun_ ,_FUNCTION), \ + _ProcInfo)); \ + } \ + _LCRT_DEFINE_IAT_SYMBOL(_FUNCTION, _SIZE); \ + _YY_THUNKS_DEFINE_RUST_RAW_DYLIB_IAT_SYMBOL(_FUNCTION, _SIZE); \ EXTERN_C _RETURN_ _CONVENTION_ _FUNCTION(__VA_ARGS__) #include "YY_Thunks_List.hpp" diff --git a/src/Thunks/YY_Thunks.h b/src/Thunks/YY_Thunks.h index 2d3f016..b3ab4fe 100644 --- a/src/Thunks/YY_Thunks.h +++ b/src/Thunks/YY_Thunks.h @@ -309,7 +309,7 @@ static HMODULE __fastcall try_get_module(volatile HMODULE* pModule, const wchar_ } #define _APPLY(_MODULE, _NAME, _FLAGS) \ - static volatile HMODULE __fastcall _CRT_CONCATENATE(try_get_module_, _MODULE)() noexcept \ + static HMODULE __fastcall _CRT_CONCATENATE(try_get_module_, _MODULE)() noexcept \ { \ __declspec(allocate(".YYThu$AAA")) static volatile HMODULE hModule; \ return try_get_module<_FLAGS>(&hModule, _CRT_CONCATENATE(module_name_, _MODULE)); \ @@ -317,20 +317,31 @@ static HMODULE __fastcall try_get_module(volatile HMODULE* pModule, const wchar_ _YY_APPLY_TO_LATE_BOUND_MODULES(_APPLY) #undef _APPLY -typedef volatile HMODULE (__fastcall* try_get_module_fun)(); +typedef HMODULE (__fastcall* try_get_module_fun)(); +typedef void*(__fastcall* try_get_proc_fallback_fun)(); + +struct ProcInfo +{ + char const* const szProcName; + try_get_module_fun pfnGetModule; + try_get_proc_fallback_fun pfnGetProcFallback; +}; static __forceinline void* __fastcall try_get_proc_address_from_first_available_module( - try_get_module_fun get_module, - char const* const name -) noexcept + const ProcInfo& _ProcInfo + ) noexcept { - HMODULE const module_handle = get_module(); + HMODULE const module_handle = _ProcInfo.pfnGetModule(); if (!module_handle) { return nullptr; } - return reinterpret_cast(GetProcAddress(module_handle, name)); + auto _pProc = reinterpret_cast(GetProcAddress(module_handle, _ProcInfo.szProcName)); + if (_pProc || _ProcInfo.pfnGetProcFallback == nullptr) + return _pProc; + + return _ProcInfo.pfnGetProcFallback(); } @@ -342,9 +353,8 @@ static __forceinline void* __cdecl invalid_function_sentinel() noexcept static void* __fastcall try_get_function( void** ppFunAddress, - char const* const name, - try_get_module_fun get_module -) noexcept + const ProcInfo& _ProcInfo + ) noexcept { // First check to see if we've cached the function pointer: { @@ -365,7 +375,7 @@ static void* __fastcall try_get_function( // If we haven't yet cached the function pointer, try to import it from any // of the modules in which it might be defined. If this fails, cache the // sentinel pointer so that we don't attempt to load this function again: - void* const new_fp = try_get_proc_address_from_first_available_module(get_module, name); + void* const new_fp = try_get_proc_address_from_first_available_module(_ProcInfo); if (!new_fp) { void* const cached_fp = __crt_fast_decode_pointer( @@ -406,15 +416,23 @@ static void* __fastcall try_get_function( static _CRT_CONCATENATE(_FUNCTION, _pft) __cdecl _CRT_CONCATENATE(try_get_, _FUNCTION)() noexcept \ { \ __CHECK_UNIT_TEST_BOOL(_FUNCTION); \ - __declspec(allocate(".YYThr$AAA")) static void* _CRT_CONCATENATE(pInit_ ,_FUNCTION) = \ + __declspec(allocate(".YYThr$AAA")) static void* const _CRT_CONCATENATE(pInit_ ,_FUNCTION) = \ reinterpret_cast(&_CRT_CONCATENATE(try_get_, _FUNCTION)); \ /*为了避免编译器将 YYThr$AAA 节优化掉*/ \ __foreinclude(_CRT_CONCATENATE(pInit_ ,_FUNCTION)); \ __declspec(allocate(".YYThu$AAB")) static void* _CRT_CONCATENATE( pFun_ ,_FUNCTION); \ + static const ProcInfo _ProcInfo = \ + { \ + _CRT_STRINGIZE(_FUNCTION), \ + &_CRT_CONCATENATE(try_get_module_, _MODULE), \ +__if_exists(YY::Thunks::Fallback::_CRT_CONCATENATE(try_get_, _FUNCTION)) \ +{ \ + &YY::Thunks::Fallback::_CRT_CONCATENATE(try_get_, _FUNCTION) \ +} \ + }; \ return reinterpret_cast<_CRT_CONCATENATE(_FUNCTION, _pft)>(try_get_function( \ &_CRT_CONCATENATE(pFun_ ,_FUNCTION), \ - _CRT_STRINGIZE(_FUNCTION), \ - &_CRT_CONCATENATE(try_get_module_, _MODULE))); \ + _ProcInfo)); \ } _YY_APPLY_TO_LATE_BOUND_FUNCTIONS(_APPLY) #undef _APPLY diff --git a/src/Thunks/uxtheme.hpp b/src/Thunks/uxtheme.hpp index a283ef7..f8242dd 100644 --- a/src/Thunks/uxtheme.hpp +++ b/src/Thunks/uxtheme.hpp @@ -4,6 +4,40 @@ #pragma comment(lib, "UxTheme.lib") #endif +#if defined(YY_Thunks_Implemented) && defined(_X86_) && (YY_Thunks_Support_Version < NTDDI_WIN6) +namespace YY::Thunks::Fallback +{ + static void* __fastcall try_get_DrawThemeTextEx() noexcept + { + auto _pUxThemeBase = (const char*)try_get_module_uxtheme(); + if (!_pUxThemeBase) + return nullptr; + + MEMORY_BASIC_INFORMATION _BaseInfo; + + // Windows XP SP3 其实已经实现了DrawThemeTextEx,只是没有导出。 + static const BYTE kAttributeCode_6_0_2900_5512[] = + { + 0x8B, 0xFF, 0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x0C, + 0x83, 0x4D, 0xF8, 0xFF, 0x83, 0x65, 0xF4, 0x00, + 0x83, 0x7D, 0x0C, 0x00, 0x56, + }; + constexpr auto kAttributeCode_6_0_2900_5512_Offset = 0x5ADC2FF8 - 0x5ADC0000; + auto _pTarget = _pUxThemeBase + kAttributeCode_6_0_2900_5512_Offset; + if (VirtualQuery(_pTarget, &_BaseInfo, sizeof(_BaseInfo)) && _BaseInfo.AllocationBase == _pUxThemeBase) + { + if (memcmp(_pTarget, kAttributeCode_6_0_2900_5512, sizeof(kAttributeCode_6_0_2900_5512)) == 0) + { + return (void*)_pTarget; + } + } + + return nullptr; + } +} +#endif + + namespace YY::Thunks { #if (YY_Thunks_Support_Version < NTDDI_WIN6) @@ -60,6 +94,12 @@ namespace YY::Thunks return _pfnGetThemeTransitionDuration(hTheme, iPartId, iStateIdFrom, iStateIdTo, iPropId, pdwDuration); } + if (pdwDuration == nullptr || iStateIdFrom <= 0 || iStateIdTo <= 0) + { + return E_INVALIDARG; + } + + *pdwDuration = 0; return E_NOTIMPL; } #endif