├── src ├── Build.cmd ├── def │ ├── x64 │ │ ├── PSAPI2Kernel32.def │ │ └── esent.def │ └── x86 │ │ ├── PSAPI2Kernel32.def │ │ └── esent.def ├── YY-Thunks.UnitTest │ ├── weak.c │ ├── proxy.pac │ ├── TestProject │ │ └── Example │ │ │ ├── main.cpp │ │ │ ├── SymbolBuildTest.vcxproj.filters │ │ │ └── SymbolBuildTest.vcxproj │ ├── pch.cpp │ ├── api-ms-win-core-kernel32-legacy.UnitTest.cpp │ ├── api-ms-win-power-base.UnitTest.cpp │ ├── PropSys.UnitTest.cpp │ ├── shell32.UnitTest.cpp │ ├── Crypt32.UnitTest.cpp │ ├── api-ms-win-core-fibers.UnitTest.cpp │ ├── pch.h │ └── api-ms-win-appmodel-runtime.UnitTest.cpp ├── Thunks │ ├── d3d9.hpp │ ├── api-ms-win-core-rtlsupport.hpp │ ├── BCryptPrimitives.hpp │ ├── mfreadwrite.hpp │ ├── api-ms-win-core-util.hpp │ ├── ext-ms-win-ntuser-misc.hpp │ ├── mmdevapi.hpp │ ├── api-ms-win-core-processtopology.hpp │ ├── api-ms-win-core-windowserrorreporting.hpp │ ├── netapi32.hpp │ ├── dxva2.hpp │ ├── ext-ms-win-ntuser-gui.hpp │ ├── Pdh.hpp │ ├── mf.hpp │ ├── api-ms-win-core-datetime.hpp │ ├── ndfapi.hpp │ ├── d3d11.hpp │ ├── dxgi.hpp │ ├── d3d12.hpp │ ├── dbghelp.hpp │ ├── api-ms-win-core-psapi.hpp │ ├── ext-ms-win-ntuser-sysparams-ext.hpp │ ├── api-ms-win-core-processtopology-obsolete.hpp │ ├── api-ms-win-core-version.hpp │ ├── dcomp.hpp │ ├── api-ms-win-core-errorhandling.hpp │ ├── wevtapi.hpp │ ├── userenv.hpp │ ├── uxtheme.hpp │ ├── ext-ms-win-ntuser-powermanagement.hpp │ ├── api-ms-win-core-interlocked.hpp │ ├── shlwapi.hpp │ ├── api-ms-win-core-winrt-error.hpp │ ├── api-ms-win-power-base.hpp │ ├── psapi.hpp │ ├── ext-ms-win-ntuser-window.hpp │ ├── ntdll.hpp │ ├── Crypt32.hpp │ └── api-ms-win-core-com.hpp ├── MinimumRequiredVersionHelper │ ├── MinimumRequiredVersionHelper.vcxproj.filters │ └── MinimumRequiredVersionHelper.cpp ├── Directory.Build.props ├── Shared │ ├── List.h │ ├── HStringPrivate.h │ ├── InterlockedQueue.h │ ├── SharedDefs.h │ └── HookThunk.h ├── YY_Thunks.sln └── YY.Depends.Analyzer │ └── YY.Depends.Analyzer.vcxproj.filters ├── .editorconfig ├── LICENSE ├── NuGet ├── YY-Thunks.nuspec └── build │ ├── native │ ├── YY-Thunks_ui_D5D733D3-8829-4509-9C74-021E5685ED18.xml │ └── YY-Thunks.targets │ └── net8.0-windows7.0 │ └── YY-Thunks.targets ├── .github └── ISSUE_TEMPLATE │ ├── Feature_Request_zh-cn.yml │ ├── Bug_Report_zh-cn.yml │ ├── Feature_Request_en.yml │ └── Bug_Report_en.yml └── .gitattributes /src/Build.cmd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chuyu-Team/YY-Thunks/HEAD/src/Build.cmd -------------------------------------------------------------------------------- /src/def/x64/PSAPI2Kernel32.def: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chuyu-Team/YY-Thunks/HEAD/src/def/x64/PSAPI2Kernel32.def -------------------------------------------------------------------------------- /src/def/x86/PSAPI2Kernel32.def: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chuyu-Team/YY-Thunks/HEAD/src/def/x86/PSAPI2Kernel32.def -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/weak.c: -------------------------------------------------------------------------------- 1 | 2 | const void* __acrt_atexit_table; 3 | 4 | const void* __pfnDllMainCRTStartupForYY_Thunks; 5 | 6 | const void* __YY_Thunks_Disable_Rreload_Dlls; 7 | 8 | const void* __pfnYY_Thunks_CustomLoadLibrary; 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | 4 | # 代码文件尽可能的使用 UTF-8,因为英语字符占据大多数。 5 | # 数据文件比如 XML,json统一缩进 2,因为外部规范往往如此 6 | 7 | [*] 8 | end_of_line = crlf 9 | insert_final_newline = true 10 | charset = utf-8-bom 11 | indent_style = space 12 | indent_size = 4 13 | 14 | [*.{vcxproj,xml,nuspec,targets}] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [*.cmd] 19 | charset = unset 20 | -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/proxy.pac: -------------------------------------------------------------------------------- 1 | function FindProxyForURL(url, host) { 2 | 3 | if (shExpMatch(host, '*.test1.com')) { return "PROXY 192.168.18.193:1081"; } 4 | 5 | if (shExpMatch(host, '*.test2.com')) { return "HTTPS 192.168.18.193"; } 6 | 7 | if (shExpMatch(host, '*.test3.com')) { return "PROXY 192.168.18.193; PROXY 192.168.18.194:100;"; } 8 | 9 | if (shExpMatch(host, '*.test4.com')) { return "HTTPS 192.168.18.193; HTTPS 192.168.18.194:102; PROXY 192.168.18.195:103"; } 10 | 11 | return 'DIRECT'; 12 | } 13 | -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/TestProject/Example/main.cpp: -------------------------------------------------------------------------------- 1 | // SymbolBuildTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 2 | // 3 | 4 | #include 5 | 6 | #include 7 | 8 | // DllMainCRTStartupForYY_Thunks是YY-Thunks中的一个内置符号,强制引用它如果链接成功则说明YY-Thunks肯定被依赖上了。 9 | extern "C" BOOL WINAPI DllMainCRTStartupForYY_Thunks( 10 | HINSTANCE const _hInstance, 11 | DWORD const _uReason, 12 | LPVOID const _pReserved 13 | ); 14 | 15 | int main() 16 | { 17 | printf("%p\n", &DllMainCRTStartupForYY_Thunks); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /src/Thunks/d3d9.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #if (YY_Thunks_Target < __WindowsNT6) 8 | 9 | __DEFINE_THUNK( 10 | d3d9, 11 | 8, 12 | HRESULT, 13 | WINAPI, 14 | Direct3DCreate9Ex, 15 | UINT SDKVersion, 16 | IDirect3D9Ex** unnamedParam2 17 | ) 18 | { 19 | if (const auto _pfnDirect3DCreate9Ex = try_get_Direct3DCreate9Ex()) 20 | { 21 | return _pfnDirect3DCreate9Ex(SDKVersion, unnamedParam2); 22 | } 23 | 24 | if (unnamedParam2) 25 | *unnamedParam2 = nullptr; 26 | return D3DERR_NOTAVAILABLE; 27 | } 28 | #endif 29 | } 30 | -------------------------------------------------------------------------------- /src/Thunks/api-ms-win-core-rtlsupport.hpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | namespace YY::Thunks 4 | { 5 | #if (YY_Thunks_Target < __WindowsNT5_1) 6 | 7 | // Available in starting with Windows XP. 8 | // Windows 2000时这个函数就已经存在了,只是从XP开始才从kernel32.dll中导出 9 | __DEFINE_THUNK( 10 | ntdll, 11 | 16, 12 | WORD, 13 | NTAPI, 14 | RtlCaptureStackBackTrace, 15 | _In_ DWORD _uFramesToSkip, 16 | _In_ DWORD _uFramesToCapture, 17 | _Out_writes_to_(_uFramesToCapture, return) PVOID* _pBackTrace, 18 | _Out_opt_ PDWORD _puBackTraceHash 19 | ) 20 | { 21 | if (const auto _pfnRtlCaptureStackBackTrace = try_get_RtlCaptureStackBackTrace()) 22 | { 23 | return _pfnRtlCaptureStackBackTrace(_uFramesToSkip, _uFramesToCapture, _pBackTrace, _puBackTraceHash); 24 | } 25 | 26 | return 0; 27 | } 28 | #endif 29 | } 30 | -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/pch.cpp: -------------------------------------------------------------------------------- 1 | // pch.cpp: 与预编译标头对应的源文件 2 | 3 | #include "pch.h" 4 | 5 | // 当使用预编译的头时,需要使用此源文件,编译才能成功。 6 | std::string ReadFileData(LPCWSTR _szFilePath) 7 | { 8 | std::string _FileData; 9 | auto _hFile = CreateFileW(_szFilePath, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); 10 | if (_hFile == INVALID_HANDLE_VALUE) 11 | return _FileData; 12 | 13 | LARGE_INTEGER _FileSize; 14 | if (GetFileSizeEx(_hFile, &_FileSize)) 15 | { 16 | if (_FileSize.HighPart) 17 | { 18 | // 不支持超过4GB的文件 19 | return _FileData; 20 | } 21 | 22 | _FileData.resize(_FileSize.LowPart); 23 | 24 | if (!ReadFile(_hFile, _FileData.data(), _FileSize.LowPart, &_FileSize.LowPart, nullptr)) 25 | _FileData.clear(); 26 | } 27 | 28 | CloseHandle(_hFile); 29 | return _FileData; 30 | } 31 | -------------------------------------------------------------------------------- /src/Thunks/BCryptPrimitives.hpp: -------------------------------------------------------------------------------- 1 | 2 | extern "C" BOOL WINAPI ProcessPrng( 3 | _Out_writes_bytes_(_cbBuffer) PUCHAR _pbBuffer, 4 | _In_ ULONG _cbBuffer 5 | ); 6 | 7 | namespace YY::Thunks 8 | { 9 | #if (YY_Thunks_Target < __WindowsNT6_2) 10 | 11 | // 用户反馈Windows 7也会报告此API不存在。 12 | __DEFINE_THUNK( 13 | bcryptprimitives, 14 | 8, 15 | BOOL, 16 | WINAPI, 17 | ProcessPrng, 18 | _Out_writes_bytes_(_cbBuffer) PUCHAR _pbBuffer, 19 | _In_ ULONG _cbBuffer 20 | ) 21 | { 22 | if (auto _pfnProcessPrng = try_get_ProcessPrng()) 23 | { 24 | return _pfnProcessPrng(_pbBuffer, _cbBuffer); 25 | } 26 | 27 | const auto _pfnRtlGenRandom = try_get_SystemFunction036(); 28 | if (!_pfnRtlGenRandom) 29 | { 30 | SetLastError(ERROR_FUNCTION_FAILED); 31 | return FALSE; 32 | } 33 | 34 | return _pfnRtlGenRandom(_pbBuffer, _cbBuffer); 35 | } 36 | #endif 37 | } // namespace YY::Thunks 38 | -------------------------------------------------------------------------------- /src/MinimumRequiredVersionHelper/MinimumRequiredVersionHelper.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 源文件 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Thunks/mfreadwrite.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6_1) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #if (YY_Thunks_Target < __WindowsNT6_1) 8 | 9 | // 最低受支持的客户端 适用于 Windows Vista 的 Windows 7、Windows Vista 和平台更新补充 [桌面应用 |UWP 应用] 10 | // 最低受支持的服务器 Windows Server 2008 R2[桌面应用 | UWP 应用] 11 | __DEFINE_THUNK( 12 | mfreadwrite, 13 | 12, 14 | HRESULT, 15 | STDAPICALLTYPE, 16 | MFCreateSourceReaderFromMediaSource, 17 | _In_ IMFMediaSource* pMediaSource, 18 | _In_opt_ IMFAttributes* pAttributes, 19 | _Out_ IMFSourceReader** ppSourceReader 20 | ) 21 | { 22 | if (const auto _pfnMFCreateSourceReaderFromMediaSource = try_get_MFCreateSourceReaderFromMediaSource()) 23 | { 24 | return _pfnMFCreateSourceReaderFromMediaSource(pMediaSource, pAttributes, ppSourceReader); 25 | } 26 | 27 | if (!ppSourceReader) 28 | return E_POINTER; 29 | 30 | *ppSourceReader = nullptr; 31 | return E_NOTIMPL; 32 | } 33 | #endif 34 | } 35 | -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/TestProject/Example/SymbolBuildTest.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 源文件 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Chuyu-Team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Thunks/api-ms-win-core-util.hpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | namespace YY::Thunks 4 | { 5 | #if (YY_Thunks_Target < __WindowsNT5_2_SP1) 6 | 7 | //Windows XP with SP2, Windows Server 2003 with SP1 8 | __DEFINE_THUNK( 9 | kernel32, 10 | 4, 11 | PVOID, 12 | WINAPI, 13 | DecodePointer, 14 | _In_opt_ PVOID Ptr 15 | ) 16 | { 17 | if (auto const pDecodePointer = try_get_DecodePointer()) 18 | { 19 | return pDecodePointer(Ptr); 20 | } 21 | else 22 | { 23 | return Ptr; 24 | } 25 | } 26 | #endif 27 | 28 | 29 | #if (YY_Thunks_Target < __WindowsNT5_2_SP1) 30 | 31 | //Windows XP with SP2, Windows Server 2003 with SP1 32 | __DEFINE_THUNK( 33 | kernel32, 34 | 4, 35 | PVOID, 36 | WINAPI, 37 | EncodePointer, 38 | _In_opt_ PVOID Ptr 39 | ) 40 | { 41 | if (auto const pEncodePointer = try_get_EncodePointer()) 42 | { 43 | return pEncodePointer(Ptr); 44 | } 45 | else 46 | { 47 | return Ptr; 48 | } 49 | } 50 | #endif 51 | } //namespace YY::Thunks 52 | -------------------------------------------------------------------------------- /src/Thunks/ext-ms-win-ntuser-misc.hpp: -------------------------------------------------------------------------------- 1 | namespace YY::Thunks 2 | { 3 | #if (YY_Thunks_Target < __WindowsNT6) 4 | 5 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 6 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 7 | __DEFINE_THUNK( 8 | user32, 9 | 4, 10 | BOOL, 11 | WINAPI, 12 | AddClipboardFormatListener, 13 | _In_ HWND _hWnd 14 | ) 15 | { 16 | if (const auto _pfnAddClipboardFormatListener = try_get_AddClipboardFormatListener()) 17 | { 18 | return _pfnAddClipboardFormatListener(_hWnd); 19 | } 20 | 21 | return TRUE; 22 | } 23 | #endif 24 | 25 | 26 | #if (YY_Thunks_Target < __WindowsNT6) 27 | 28 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 29 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 30 | __DEFINE_THUNK( 31 | user32, 32 | 4, 33 | BOOL, 34 | WINAPI, 35 | RemoveClipboardFormatListener, 36 | _In_ HWND _hWnd 37 | ) 38 | { 39 | if (const auto _pfnRemoveClipboardFormatListener = try_get_RemoveClipboardFormatListener()) 40 | { 41 | return _pfnRemoveClipboardFormatListener(_hWnd); 42 | } 43 | 44 | return TRUE; 45 | } 46 | #endif 47 | } 48 | -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/api-ms-win-core-kernel32-legacy.UnitTest.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "CppUnitTest.h" 3 | 4 | #include "Thunks/api-ms-win-core-kernel32-legacy.hpp" 5 | 6 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 7 | 8 | 9 | namespace api_ms_win_core_kernel32_legacy 10 | { 11 | TEST_CLASS(PowerRequest) 12 | { 13 | AwaysNullGuard Guard; 14 | 15 | public: 16 | PowerRequest() 17 | { 18 | Guard |= YY::Thunks::aways_null_try_get_PowerCreateRequest; 19 | Guard |= YY::Thunks::aways_null_try_get_PowerSetRequest; 20 | Guard |= YY::Thunks::aways_null_try_get_PowerClearRequest; 21 | } 22 | 23 | TEST_METHOD(Set然后Clear) 24 | { 25 | REASON_CONTEXT _Context = { POWER_REQUEST_CONTEXT_VERSION }; 26 | auto _hPower = ::PowerCreateRequest(&_Context); 27 | Assert::AreNotEqual(_hPower, INVALID_HANDLE_VALUE); 28 | 29 | auto _bRet = PowerSetRequest(_hPower, POWER_REQUEST_TYPE::PowerRequestAwayModeRequired); 30 | Assert::IsTrue(_bRet); 31 | 32 | _bRet = PowerClearRequest(_hPower, POWER_REQUEST_TYPE::PowerRequestAwayModeRequired); 33 | Assert::IsTrue(_bRet); 34 | 35 | CloseHandle(_hPower); 36 | } 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /src/Thunks/mmdevapi.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6_2) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #if (YY_Thunks_Target < __WindowsNT6_2) 8 | 9 | // 最低受支持的客户端 Windows 8 [桌面应用 |UWP 应用] 10 | // 最低受支持的服务器 Windows Server 2012 [桌面应用 |UWP 应用] 11 | __DEFINE_THUNK( 12 | mmdevapi, 13 | 20, 14 | HRESULT, 15 | STDAPICALLTYPE, 16 | ActivateAudioInterfaceAsync, 17 | _In_ LPCWSTR _szDeviceInterfacePath, 18 | _In_ REFIID riid, 19 | _In_opt_ PROPVARIANT* _pActivationParams, 20 | _In_ IActivateAudioInterfaceCompletionHandler* _pCompletionHandler, 21 | _COM_Outptr_ IActivateAudioInterfaceAsyncOperation** _ppActivationOperation 22 | ) 23 | { 24 | if (const auto _pfnActivateAudioInterfaceAsync = try_get_ActivateAudioInterfaceAsync()) 25 | { 26 | return _pfnActivateAudioInterfaceAsync(_szDeviceInterfacePath, riid, _pActivationParams, _pCompletionHandler, _ppActivationOperation); 27 | } 28 | 29 | if (!_ppActivationOperation) 30 | return E_POINTER; 31 | 32 | *_ppActivationOperation = nullptr; 33 | return E_NOTIMPL; 34 | } 35 | #endif 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/api-ms-win-power-base.UnitTest.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Thunks/api-ms-win-power-base.hpp" 3 | 4 | namespace api_ms_win_power_base 5 | { 6 | TEST_CLASS(PowerRegisterSuspendResumeNotification) 7 | { 8 | AwaysNullGuard Guard; 9 | 10 | public: 11 | PowerRegisterSuspendResumeNotification() 12 | { 13 | Guard |= YY::Thunks::aways_null_try_get_PowerRegisterSuspendResumeNotification; 14 | Guard |= YY::Thunks::aways_null_try_get_PowerUnregisterSuspendResumeNotification; 15 | } 16 | 17 | TEST_METHOD(创建然后关闭) 18 | { 19 | DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS Parameters = {}; 20 | Parameters.Callback = [](_In_opt_ PVOID Context, 21 | _In_ ULONG Type, 22 | _In_ PVOID Setting) -> ULONG 23 | { 24 | return ERROR_SUCCESS; 25 | }; 26 | 27 | HPOWERNOTIFY RegistrationHandle = nullptr; 28 | 29 | auto _lStatus = ::PowerRegisterSuspendResumeNotification(DEVICE_NOTIFY_CALLBACK, &Parameters, &RegistrationHandle); 30 | Assert::AreEqual(_lStatus, (DWORD)ERROR_SUCCESS); 31 | Assert::IsNotNull(RegistrationHandle); 32 | 33 | Sleep(500); 34 | 35 | _lStatus = ::PowerUnregisterSuspendResumeNotification(RegistrationHandle); 36 | Assert::AreEqual(_lStatus, (DWORD)ERROR_SUCCESS); 37 | } 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /src/Thunks/api-ms-win-core-processtopology.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6_1) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #if (YY_Thunks_Target < __WindowsNT6_1) 8 | 9 | //Minimum supported client Windows 7 [desktop apps only] 10 | //Minimum supported server Windows Server 2008 R2 [desktop apps only] 11 | __DEFINE_THUNK( 12 | kernel32, 13 | 12, 14 | BOOL, 15 | WINAPI, 16 | GetProcessGroupAffinity, 17 | _In_ HANDLE _hProcess, 18 | _Inout_ PUSHORT _pGroupCount, 19 | _Out_writes_(*_pGroupCount) PUSHORT _pGroupArray 20 | ) 21 | { 22 | if (const auto _pfnGetProcessGroupAffinity = try_get_GetProcessGroupAffinity()) 23 | { 24 | return _pfnGetProcessGroupAffinity(_hProcess, _pGroupCount, _pGroupArray); 25 | } 26 | 27 | // 更低版本系统不支持 CPU组,所以我们可以视为系统只有一组处理器。 28 | if (_pGroupCount == nullptr || _pGroupArray == nullptr) 29 | { 30 | SetLastError(ERROR_NOACCESS); 31 | return FALSE; 32 | } 33 | 34 | if (*_pGroupCount < 1) 35 | { 36 | SetLastError(ERROR_INSUFFICIENT_BUFFER); 37 | return FALSE; 38 | } 39 | *_pGroupCount = 1; 40 | _pGroupArray[0] = 0; 41 | return TRUE; 42 | } 43 | #endif 44 | } // namespace YY::Thunks 45 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | native,Version=v0.0 24 | 25 | win;win-x86;win-x64;win-arm;win-arm64 26 | 27 | 28 | 29 | 30 | $([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../')) 31 | 32 | 33 | -------------------------------------------------------------------------------- /NuGet/YY-Thunks.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | YY-Thunks 5 | $version$ 6 | YY-Thunks 7 | YY 8 | 初雨团队 9 | false 10 | MIT 11 | https://licenses.nuget.org/MIT 12 | https://github.com/Chuyu-Team/YY-Thunks/ 13 | 功能 —— 让兼容Windows更轻松 14 | - 简洁优雅,一个obj解决找不到指定入口点问题。 15 | 优雅的解决Windows XP RTM无法定位程序输入点 DecodePointer、EncodePointer、RegDeleteKeyEx等,让你兼容Windows更轻松。 16 | $releaseNotes$ 17 | Copyright 2021 18 | Chuyu YY-Thunks native nativepackage 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Thunks/api-ms-win-core-windowserrorreporting.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6_1) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #if (YY_Thunks_Target < __WindowsNT6_1) 8 | 9 | // 最低受支持的客户端 Windows 7 [仅限桌面应用] 10 | // 最低受支持的服务器 Windows Server 2008 R2[仅限桌面应用] 11 | __DEFINE_THUNK( 12 | kernel32, 13 | 8, 14 | HRESULT, 15 | WINAPI, 16 | WerRegisterRuntimeExceptionModule, 17 | _In_ PCWSTR _szOutOfProcessCallbackDll, 18 | _In_ PVOID _pContext 19 | ) 20 | { 21 | if (const auto _pfnWerRegisterRuntimeExceptionModule = try_get_WerRegisterRuntimeExceptionModule()) 22 | { 23 | return _pfnWerRegisterRuntimeExceptionModule(_szOutOfProcessCallbackDll, _pContext); 24 | } 25 | 26 | return S_OK; 27 | } 28 | #endif 29 | 30 | 31 | #if (YY_Thunks_Target < __WindowsNT6_1) 32 | 33 | // 最低受支持的客户端 Windows 7 [仅限桌面应用] 34 | // 最低受支持的服务器 Windows Server 2008 R2[仅限桌面应用] 35 | __DEFINE_THUNK( 36 | kernel32, 37 | 8, 38 | HRESULT, 39 | WINAPI, 40 | WerUnregisterRuntimeExceptionModule, 41 | _In_ PCWSTR _szOutOfProcessCallbackDll, 42 | _In_ PVOID _pContext 43 | ) 44 | { 45 | if (const auto _pfnWerUnregisterRuntimeExceptionModule = try_get_WerUnregisterRuntimeExceptionModule()) 46 | { 47 | return _pfnWerUnregisterRuntimeExceptionModule(_szOutOfProcessCallbackDll, _pContext); 48 | } 49 | 50 | return S_OK; 51 | } 52 | #endif 53 | } 54 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_Request_zh-cn.yml: -------------------------------------------------------------------------------- 1 | name: "新功能建议模板 - 简体中文" 2 | description: "需要新的API支持或者功能请选择此模板" 3 | title: "简要标题,如:执行XXX程序时报告YYY等相关API缺失" 4 | labels: ["进度:等待审核"] 5 | type: Feature 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: "* 温馨提示:提出问题后我们不保证跟进,与其提出问题我们更欣赏提交PR。 10 | * 请简洁明了地描述此建议。如:执行XXX程序时报告YYY等相关API缺失;希望支持某个VS新提供的功能。" 11 | 12 | - type: textarea 13 | id: background_cn 14 | attributes: 15 | label: "背景信息" 16 | description: "请提供以下相关信息(可逐条填写)。" 17 | placeholder: | 18 | - 我们为什么使用这个功能/API?遇到了实际什么需求? 19 | - 如果仅仅是“觉得有用”或者“觉得不错”等个人喜好我们不予考虑。 20 | - 该接口/功能在其他类似项目中是如何实现的?(如果有的话) 21 | - 需要支持的程度(比如:至少需要在 Windows 7 上可以跑起来) 22 | - 如果缺API,请详细提供 YY.Depends.Analyzer 的扫描结果(因为一个API缺失可能伴随着其他多个API缺失) 23 | - 具体请参考 Fea 138 中的 YY.Depends.Analyzer 使用方法:https://github.com/Chuyu-Team/YY-Thunks/issues/138 24 | validations: 25 | required: true 26 | 27 | - type: textarea 28 | id: details_cn 29 | attributes: 30 | label: "详细说明" 31 | description: "补充任何有助于理解需求的细节:场景、限制、兼容性期望、风险、替代方案等。" 32 | placeholder: | 33 | - 具体使用场景: 34 | - 与现有接口的关系: 35 | - 兼容性期望(最低系统版本、架构等): 36 | - 潜在风险或影响: 37 | - 可替代方案及其不足: 38 | validations: 39 | required: false 40 | 41 | - type: checkboxes 42 | id: confirmations_cn 43 | attributes: 44 | label: "提交前确认" 45 | options: 46 | - label: "我已搜索现有 Issue,未发现重复建议" 47 | - label: "我已提供背景信息与期望支持范围" 48 | - label: "如涉及缺API,我已附上 YY.Depends.Analyzer 扫描结果或链接" 49 | -------------------------------------------------------------------------------- /src/Thunks/netapi32.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT10_10240) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #if (YY_Thunks_Target < __WindowsNT10_10240) 8 | 9 | // 最低受支持的客户端 Windows 10 [仅限桌面应用] 10 | // 最低受支持的服务器 Windows Server 2016[仅限桌面应用] 11 | __DEFINE_THUNK( 12 | netapi32, 13 | 8, 14 | HRESULT, 15 | NET_API_FUNCTION, 16 | NetGetAadJoinInformation, 17 | _In_opt_ LPCWSTR _szTenantId, 18 | _Outptr_result_maybenull_ PDSREG_JOIN_INFO* _ppJoinInfo 19 | ) 20 | { 21 | if (const auto _pfnNetGetAadJoinInformation = try_get_NetGetAadJoinInformation()) 22 | { 23 | return _pfnNetGetAadJoinInformation(_szTenantId, _ppJoinInfo); 24 | } 25 | if (!_ppJoinInfo) 26 | return E_INVALIDARG; 27 | 28 | // 总是认为自己没有加入 Azure AD 帐户。 29 | *_ppJoinInfo = nullptr; 30 | return S_OK; 31 | } 32 | #endif 33 | 34 | 35 | #if (YY_Thunks_Target < __WindowsNT10_10240) 36 | 37 | // 最低受支持的客户端 Windows 10 [仅限桌面应用] 38 | // 最低受支持的服务器 Windows Server 2016[仅限桌面应用] 39 | __DEFINE_THUNK( 40 | netapi32, 41 | 4, 42 | VOID, 43 | NET_API_FUNCTION, 44 | NetFreeAadJoinInformation, 45 | _In_opt_ PDSREG_JOIN_INFO _pJoinInfo 46 | ) 47 | { 48 | if (const auto _pfnNetFreeAadJoinInformation = try_get_NetFreeAadJoinInformation()) 49 | { 50 | return _pfnNetFreeAadJoinInformation(_pJoinInfo); 51 | } 52 | 53 | // 什么也不做,老版本系统不可能会拿到这个信息。 54 | UNREFERENCED_PARAMETER(_pJoinInfo); 55 | } 56 | #endif 57 | } // namespace YY::Thunks 58 | -------------------------------------------------------------------------------- /src/Thunks/dxva2.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6) 2 | #include 3 | #include 4 | #endif 5 | 6 | namespace YY::Thunks 7 | { 8 | #if (YY_Thunks_Target < __WindowsNT6) 9 | 10 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 11 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 12 | __DEFINE_THUNK( 13 | dxva2, 14 | 8, 15 | HRESULT, 16 | WINAPI, 17 | DXVA2CreateDirect3DDeviceManager9, 18 | _Out_ UINT* pResetToken, 19 | _Outptr_ IDirect3DDeviceManager9** ppDeviceManager 20 | ) 21 | { 22 | if (const auto _pfnDXVA2CreateDirect3DDeviceManager9 = try_get_DXVA2CreateDirect3DDeviceManager9()) 23 | { 24 | return _pfnDXVA2CreateDirect3DDeviceManager9(pResetToken, ppDeviceManager); 25 | } 26 | 27 | if (ppDeviceManager) 28 | *ppDeviceManager = nullptr; 29 | return E_NOINTERFACE; 30 | } 31 | #endif 32 | 33 | 34 | #if (YY_Thunks_Target < __WindowsNT6) 35 | 36 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 37 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 38 | __DEFINE_THUNK( 39 | dxva2, 40 | 12, 41 | HRESULT, 42 | WINAPI, 43 | DXVA2CreateVideoService, 44 | _In_ IDirect3DDevice9* pDD, 45 | _In_ REFIID riid, 46 | _Outptr_ void** ppService 47 | ) 48 | { 49 | if (const auto _pfnDXVA2CreateVideoService = try_get_DXVA2CreateVideoService()) 50 | { 51 | return _pfnDXVA2CreateVideoService(pDD, riid, ppService); 52 | } 53 | 54 | if (ppService) 55 | *ppService = nullptr; 56 | return E_NOINTERFACE; 57 | } 58 | #endif 59 | } 60 | -------------------------------------------------------------------------------- /src/Thunks/ext-ms-win-ntuser-gui.hpp: -------------------------------------------------------------------------------- 1 | namespace YY::Thunks 2 | { 3 | #if (YY_Thunks_Target < __WindowsNT6_1) 4 | 5 | // 最低受支持的客户端 Windows 7 [仅限桌面应用] 6 | // 最低受支持的服务器 Windows Server 2008 R2[仅限桌面应用] 7 | __DEFINE_THUNK( 8 | user32, 9 | 16, 10 | BOOL, 11 | WINAPI, 12 | ChangeWindowMessageFilterEx, 13 | _In_ HWND _hWnd, 14 | _In_ UINT _uMessage, 15 | _In_ DWORD _uAction, 16 | _Inout_opt_ PCHANGEFILTERSTRUCT _pChangeFilterStruct 17 | ) 18 | { 19 | if (const auto _pfnChangeWindowMessageFilterEx = try_get_ChangeWindowMessageFilterEx()) 20 | { 21 | return _pfnChangeWindowMessageFilterEx(_hWnd, _uMessage, _uAction, _pChangeFilterStruct); 22 | } 23 | 24 | if (_hWnd == NULL || (_pChangeFilterStruct && _pChangeFilterStruct->cbSize != sizeof(CHANGEFILTERSTRUCT))) 25 | { 26 | SetLastError(ERROR_INVALID_PARAMETER); 27 | return FALSE; 28 | } 29 | 30 | DWORD _fFlag; 31 | if (_uAction == MSGFLT_ALLOW || _uAction == MSGFLT_DISALLOW) 32 | { 33 | _fFlag = _uAction; 34 | } 35 | else if (_uAction == MSGFLT_RESET) 36 | { 37 | // 默认情况下大于WM_USER的全部阻止,这是系统规则。 38 | _fFlag = _uMessage >= WM_USER ? MSGFLT_REMOVE : MSGFLT_ADD; 39 | } 40 | else 41 | { 42 | SetLastError(ERROR_INVALID_PARAMETER); 43 | return FALSE; 44 | } 45 | 46 | auto _bRet = ChangeWindowMessageFilter(_uMessage, _fFlag); 47 | if (_bRet && _pChangeFilterStruct) 48 | { 49 | _pChangeFilterStruct->ExtStatus = MSGFLTINFO_NONE; 50 | } 51 | 52 | return _bRet; 53 | } 54 | #endif 55 | } 56 | -------------------------------------------------------------------------------- /NuGet/build/native/YY-Thunks_ui_D5D733D3-8829-4509-9C74-021E5685ED18.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 24 | 27 | 28 | 31 | 32 | 35 | 36 | 39 | 40 | 43 | 44 | 47 | 48 | 51 | 52 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/Thunks/Pdh.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6) 2 | #include 3 | #endif 4 | 5 | #if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_pdh) 6 | #define __Comment_Lib_pdh 7 | #pragma comment(lib, "Pdh.lib") 8 | #endif 9 | 10 | namespace YY::Thunks 11 | { 12 | #if (YY_Thunks_Target < __WindowsNT6) 13 | 14 | // Windows Vista [desktop apps only] 15 | // Windows Server 2008 [desktop apps only] 16 | __DEFINE_THUNK( 17 | pdh, 18 | 16, 19 | PDH_STATUS, 20 | WINAPI, 21 | PdhAddEnglishCounterW, 22 | _In_ PDH_HQUERY hQuery, 23 | _In_ LPCWSTR szFullCounterPath, 24 | _In_ DWORD_PTR dwUserData, 25 | _Out_ PDH_HCOUNTER * phCounter 26 | ) 27 | { 28 | if (const auto pPdhAddEnglishCounterW = try_get_PdhAddEnglishCounterW()) 29 | { 30 | return pPdhAddEnglishCounterW(hQuery, szFullCounterPath, dwUserData, phCounter); 31 | } 32 | 33 | return PdhAddCounterW(hQuery, szFullCounterPath, dwUserData, phCounter); 34 | } 35 | #endif 36 | 37 | 38 | #if (YY_Thunks_Target < __WindowsNT6) 39 | 40 | // Windows Vista [desktop apps only] 41 | // Windows Server 2008 [desktop apps only] 42 | __DEFINE_THUNK( 43 | pdh, 44 | 16, 45 | PDH_STATUS, 46 | WINAPI, 47 | PdhAddEnglishCounterA, 48 | _In_ PDH_HQUERY hQuery, 49 | _In_ LPCSTR szFullCounterPath, 50 | _In_ DWORD_PTR dwUserData, 51 | _Out_ PDH_HCOUNTER * phCounter 52 | ) 53 | { 54 | if (const auto pPdhAddEnglishCounterA = try_get_PdhAddEnglishCounterA()) 55 | { 56 | return pPdhAddEnglishCounterA(hQuery, szFullCounterPath, dwUserData, phCounter); 57 | } 58 | 59 | return PdhAddCounterA(hQuery, szFullCounterPath, dwUserData, phCounter); 60 | } 61 | 62 | #endif 63 | } 64 | -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/PropSys.UnitTest.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Thunks/PropSys.hpp" 3 | 4 | namespace PropSys 5 | { 6 | TEST_CLASS(VariantCompare) 7 | { 8 | AwaysNullGuard Guard; 9 | 10 | public: 11 | VariantCompare() 12 | { 13 | Guard |= YY::Thunks::aways_null_try_get_VariantCompare; 14 | } 15 | 16 | TEST_METHOD(一般) 17 | { 18 | { 19 | VARIANT _Left = {}; 20 | VARIANT _Rigth = {}; 21 | 22 | _Left.vt = VT_I1; 23 | _Left.bVal = 8; 24 | 25 | _Rigth.vt = VT_I1; 26 | _Rigth.bVal = 9; 27 | 28 | Assert::IsTrue(::VariantCompare(_Left, _Rigth) < 0); 29 | } 30 | 31 | { 32 | VARIANT _Left = {}; 33 | VARIANT _Rigth = {}; 34 | 35 | _Left.vt = VT_R4; 36 | _Left.fltVal = 8; 37 | 38 | _Rigth.vt = VT_R4; 39 | _Rigth.fltVal = 8; 40 | 41 | Assert::IsTrue(::VariantCompare(_Left, _Rigth) == 0); 42 | } 43 | 44 | { 45 | VARIANT _Left = {}; 46 | VARIANT _Rigth = {}; 47 | 48 | _Left.vt = VT_R4; 49 | _Left.fltVal = 9; 50 | 51 | _Rigth.vt = VT_R4; 52 | _Rigth.fltVal = 8; 53 | 54 | Assert::IsTrue(::VariantCompare(_Left, _Rigth) > 0); 55 | } 56 | 57 | { 58 | VARIANT _Left = {}; 59 | VARIANT _Rigth = {}; 60 | 61 | _Left.vt = VT_R4; 62 | _Left.fltVal = 8.1f; 63 | 64 | _Rigth.vt = VT_R4; 65 | _Rigth.fltVal = 8; 66 | 67 | Assert::IsTrue(::VariantCompare(_Left, _Rigth) > 0); 68 | } 69 | } 70 | }; 71 | } 72 | -------------------------------------------------------------------------------- /src/Thunks/mf.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6_1) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #if (YY_Thunks_Target < __WindowsNT6_1) 8 | 9 | // Minimum supported client Windows 7 [desktop apps only] 10 | // Minimum supported server Windows Server 2008 R2[desktop apps only] 11 | __DEFINE_THUNK( 12 | mf, 13 | 8, 14 | HRESULT, 15 | STDAPICALLTYPE, 16 | MFCreateDeviceSource, 17 | _In_ IMFAttributes* pAttributes, 18 | _Outptr_ IMFMediaSource** ppSource 19 | ) 20 | { 21 | if (const auto _pfnMFCreateDeviceSource = try_get_MFCreateDeviceSource()) 22 | { 23 | return _pfnMFCreateDeviceSource(pAttributes, ppSource); 24 | } 25 | 26 | if (!ppSource) 27 | return E_POINTER; 28 | 29 | *ppSource = nullptr; 30 | return E_NOTIMPL; 31 | } 32 | #endif 33 | 34 | 35 | #if (YY_Thunks_Target < __WindowsNT6_1) 36 | 37 | // Minimum supported client Windows 7 [desktop apps only] 38 | // Minimum supported server Windows Server 2008 R2[desktop apps only] 39 | __DEFINE_THUNK( 40 | mf, 41 | 12, 42 | HRESULT, 43 | STDAPICALLTYPE, 44 | MFEnumDeviceSources, 45 | _In_ IMFAttributes* pAttributes, 46 | _Outptr_result_buffer_(*pcSourceActivate) IMFActivate*** pppSourceActivate, 47 | _Out_ UINT32* pcSourceActivate 48 | ) 49 | { 50 | if (const auto _pfnMFEnumDeviceSources = try_get_MFEnumDeviceSources()) 51 | { 52 | return _pfnMFEnumDeviceSources(pAttributes, pppSourceActivate, pcSourceActivate); 53 | } 54 | 55 | if (!pcSourceActivate) 56 | return E_POINTER; 57 | *pcSourceActivate = 0; 58 | 59 | if (!pppSourceActivate) 60 | return E_POINTER; 61 | *pppSourceActivate = nullptr; 62 | return E_NOTIMPL; 63 | } 64 | #endif 65 | } 66 | -------------------------------------------------------------------------------- /src/Shared/List.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace YY::Thunks 4 | { 5 | namespace 6 | { 7 | template 8 | struct ListEntryImpl 9 | { 10 | ListEntry* pPrior = nullptr; 11 | ListEntry* pNext = nullptr; 12 | }; 13 | 14 | template 15 | class ListImpl 16 | { 17 | public: 18 | ListEntry* pFirst = nullptr; 19 | ListEntry* pLast = nullptr; 20 | 21 | void __fastcall PushBack(ListEntry* _pItem) noexcept 22 | { 23 | if (!_pItem) 24 | return; 25 | 26 | _pItem->pNext = nullptr; 27 | _pItem->pPrior = pLast; 28 | if (pLast) 29 | { 30 | pLast->pNext = _pItem; 31 | } 32 | pLast = _pItem; 33 | 34 | if (!pFirst) 35 | pFirst = _pItem; 36 | } 37 | 38 | bool __fastcall Remove(ListEntry* _pItem) noexcept 39 | { 40 | if (!_pItem) 41 | return false; 42 | 43 | if (!pFirst) 44 | return false; 45 | 46 | auto _pPrior = _pItem->pPrior; 47 | auto _pNext = _pItem->pNext; 48 | if (_pPrior) 49 | { 50 | _pPrior->pNext = _pNext; 51 | } 52 | 53 | if (_pNext) 54 | { 55 | _pNext->pPrior = _pPrior; 56 | } 57 | 58 | if (pFirst == _pItem) 59 | { 60 | pFirst = _pNext; 61 | } 62 | 63 | if (pLast == _pItem) 64 | { 65 | pLast = _pPrior; 66 | } 67 | 68 | return true; 69 | } 70 | }; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Shared/HStringPrivate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PROJECT: YY-Thunks 3 | * FILE: hstring_private.h 4 | * PURPOSE: Extra definitions for the Windows Runtime String (HSTRING) 5 | * 6 | * LICENSE: The MIT License 7 | * 8 | * MAINTAINER: MouriNaruto (Kenji.Mouri@outlook.com) 9 | */ 10 | #pragma once 11 | #include 12 | 13 | #include "SharedDefs.h" 14 | 15 | /* 16 | * @remark The following definitions are dumped from the debug symbol from the 17 | * Windows 10 Build 14347's combase.dll. 18 | */ 19 | namespace YY::Thunks::internal 20 | { 21 | namespace 22 | { 23 | /* 24 | * @brief The flags of the Windows Runtime String. 25 | * @remark Originally it's a C/C++ enum in the debug symbols. 26 | */ 27 | enum class RuntimeStringFlags : UINT32 28 | { 29 | WRHF_NONE = 0x00000000, 30 | WRHF_STRING_REFERENCE = 0x00000001, 31 | WRHF_VALID_UNICODE_FORMAT_INFO = 0x00000002, 32 | WRHF_WELL_FORMED_UNICODE = 0x00000004, 33 | WRHF_HAS_EMBEDDED_NULLS = 0x00000008, 34 | WRHF_EMBEDDED_NULLS_COMPUTED = 0x00000010, 35 | WRHF_RESERVED_FOR_PREALLOCATED_STRING_BUFFER = 0x80000000, 36 | }; 37 | YY_APPLY_ENUM_CALSS_BIT_OPERATOR(RuntimeStringFlags) 38 | 39 | /* 40 | * @brief The internal structure of Windows Runtime String header. 41 | */ 42 | typedef struct _HSTRING_HEADER_INTERNAL 43 | { 44 | RuntimeStringFlags Flags; 45 | UINT32 Length; 46 | UINT32 Padding1; 47 | UINT32 Padding2; 48 | PCWSTR StringRef; 49 | } HSTRING_HEADER_INTERNAL, * PHSTRING_HEADER_INTERNAL; 50 | static_assert(sizeof(HSTRING_HEADER) == sizeof(HSTRING_HEADER_INTERNAL)); 51 | 52 | /* 53 | * @brief The internal structure of heap allocated Windows Runtime String. 54 | */ 55 | typedef struct _STRING_OPAQUE 56 | { 57 | HSTRING_HEADER_INTERNAL Header; 58 | volatile LONG RefCount; 59 | WCHAR String[ANYSIZE_ARRAY]; 60 | } STRING_OPAQUE, * PSTRING_OPAQUE; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Thunks/api-ms-win-core-datetime.hpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | namespace YY::Thunks 5 | { 6 | #if (YY_Thunks_Target < __WindowsNT6) 7 | 8 | //Windows Vista, Windows Server 2008 9 | __DEFINE_THUNK( 10 | kernel32, 11 | 28, 12 | int, 13 | WINAPI, 14 | GetDateFormatEx, 15 | _In_opt_ LPCWSTR lpLocaleName, 16 | _In_ DWORD dwFlags, 17 | _In_opt_ CONST SYSTEMTIME* lpDate, 18 | _In_opt_ LPCWSTR lpFormat, 19 | _Out_writes_opt_(cchDate) LPWSTR lpDateStr, 20 | _In_ int cchDate, 21 | _In_opt_ LPCWSTR lpCalendar 22 | ) 23 | { 24 | if (auto pGetDateFormatEx = try_get_GetDateFormatEx()) 25 | { 26 | return pGetDateFormatEx(lpLocaleName, dwFlags, lpDate, lpFormat, lpDateStr, cchDate, lpCalendar); 27 | } 28 | 29 | auto Locale = LocaleNameToLCID(lpLocaleName, 0); 30 | 31 | if (Locale == 0) 32 | { 33 | SetLastError(ERROR_INVALID_PARAMETER); 34 | return 0; 35 | } 36 | 37 | return GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, lpDateStr, cchDate); 38 | } 39 | #endif 40 | 41 | 42 | #if (YY_Thunks_Target < __WindowsNT6) 43 | 44 | //Windows Vista, Windows Server 2008 45 | __DEFINE_THUNK( 46 | kernel32, 47 | 24, 48 | int, 49 | WINAPI, 50 | GetTimeFormatEx, 51 | _In_opt_ LPCWSTR lpLocaleName, 52 | _In_ DWORD dwFlags, 53 | _In_opt_ CONST SYSTEMTIME* lpTime, 54 | _In_opt_ LPCWSTR lpFormat, 55 | _Out_writes_opt_(cchTime) LPWSTR lpTimeStr, 56 | _In_ int cchTime 57 | ) 58 | { 59 | if (auto pGetTimeFormatEx = try_get_GetTimeFormatEx()) 60 | { 61 | return pGetTimeFormatEx(lpLocaleName, dwFlags, lpTime, lpFormat, lpTimeStr, cchTime); 62 | } 63 | 64 | auto Locale = LocaleNameToLCID(lpLocaleName, 0); 65 | 66 | if (Locale == 0) 67 | { 68 | SetLastError(ERROR_INVALID_PARAMETER); 69 | return 0; 70 | } 71 | 72 | return GetTimeFormatW(Locale, dwFlags, lpTime, lpFormat, lpTimeStr, cchTime); 73 | } 74 | #endif 75 | } //namespace YY::Thunks 76 | -------------------------------------------------------------------------------- /src/Thunks/ndfapi.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #if (YY_Thunks_Target < __WindowsNT6) 8 | 9 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 10 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 11 | __DEFINE_THUNK( 12 | ndfapi, 13 | 8, 14 | HRESULT, 15 | WINAPI, 16 | NdfCreateWebIncident, 17 | _In_ LPCWSTR _szUrl, 18 | _Outptr_ NDFHANDLE* _phHandle 19 | ) 20 | { 21 | if (const auto _pfnNdfCreateWebIncident = try_get_NdfCreateWebIncident()) 22 | { 23 | return _pfnNdfCreateWebIncident(_szUrl, _phHandle); 24 | } 25 | 26 | if (_szUrl == nullptr || _phHandle == nullptr) 27 | return NDF_E_BAD_PARAM; 28 | 29 | *_phHandle = INVALID_HANDLE_VALUE; 30 | return S_OK; 31 | } 32 | #endif 33 | 34 | 35 | #if (YY_Thunks_Target < __WindowsNT6) 36 | 37 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 38 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 39 | __DEFINE_THUNK( 40 | ndfapi, 41 | 4, 42 | HRESULT, 43 | WINAPI, 44 | NdfCloseIncident, 45 | NDFHANDLE _hHandle 46 | ) 47 | { 48 | if (const auto _pfnNdfCloseIncident = try_get_NdfCloseIncident()) 49 | { 50 | return _pfnNdfCloseIncident(_hHandle); 51 | } 52 | 53 | if (_hHandle != INVALID_HANDLE_VALUE) 54 | return E_HANDLE; 55 | 56 | return S_OK; 57 | } 58 | #endif 59 | 60 | 61 | #if (YY_Thunks_Target < __WindowsNT6) 62 | 63 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 64 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 65 | __DEFINE_THUNK( 66 | ndfapi, 67 | 8, 68 | HRESULT, 69 | WINAPI, 70 | NdfExecuteDiagnosis, 71 | _In_ NDFHANDLE _hHandle, 72 | _In_opt_ HWND _hWnd 73 | ) 74 | { 75 | if (const auto _pfnNdfExecuteDiagnosis = try_get_NdfExecuteDiagnosis()) 76 | { 77 | return _pfnNdfExecuteDiagnosis(_hHandle, _hWnd); 78 | } 79 | 80 | if (_hHandle != INVALID_HANDLE_VALUE) 81 | { 82 | return E_HANDLE; 83 | } 84 | 85 | return S_OK; 86 | } 87 | #endif 88 | } 89 | -------------------------------------------------------------------------------- /src/Thunks/d3d11.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6_1) 2 | #include 3 | #endif 4 | 5 | #if (YY_Thunks_Target < __WindowsNT10_10240) 6 | #include 7 | #endif 8 | 9 | namespace YY::Thunks 10 | { 11 | #if (YY_Thunks_Target < __WindowsNT6_1) 12 | 13 | // Windows 7自带,Vista需要安装KB971644 14 | __DEFINE_THUNK( 15 | d3d11, 16 | 40, 17 | HRESULT, 18 | WINAPI, 19 | D3D11CreateDevice, 20 | _In_opt_ IDXGIAdapter* pAdapter, 21 | D3D_DRIVER_TYPE DriverType, 22 | HMODULE Software, 23 | UINT Flags, 24 | _In_reads_opt_( FeatureLevels ) CONST D3D_FEATURE_LEVEL* pFeatureLevels, 25 | UINT FeatureLevels, 26 | UINT SDKVersion, 27 | _COM_Outptr_opt_ ID3D11Device** ppDevice, 28 | _Out_opt_ D3D_FEATURE_LEVEL* pFeatureLevel, 29 | _COM_Outptr_opt_ ID3D11DeviceContext** ppImmediateContext 30 | ) 31 | { 32 | if (const auto _pfnD3D11CreateDevice = try_get_D3D11CreateDevice()) 33 | { 34 | return _pfnD3D11CreateDevice(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, ppDevice, pFeatureLevel, ppImmediateContext); 35 | } 36 | 37 | if (ppDevice) 38 | *ppDevice = nullptr; 39 | 40 | if (ppImmediateContext) 41 | *ppImmediateContext = nullptr; 42 | 43 | return E_NOINTERFACE; 44 | } 45 | #endif 46 | 47 | 48 | #if (YY_Thunks_Target < __WindowsNT10_10240) 49 | 50 | // 已知 Windows 10 10240已经自带 51 | __DEFINE_THUNK( 52 | d3d11, 53 | 8, 54 | HRESULT, 55 | WINAPI, 56 | CreateDirect3D11DeviceFromDXGIDevice, 57 | _In_opt_ IDXGIDevice* _pDxgiDevice, 58 | _COM_Outptr_ IInspectable** _ppGraphicsDevice 59 | ) 60 | { 61 | if (const auto _pfnCreateDirect3D11DeviceFromDXGIDevice = try_get_CreateDirect3D11DeviceFromDXGIDevice()) 62 | { 63 | return _pfnCreateDirect3D11DeviceFromDXGIDevice(_pDxgiDevice, _ppGraphicsDevice); 64 | } 65 | 66 | if (_ppGraphicsDevice) 67 | *_ppGraphicsDevice = nullptr; 68 | 69 | return E_NOINTERFACE; 70 | } 71 | #endif 72 | } 73 | -------------------------------------------------------------------------------- /src/Thunks/dxgi.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6_3) 2 | #include 3 | #endif 4 | 5 | #if (YY_Thunks_Target < __WindowsNT6_3) && !defined(__Comment_Lib_dxgi) 6 | #define __Comment_Lib_dxgi 7 | #pragma comment(lib, "DXGI.lib") 8 | #endif 9 | 10 | namespace YY::Thunks 11 | { 12 | #if (YY_Thunks_Target < __WindowsNT6) 13 | 14 | // Minimum supported client Windows Vista 15 | // Minimum supported server Windows Server 2008 16 | __DEFINE_THUNK( 17 | dxgi, 18 | 8, 19 | HRESULT, 20 | STDAPICALLTYPE, 21 | CreateDXGIFactory, 22 | REFIID _IID, 23 | _COM_Outptr_ void** _ppFactory 24 | ) 25 | { 26 | if (auto const _pfnCreateDXGIFactory = try_get_CreateDXGIFactory()) 27 | { 28 | return _pfnCreateDXGIFactory(_IID, _ppFactory); 29 | } 30 | 31 | if (_ppFactory) 32 | *_ppFactory = nullptr; 33 | return DXGI_ERROR_UNSUPPORTED; 34 | } 35 | #endif 36 | 37 | 38 | #if (YY_Thunks_Target < __WindowsNT6_SP2) 39 | 40 | // 最低受支持的客户端 Windows 7 [桌面应用 |UWP 应用] 41 | // 最低受支持的服务器 Windows Server 2008 R2[桌面应用 | UWP 应用] 42 | __DEFINE_THUNK( 43 | dxgi, 44 | 8, 45 | HRESULT, 46 | WINAPI, 47 | CreateDXGIFactory1, 48 | REFIID _IID, 49 | _COM_Outptr_ void ** _ppFactory 50 | ) 51 | { 52 | if (const auto _pfnCreateDXGIFactory1 = try_get_CreateDXGIFactory1()) 53 | { 54 | return _pfnCreateDXGIFactory1(_IID, _ppFactory); 55 | } 56 | 57 | return CreateDXGIFactory(_IID, _ppFactory); 58 | } 59 | #endif 60 | 61 | 62 | #if (YY_Thunks_Target < __WindowsNT6_3) 63 | 64 | // Minimum supported client Windows 8.1 65 | // Minimum supported server Windows Server 2012 R2 66 | __DEFINE_THUNK( 67 | dxgi, 68 | 12, 69 | HRESULT, 70 | STDAPICALLTYPE, 71 | CreateDXGIFactory2, 72 | UINT _fFlags, 73 | REFIID _IID, 74 | _COM_Outptr_ void** _ppFactory 75 | ) 76 | { 77 | if (auto const _pfnCreateDXGIFactory2 = try_get_CreateDXGIFactory2()) 78 | { 79 | return _pfnCreateDXGIFactory2(_fFlags, _IID, _ppFactory); 80 | } 81 | 82 | return CreateDXGIFactory1(_IID, _ppFactory); 83 | } 84 | #endif 85 | } 86 | -------------------------------------------------------------------------------- /src/Thunks/d3d12.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT10_10240) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #if (YY_Thunks_Target < __WindowsNT10_10240) 8 | 9 | // Windows 10 10 | __DEFINE_THUNK( 11 | d3d12, 12 | 16, 13 | HRESULT, 14 | WINAPI, 15 | D3D12CreateDevice, 16 | _In_opt_ IUnknown* pAdapter, 17 | D3D_FEATURE_LEVEL MinimumFeatureLevel, 18 | _In_ REFIID riid, // Expected: ID3D12Device 19 | _COM_Outptr_opt_ void** ppDevice) 20 | { 21 | if (const auto _pfnD3D12CreateDevice = try_get_D3D12CreateDevice()) 22 | { 23 | return _pfnD3D12CreateDevice(pAdapter, MinimumFeatureLevel, riid, ppDevice); 24 | } 25 | 26 | if (ppDevice) 27 | *ppDevice = nullptr; 28 | return E_NOINTERFACE; 29 | } 30 | #endif 31 | 32 | 33 | #if (YY_Thunks_Target < __WindowsNT10_10240) 34 | 35 | // Windows 10 36 | __DEFINE_THUNK( 37 | d3d12, 38 | 8, 39 | HRESULT, 40 | WINAPI, 41 | D3D12GetDebugInterface, 42 | _In_ REFIID _oId, 43 | _COM_Outptr_opt_ void** _ppvDebug) 44 | { 45 | if (const auto _pfnD3D12GetDebugInterface = try_get_D3D12GetDebugInterface()) 46 | { 47 | return _pfnD3D12GetDebugInterface(_oId, _ppvDebug); 48 | } 49 | 50 | if (_ppvDebug) 51 | *_ppvDebug = nullptr; 52 | 53 | return E_NOINTERFACE; 54 | } 55 | #endif 56 | 57 | 58 | #if (YY_Thunks_Target < __WindowsNT10_10240) 59 | 60 | // Windows 10 61 | __DEFINE_THUNK( 62 | d3d12, 63 | 12, 64 | HRESULT, 65 | WINAPI, 66 | D3D12SerializeVersionedRootSignature , 67 | _In_ const D3D12_VERSIONED_ROOT_SIGNATURE_DESC* _pRootSignature, 68 | _Out_ ID3DBlob** _ppBlob, 69 | _Always_(_Outptr_opt_result_maybenull_) ID3DBlob** _ppErrorBlob) 70 | { 71 | if (const auto _pfnD3D12SerializeVersionedRootSignature = try_get_D3D12SerializeVersionedRootSignature()) 72 | { 73 | return _pfnD3D12SerializeVersionedRootSignature(_pRootSignature, _ppBlob, _ppErrorBlob); 74 | } 75 | 76 | if (_ppBlob) 77 | *_ppBlob = nullptr; 78 | 79 | if (_ppErrorBlob) 80 | *_ppErrorBlob = nullptr; 81 | 82 | return E_NOINTERFACE; 83 | } 84 | #endif 85 | } 86 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_Report_zh-cn.yml: -------------------------------------------------------------------------------- 1 | name: "Bug反馈模板 - 简体中文" 2 | description: "使用YY-Thunks时遇到Bug请选择此模板" 3 | title: "简要标题,如:调用XXXX函数时发生崩溃/死锁" 4 | labels: ["进度:等待审核"] 5 | type: bug 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: "请简洁明了地描述此Bug的标题。示例:调用XXXX函数时发生崩溃/死锁;链接时找不到XXXX函数;调用XXXX函数时返回结果非预期。" 10 | 11 | - type: textarea 12 | id: background_cn 13 | attributes: 14 | label: "背景信息" 15 | description: "请提供以下相关信息(可逐条填写):错误截图(如有);操作系统版本;YY-Thunks版本;YY-Thunks配置;VC工具集版本;工程平台。" 16 | placeholder: | 17 | - 错误截图:<粘贴或拖拽图片> 18 | - 操作系统版本:Windows 10 16299 arm64 19 | - YY-Thunks版本:v1.1.9 20 | - YY-Thunks配置:兼容到 6.0.6000 21 | - VC工具集版本:14.14.26428 22 | - 工程平台:x64 23 | validations: 24 | required: true 25 | 26 | - type: textarea 27 | id: expected_cn 28 | attributes: 29 | label: "预期行为" 30 | description: "请描述此Bug的预期行为。示例:调用XXXX函数时应该正常返回XXX。" 31 | placeholder: "调用XXXX函数时应该正常返回XXX" 32 | validations: 33 | required: true 34 | 35 | - type: textarea 36 | id: steps_cn 37 | attributes: 38 | label: "重现步骤或最小复现代码" 39 | description: "详细描述重现此Bug的步骤或提供最小复现代码。" 40 | placeholder: | 41 | 1. 使用XXXX版本的YY-Thunks 42 | 2. 调用XXXX函数 43 | 3. 再调用YYYY函数 44 | 4. 观察到崩溃/死锁/非预期返回结果 45 | render: bash 46 | validations: 47 | required: true 48 | 49 | - type: textarea 50 | id: repro_code_cn 51 | attributes: 52 | label: "复现代码示例(C++)" 53 | description: "提供可编译运行的最小复现代码(C++14)。" 54 | placeholder: | 55 | ```cpp 56 | int main() 57 | { 58 | // 这里是最小复现代码 59 | return 0; 60 | } 61 | ``` 62 | render: cpp 63 | 64 | - type: textarea 65 | id: investigation_cn 66 | attributes: 67 | label: "你的调查结果" 68 | description: "记录你为调查此Bug所做的工作和线索。" 69 | placeholder: | 70 | - 我尝试过使用不同版本的YY-Thunks,结果是一样的。 71 | - 我发现只有XXX版本的系统能复现此问题。 72 | - 我发现只有第一次调用XXXX函数时结果才不对。 73 | 74 | - type: checkboxes 75 | id: confirmations_cn 76 | attributes: 77 | label: "提交前确认" 78 | options: 79 | - label: "我已搜索现有Issue,未发现重复问题" 80 | - label: "我已提供尽可能详细的重现步骤或最小复现代码" 81 | - label: "我已填写完整环境信息" 82 | -------------------------------------------------------------------------------- /src/Thunks/dbghelp.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6) 2 | #include 3 | #endif 4 | 5 | #if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_dbghelp) 6 | #define __Comment_Lib_dbghelp 7 | #pragma comment(lib, "Dbghelp.lib") 8 | #endif 9 | 10 | namespace YY::Thunks 11 | { 12 | #if (YY_Thunks_Target < __WindowsNT6) 13 | 14 | // XP SP3自带的没有W版 15 | __DEFINE_THUNK( 16 | dbghelp, 17 | 8, 18 | BOOL, 19 | WINAPI, 20 | SymSetSearchPathW, 21 | _In_ HANDLE hProcess, 22 | _In_opt_ PCWSTR SearchPath 23 | ) 24 | { 25 | if (const auto _pfnSymSetSearchPathW = try_get_SymSetSearchPathW()) 26 | { 27 | return _pfnSymSetSearchPathW(hProcess, SearchPath); 28 | } 29 | 30 | PCSTR _szSearchPathANSI = nullptr; 31 | 32 | internal::StringBuffer _szBuffer; 33 | if (SearchPath) 34 | { 35 | auto _lStatus = internal::Convert(SearchPath, -1, &_szBuffer); 36 | if (_lStatus) 37 | { 38 | SetLastError(_lStatus); 39 | return FALSE; 40 | } 41 | 42 | _szSearchPathANSI = _szBuffer.GetC_String(); 43 | } 44 | return ::SymSetSearchPath(hProcess, _szSearchPathANSI); 45 | } 46 | #endif 47 | 48 | 49 | #if (YY_Thunks_Target < __WindowsNT6) 50 | 51 | // XP SP3自带的没有W版 52 | __DEFINE_THUNK( 53 | dbghelp, 54 | 12, 55 | BOOL, 56 | WINAPI, 57 | SymGetSearchPathW, 58 | _In_ HANDLE hProcess, 59 | _Out_writes_(SearchPathLength) PWSTR SearchPath, 60 | _In_ DWORD SearchPathLength 61 | ) 62 | { 63 | if (const auto _pfnSymGetSearchPathW = try_get_SymGetSearchPathW()) 64 | { 65 | return _pfnSymGetSearchPathW(hProcess, SearchPath, SearchPathLength); 66 | } 67 | 68 | if (SearchPath == nullptr || SearchPathLength == 0) 69 | { 70 | SetLastError(ERROR_INVALID_PARAMETER); 71 | return FALSE; 72 | } 73 | 74 | char _szANSISearchPathBuffer[2048]; 75 | if (!SymGetSearchPath(hProcess, _szANSISearchPathBuffer, _countof(_szANSISearchPathBuffer))) 76 | { 77 | return FALSE; 78 | } 79 | 80 | if (*_szANSISearchPathBuffer == L'\0') 81 | { 82 | SearchPath[0] = L'\0'; 83 | return TRUE; 84 | } 85 | 86 | return MultiByteToWideChar(CP_ACP, 0, _szANSISearchPathBuffer, -1, SearchPath, SearchPathLength) == 0; 87 | } 88 | #endif 89 | } 90 | -------------------------------------------------------------------------------- /src/Thunks/api-ms-win-core-psapi.hpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | namespace YY::Thunks 4 | { 5 | #if (YY_Thunks_Target < __WindowsNT6) 6 | 7 | //Windows Vista [desktop apps only] 8 | //Windows Server 2008 [desktop apps only] 9 | __DEFINE_THUNK( 10 | kernel32, 11 | 16, 12 | BOOL, 13 | WINAPI, 14 | QueryFullProcessImageNameW, 15 | _In_ HANDLE hProcess, 16 | _In_ DWORD dwFlags, 17 | _Out_writes_to_(*lpdwSize, *lpdwSize) LPWSTR lpExeName, 18 | _Inout_ PDWORD lpdwSize 19 | ) 20 | { 21 | if (auto pQueryFullProcessImageNameW = try_get_QueryFullProcessImageNameW()) 22 | { 23 | return pQueryFullProcessImageNameW(hProcess, dwFlags, lpExeName, lpdwSize); 24 | } 25 | 26 | auto dwSize = *lpdwSize; 27 | 28 | if (dwFlags & PROCESS_NAME_NATIVE) 29 | { 30 | dwSize = GetProcessImageFileNameW(hProcess, lpExeName, dwSize); 31 | } 32 | else 33 | { 34 | dwSize = GetModuleFileNameExW(hProcess, nullptr, lpExeName, dwSize); 35 | } 36 | 37 | if (dwSize) 38 | { 39 | *lpdwSize = dwSize; 40 | return TRUE; 41 | } 42 | else 43 | { 44 | return FALSE; 45 | } 46 | } 47 | #endif 48 | 49 | 50 | #if (YY_Thunks_Target < __WindowsNT6) 51 | 52 | //Windows Vista [desktop apps only] 53 | //Windows Server 2008 [desktop apps only] 54 | __DEFINE_THUNK( 55 | kernel32, 56 | 16, 57 | BOOL, 58 | WINAPI, 59 | QueryFullProcessImageNameA, 60 | _In_ HANDLE hProcess, 61 | _In_ DWORD dwFlags, 62 | _Out_writes_to_(*lpdwSize, *lpdwSize) LPSTR lpExeName, 63 | _Inout_ PDWORD lpdwSize 64 | ) 65 | { 66 | if (auto pQueryFullProcessImageNameA = try_get_QueryFullProcessImageNameA()) 67 | { 68 | return pQueryFullProcessImageNameA(hProcess, dwFlags, lpExeName, lpdwSize); 69 | } 70 | 71 | auto dwSize = *lpdwSize; 72 | 73 | if (dwFlags & PROCESS_NAME_NATIVE) 74 | { 75 | dwSize = GetProcessImageFileNameA(hProcess, lpExeName, dwSize); 76 | } 77 | else 78 | { 79 | dwSize = GetModuleFileNameExA(hProcess, nullptr, lpExeName, dwSize); 80 | } 81 | 82 | if (dwSize) 83 | { 84 | *lpdwSize = dwSize; 85 | return TRUE; 86 | } 87 | else 88 | { 89 | return FALSE; 90 | } 91 | } 92 | #endif 93 | } //namespace YY::Thunks 94 | -------------------------------------------------------------------------------- /src/Thunks/ext-ms-win-ntuser-sysparams-ext.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #if (YY_Thunks_Target < __WindowsNT6) 8 | 9 | // 最低受支持的客户端 在 Windows Vista 和更高版本的 Windows 操作系统中可用。 10 | __DEFINE_THUNK( 11 | user32, 12 | 4, 13 | LONG, 14 | WINAPI, 15 | DisplayConfigGetDeviceInfo, 16 | _Inout_ DISPLAYCONFIG_DEVICE_INFO_HEADER* requestPacket 17 | ) 18 | { 19 | if (const auto _pfnDisplayConfigGetDeviceInfo = try_get_DisplayConfigGetDeviceInfo()) 20 | { 21 | return _pfnDisplayConfigGetDeviceInfo(requestPacket); 22 | } 23 | 24 | return ERROR_NOT_SUPPORTED; 25 | } 26 | #endif 27 | 28 | 29 | #if (YY_Thunks_Target < __WindowsNT6) 30 | 31 | // 最低受支持的客户端 在 Windows Vista 和更高版本的 Windows 操作系统中可用。 32 | __DEFINE_THUNK( 33 | user32, 34 | 12, 35 | LONG, 36 | WINAPI, 37 | GetDisplayConfigBufferSizes, 38 | _In_ UINT32 flags, 39 | _Out_ UINT32* numPathArrayElements, 40 | _Out_ UINT32* numModeInfoArrayElements 41 | ) 42 | { 43 | if (const auto _pfnGetDisplayConfigBufferSizes = try_get_GetDisplayConfigBufferSizes()) 44 | { 45 | return _pfnGetDisplayConfigBufferSizes(flags, numPathArrayElements, numModeInfoArrayElements); 46 | } 47 | 48 | return ERROR_NOT_SUPPORTED; 49 | } 50 | #endif 51 | 52 | 53 | #if (YY_Thunks_Target < __WindowsNT6) 54 | 55 | // 最低受支持的客户端 在 Windows Vista 和更高版本的 Windows 操作系统中可用。 56 | __DEFINE_THUNK( 57 | user32, 58 | 24, 59 | LONG, 60 | WINAPI, 61 | QueryDisplayConfig, 62 | _In_ UINT32 flags, 63 | _Inout_ UINT32* numPathArrayElements, 64 | _Out_writes_to_(*numPathArrayElements, *numPathArrayElements) DISPLAYCONFIG_PATH_INFO* pathArray, 65 | _Inout_ UINT32* numModeInfoArrayElements, 66 | _Out_writes_to_(*numModeInfoArrayElements, *numModeInfoArrayElements) DISPLAYCONFIG_MODE_INFO* modeInfoArray, 67 | _When_(!(flags & QDC_DATABASE_CURRENT), _Pre_null_) 68 | _When_(flags & QDC_DATABASE_CURRENT, _Out_) 69 | DISPLAYCONFIG_TOPOLOGY_ID* currentTopologyId 70 | ) 71 | { 72 | if (const auto _pfnQueryDisplayConfig = try_get_QueryDisplayConfig()) 73 | { 74 | return _pfnQueryDisplayConfig(flags, numPathArrayElements, pathArray, numModeInfoArrayElements, modeInfoArray, currentTopologyId); 75 | } 76 | 77 | return ERROR_NOT_SUPPORTED; 78 | } 79 | #endif 80 | } 81 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_Request_en.yml: -------------------------------------------------------------------------------- 1 | name: "Feature Request Template - English" 2 | description: "Use this template to request a new feature or API support" 3 | title: "Brief title, such as: Report missing related APIs such as YYY when executing XXX" 4 | labels: ["进度:等待审核"] 5 | type: Feature 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: "* Tips: After raising an issue, we do not guarantee follow-up. We appreciate PR submissions more than issues. 10 | * Clearly and concisely describe the suggestion. Examples: Report missing related APIs such as YYY when executing XXX; Hope to support a new feature provided by VS." 11 | 12 | - type: textarea 13 | id: background_en 14 | attributes: 15 | label: "Background Information" 16 | description: "Provide the following relevant information (fill in item by item if applicable)." 17 | placeholder: | 18 | - Why do we use this feature/API? What actual needs are encountered? 19 | - If it is just \"feels useful\" or \"feels good\", personal preferences will not be considered. 20 | - How is the interface/function implemented in other similar projects? (if any) 21 | - The degree of support needed (e.g., at least needs to run on Windows 7) 22 | - If the API is missing, please provide the scan results of YY.Depends.Analyzer in detail (one API missing may be accompanied by multiple other APIs missing) 23 | - For details, refer to Fea 138: https://github.com/Chuyu-Team/YY-Thunks/issues/138 24 | validations: 25 | required: true 26 | 27 | - type: textarea 28 | id: details_en 29 | attributes: 30 | label: "Detailed Explanation" 31 | description: "Add details that help understand the need: scenarios, constraints, compatibility expectations, risks, alternatives, etc." 32 | placeholder: | 33 | - Specific usage scenario: 34 | - Relation to existing interfaces: 35 | - Compatibility expectations (minimum OS version, architecture, etc.): 36 | - Potential risks or impacts: 37 | - Alternatives and their drawbacks: 38 | validations: 39 | required: false 40 | 41 | - type: checkboxes 42 | id: confirmations_en 43 | attributes: 44 | label: "Confirm before submitting" 45 | options: 46 | - label: "I have searched existing issues for duplicates" 47 | - label: "I have provided background information and expected support scope" 48 | - label: "If APIs are missing, I have attached YY.Depends.Analyzer results or links" 49 | -------------------------------------------------------------------------------- /src/Shared/InterlockedQueue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace YY::Thunks::internal 4 | { 5 | namespace 6 | { 7 | template 8 | class InterlockedQueue 9 | { 10 | private: 11 | struct Block 12 | { 13 | size_t uLastReadIndex = 0; 14 | size_t uLastWriteIndex = 0; 15 | Block* pNextBlock = nullptr; 16 | Entry* arrLoopBuffer[kMaxBlockSize]; 17 | 18 | bool IsEmpty() 19 | { 20 | return uLastReadIndex == uLastWriteIndex; 21 | } 22 | 23 | bool IsFull() 24 | { 25 | return uLastReadIndex + kMaxBlockSize == uLastWriteIndex; 26 | } 27 | }; 28 | 29 | Block* pFirstReadBlock = nullptr; 30 | Block* pLastWriteBlock = nullptr; 31 | 32 | public: 33 | Entry* Pop() noexcept 34 | { 35 | if (!pFirstReadBlock) 36 | return nullptr; 37 | 38 | for (;;) 39 | { 40 | // 当前块任然有元素? 41 | if (!pFirstReadBlock->IsEmpty()) 42 | { 43 | auto _pTmp = pFirstReadBlock->arrLoopBuffer[pFirstReadBlock->uLastReadIndex % kMaxBlockSize]; 44 | pFirstReadBlock->uLastReadIndex += 1; 45 | return _pTmp; 46 | } 47 | 48 | // 尝试流转到下一块 49 | if (!pFirstReadBlock->pNextBlock) 50 | return nullptr; 51 | 52 | auto _pPendingDelete = pFirstReadBlock; 53 | pFirstReadBlock = pFirstReadBlock->pNextBlock; 54 | Delete(_pPendingDelete); 55 | } 56 | 57 | return nullptr; 58 | } 59 | 60 | void Push(_In_ Entry* _pEntry) 61 | { 62 | if (!pLastWriteBlock) 63 | { 64 | pFirstReadBlock = pLastWriteBlock = New(); 65 | } 66 | 67 | // 如果满了就尝试链接到下一块 68 | if (pLastWriteBlock->IsFull()) 69 | { 70 | auto _pNextBlock = New(); 71 | pLastWriteBlock->pNextBlock = _pNextBlock; 72 | pLastWriteBlock = _pNextBlock; 73 | } 74 | 75 | pLastWriteBlock->arrLoopBuffer[pLastWriteBlock->uLastWriteIndex % kMaxBlockSize] = _pEntry; 76 | pLastWriteBlock->uLastWriteIndex += 1; 77 | } 78 | }; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/shell32.UnitTest.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Thunks/shell32.hpp" 3 | 4 | namespace shell32 5 | { 6 | __if_exists(YY::Thunks::aways_null_try_get_SHGetKnownFolderPath) 7 | { 8 | TEST_CLASS(SHGetKnownFolderPath) 9 | { 10 | AwaysNullGuard Guard; 11 | 12 | public: 13 | SHGetKnownFolderPath() 14 | { 15 | Guard |= YY::Thunks::aways_null_try_get_SHGetKnownFolderPath; 16 | } 17 | 18 | TEST_METHOD(基本验证) 19 | { 20 | { 21 | wchar_t* _szValue = nullptr; 22 | auto hr = ::SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_CREATE, nullptr, &_szValue); 23 | Assert::IsTrue(SUCCEEDED(hr)); 24 | CoTaskMemFree(_szValue); 25 | } 26 | 27 | { 28 | wchar_t* _szValue = nullptr; 29 | auto hr = ::SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_CREATE | KF_FLAG_DEFAULT_PATH, nullptr, &_szValue); 30 | Assert::IsTrue(SUCCEEDED(hr)); 31 | CoTaskMemFree(_szValue); 32 | } 33 | 34 | { 35 | wchar_t* _szValue = nullptr; 36 | auto hr = ::SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_CREATE | KF_FLAG_DEFAULT_PATH | KF_FLAG_NOT_PARENT_RELATIVE, nullptr, &_szValue); 37 | Assert::IsTrue(SUCCEEDED(hr)); 38 | CoTaskMemFree(_szValue); 39 | } 40 | 41 | // KF_FLAG_NOT_PARENT_RELATIVE必须跟 KF_FLAG_DEFAULT_PATH一起使用 42 | { 43 | wchar_t* _szValue = nullptr; 44 | auto hr = ::SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_CREATE | KF_FLAG_NOT_PARENT_RELATIVE, nullptr, &_szValue); 45 | Assert::AreEqual(hr, E_INVALIDARG); 46 | } 47 | } 48 | }; 49 | } 50 | 51 | __if_exists(YY::Thunks::aways_null_try_get_SHGetKnownFolderIDList) 52 | { 53 | TEST_CLASS(SHGetKnownFolderIDList) 54 | { 55 | AwaysNullGuard Guard; 56 | 57 | public: 58 | SHGetKnownFolderIDList() 59 | { 60 | Guard |= YY::Thunks::aways_null_try_get_SHGetKnownFolderIDList; 61 | } 62 | 63 | TEST_METHOD(基本验证) 64 | { 65 | PIDLIST_ABSOLUTE _List = nullptr; 66 | auto hr = ::SHGetKnownFolderIDList(FOLDERID_Documents, KF_FLAG_CREATE, nullptr, &_List); 67 | Assert::IsTrue(SUCCEEDED(hr)); 68 | ILFree(_List); 69 | } 70 | }; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=crlf 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /src/def/x64/esent.def: -------------------------------------------------------------------------------- 1 | ;Windows Vista开始,新增了A后缀来代替统一表示ANSI版函数 2 | 3 | [Symbols] 4 | JetAddColumnA=JetAddColumn 5 | JetAttachDatabaseA=JetAttachDatabase 6 | JetAttachDatabase2A=JetAttachDatabase2 7 | JetAttachDatabaseWithStreamingA=JetAttachDatabaseWithStreaming 8 | JetBackupA=JetBackup 9 | JetBackupInstanceA=JetBackupInstance 10 | JetBeginSessionA=JetBeginSession 11 | JetCompactA=JetCompact 12 | JetConvertDDLA=JetConvertDDL 13 | JetCreateDatabaseA=JetCreateDatabase 14 | JetCreateDatabase2A=JetCreateDatabase2 15 | JetCreateDatabaseWithStreamingA=JetCreateDatabaseWithStreaming 16 | JetCreateIndexA=JetCreateIndex 17 | JetCreateIndex2A=JetCreateIndex2 18 | JetCreateInstanceA=JetCreateInstance 19 | JetCreateInstance2A=JetCreateInstance2 20 | JetCreateTableA=JetCreateTable 21 | JetCreateTableColumnIndexA=JetCreateTableColumnIndex 22 | JetCreateTableColumnIndex2A=JetCreateTableColumnIndex2 23 | JetDBUtilitiesA=JetDBUtilities 24 | JetDefragmentA=JetDefragment 25 | JetDefragment2A=JetDefragment2 26 | JetDeleteColumnA=JetDeleteColumn 27 | JetDeleteColumn2A=JetDeleteColumn2 28 | JetDeleteIndexA=JetDeleteIndex 29 | JetDeleteTableA=JetDeleteTable 30 | JetDetachDatabaseA=JetDetachDatabase 31 | JetDetachDatabase2A=JetDetachDatabase2 32 | JetEnableMultiInstanceA=JetEnableMultiInstance 33 | JetExternalRestoreA=JetExternalRestore 34 | JetExternalRestore2A=JetExternalRestore2 35 | JetGetAttachInfoA=JetGetAttachInfo 36 | JetGetAttachInfoInstanceA=JetGetAttachInfoInstance 37 | JetGetColumnInfoA=JetGetColumnInfo 38 | JetGetCurrentIndexA=JetGetCurrentIndex 39 | JetGetDatabaseFileInfoA=JetGetDatabaseFileInfo 40 | JetGetDatabaseInfoA=JetGetDatabaseInfo 41 | JetGetIndexInfoA=JetGetIndexInfo 42 | JetGetInstanceInfoA=JetGetInstanceInfo 43 | JetGetLogInfoA=JetGetLogInfo 44 | JetGetLogInfoInstanceA=JetGetLogInfoInstance 45 | JetGetLogInfoInstance2A=JetGetLogInfoInstance2 46 | JetGetObjectInfoA=JetGetObjectInfo 47 | JetGetSystemParameterA=JetGetSystemParameter 48 | JetGetTableColumnInfoA=JetGetTableColumnInfo 49 | JetGetTableIndexInfoA=JetGetTableIndexInfo 50 | JetGetTableInfoA=JetGetTableInfo 51 | JetGetTruncateLogInfoInstanceA=JetGetTruncateLogInfoInstance 52 | JetInit3A=JetInit3 53 | JetOpenDatabaseA=JetOpenDatabase 54 | JetOpenFileA=JetOpenFile 55 | JetOpenFileInstanceA=JetOpenFileInstance 56 | JetOpenTableA=JetOpenTable 57 | JetOSSnapshotFreezeA=JetOSSnapshotFreeze 58 | JetRenameColumnA=JetRenameColumn 59 | JetRenameTableA=JetRenameTable 60 | JetRestoreA=JetRestore 61 | JetRestore2A=JetRestore2 62 | JetRestoreInstanceA=JetRestoreInstance 63 | JetSetColumnDefaultValueA=JetSetColumnDefaultValue 64 | JetSetCurrentIndexA=JetSetCurrentIndex 65 | JetSetCurrentIndex2A=JetSetCurrentIndex2 66 | JetSetCurrentIndex3A=JetSetCurrentIndex3 67 | JetSetCurrentIndex4A=JetSetCurrentIndex4 68 | JetSetDatabaseSizeA=JetSetDatabaseSize 69 | JetSetSystemParameterA=JetSetSystemParameter 70 | JetSnapshotStartA=JetSnapshotStart 71 | JetUpgradeDatabaseA=JetUpgradeDatabase 72 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_Report_en.yml: -------------------------------------------------------------------------------- 1 | name: "Bug Report Template - English" 2 | description: "Use this template to report a bug when using YY-Thunks" 3 | title: "Brief title, such as: Crash/deadlock when calling XXXX" 4 | labels: ["进度:等待审核"] 5 | type: bug 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: "Clearly and concisely describe the bug title. Examples: Crash/deadlock when calling XXXX; Cannot find XXXX when linking; Calling XXXX returns unexpected results." 10 | 11 | - type: textarea 12 | id: background_en 13 | attributes: 14 | label: "Background Information" 15 | description: "Provide relevant environment details." 16 | placeholder: | 17 | - Screenshot of error: 18 | - Operating System Version: Windows 10 16299 arm64 19 | - YY-Thunks Version: v1.1.9 20 | - YY-Thunks Configuration: Compatible to 6.0.6000 21 | - VC Toolset Version: 14.14.26428 22 | - Project Platform: x64 23 | validations: 24 | required: true 25 | 26 | - type: textarea 27 | id: expected_en 28 | attributes: 29 | label: "Expected behavior" 30 | description: "Describe what should happen. Example: Calling XXXX should normally return XXX." 31 | placeholder: "Calling XXXX should normally return XXX" 32 | validations: 33 | required: true 34 | 35 | - type: textarea 36 | id: steps_en 37 | attributes: 38 | label: "Steps to reproduce" 39 | description: "Detail the steps to reproduce or provide minimum reproducible code." 40 | placeholder: | 41 | 1. Use XXXX version of YY-Thunks 42 | 2. Call XXXX function 43 | 3. Then call YYYY function 44 | 4. Observe crash/deadlock/unexpected results 45 | render: bash 46 | validations: 47 | required: true 48 | 49 | - type: textarea 50 | id: repro_code_en 51 | attributes: 52 | label: "Reproduction code example (C++)" 53 | description: "Provide a minimal, compilable C++14 example." 54 | placeholder: | 55 | ```cpp 56 | int main() 57 | { 58 | // Minimal reproducible code 59 | return 0; 60 | } 61 | ``` 62 | render: cpp 63 | 64 | - type: textarea 65 | id: investigation_en 66 | attributes: 67 | label: "Your Investigation Results" 68 | description: "Record the work done and clues found." 69 | placeholder: | 70 | - I have tried different versions of YY-Thunks; result is the same. 71 | - Only XXX OS version can reproduce. 72 | - Only the first call to XXXX gives incorrect results. 73 | 74 | - type: checkboxes 75 | id: confirmations_en 76 | attributes: 77 | label: "Confirm before submitting" 78 | options: 79 | - label: "I have searched existing issues for duplicates" 80 | - label: "I included detailed steps or a minimal repro" 81 | - label: "I included environment details" 82 | -------------------------------------------------------------------------------- /src/Thunks/api-ms-win-core-processtopology-obsolete.hpp: -------------------------------------------------------------------------------- 1 | 2 | namespace YY 3 | { 4 | namespace Thunks 5 | { 6 | #ifdef YY_Thunks_Implemented 7 | namespace Downlevel 8 | { 9 | //我们Windows 7以后才引入了组的概念,因此我们可以统一的假定 只有一组,并且不支持CPU热插拔。 10 | static 11 | DWORD 12 | WINAPI GetProcessorCount( 13 | _In_ WORD GroupNumber 14 | ) 15 | { 16 | if (GroupNumber == 0 || GroupNumber == ALL_PROCESSOR_GROUPS) 17 | { 18 | SYSTEM_INFO SystemInfo; 19 | GetSystemInfo(&SystemInfo); 20 | 21 | return SystemInfo.dwNumberOfProcessors; 22 | } 23 | 24 | SetLastError(ERROR_INVALID_PARAMETER); 25 | 26 | return 0; 27 | } 28 | } 29 | #endif 30 | 31 | #if (YY_Thunks_Target < __WindowsNT6_1) 32 | 33 | //Minimum supported client Windows 7 [desktop apps only] 34 | //Minimum supported server Windows Server 2008 R2 [desktop apps only] 35 | __DEFINE_THUNK( 36 | kernel32, 37 | 4, 38 | DWORD, 39 | WINAPI, 40 | GetMaximumProcessorCount, 41 | _In_ WORD GroupNumber 42 | ) 43 | { 44 | if (auto pGetMaximumProcessorCount = try_get_GetMaximumProcessorCount()) 45 | { 46 | return pGetMaximumProcessorCount(GroupNumber); 47 | } 48 | 49 | return Downlevel::GetProcessorCount(GroupNumber); 50 | } 51 | #endif 52 | 53 | 54 | #if (YY_Thunks_Target < __WindowsNT6_1) 55 | 56 | //Minimum supported client Windows 7 [desktop apps only] 57 | //Minimum supported server Windows Server 2008 R2 [desktop apps only] 58 | __DEFINE_THUNK( 59 | kernel32, 60 | 4, 61 | DWORD, 62 | WINAPI, 63 | GetActiveProcessorCount, 64 | _In_ WORD GroupNumber 65 | ) 66 | { 67 | if (auto pGetActiveProcessorCount = try_get_GetActiveProcessorCount()) 68 | { 69 | return pGetActiveProcessorCount(GroupNumber); 70 | } 71 | 72 | return Downlevel::GetProcessorCount(GroupNumber); 73 | } 74 | #endif 75 | 76 | 77 | #if (YY_Thunks_Target < __WindowsNT6_1) 78 | 79 | //Minimum supported client Windows 7 [desktop apps only] 80 | //Minimum supported server Windows Server 2008 R2 [desktop apps only] 81 | __DEFINE_THUNK( 82 | kernel32, 83 | 0, 84 | WORD, 85 | WINAPI, 86 | GetActiveProcessorGroupCount, 87 | VOID 88 | ) 89 | { 90 | if (auto pGetActiveProcessorGroupCount = try_get_GetActiveProcessorGroupCount()) 91 | { 92 | return pGetActiveProcessorGroupCount(); 93 | } 94 | 95 | //我们统一假定只有一组,事实也如此。 96 | return 1; 97 | } 98 | #endif 99 | 100 | 101 | #if (YY_Thunks_Target < __WindowsNT6_1) 102 | 103 | //Minimum supported client Windows 7 [desktop apps only] 104 | //Minimum supported server Windows Server 2008 R2 [desktop apps only] 105 | __DEFINE_THUNK( 106 | kernel32, 107 | 0, 108 | WORD, 109 | WINAPI, 110 | GetMaximumProcessorGroupCount, 111 | VOID 112 | ) 113 | { 114 | if (auto pGetMaximumProcessorGroupCount = try_get_GetMaximumProcessorGroupCount()) 115 | { 116 | return pGetMaximumProcessorGroupCount(); 117 | } 118 | 119 | //我们统一假定只有一组,事实也如此。 120 | return 1; 121 | } 122 | #endif 123 | } 124 | } -------------------------------------------------------------------------------- /src/Thunks/api-ms-win-core-version.hpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | namespace YY::Thunks 4 | { 5 | #if (YY_Thunks_Target < __WindowsNT6) 6 | 7 | //Windows Vista [desktop apps only] 8 | //Windows Server 2008 [desktop apps only] 9 | __DEFINE_THUNK( 10 | version, 11 | 20, 12 | BOOL, 13 | APIENTRY, 14 | GetFileVersionInfoExW, 15 | _In_ DWORD dwFlags, 16 | _In_ LPCWSTR lpwstrFilename, 17 | _Reserved_ DWORD dwHandle, 18 | _In_ DWORD dwLen, 19 | _Out_writes_bytes_(dwLen) LPVOID lpData 20 | ) 21 | { 22 | if (auto pGetFileVersionInfoExW = try_get_GetFileVersionInfoExW()) 23 | { 24 | return pGetFileVersionInfoExW(dwFlags, lpwstrFilename, dwHandle, dwLen, lpData); 25 | } 26 | 27 | return GetFileVersionInfoW(lpwstrFilename, dwHandle, dwLen, lpData); 28 | } 29 | #endif 30 | 31 | 32 | #if (YY_Thunks_Target < __WindowsNT6) 33 | 34 | //Windows Vista [desktop apps only] 35 | //Windows Server 2008 [desktop apps only] 36 | __DEFINE_THUNK( 37 | version, 38 | 20, 39 | BOOL, 40 | APIENTRY, 41 | GetFileVersionInfoExA, 42 | _In_ DWORD dwFlags, 43 | _In_ LPCSTR lpwstrFilename, 44 | _Reserved_ DWORD dwHandle, 45 | _In_ DWORD dwLen, 46 | _Out_writes_bytes_(dwLen) LPVOID lpData 47 | ) 48 | { 49 | if (auto pGetFileVersionInfoExA = try_get_GetFileVersionInfoExA()) 50 | { 51 | return pGetFileVersionInfoExA(dwFlags, lpwstrFilename, dwHandle, dwLen, lpData); 52 | } 53 | 54 | return GetFileVersionInfoA(lpwstrFilename, dwHandle, dwLen, lpData); 55 | } 56 | #endif 57 | 58 | 59 | #if (YY_Thunks_Target < __WindowsNT6) 60 | 61 | //Windows Vista [desktop apps only] 62 | //Windows Server 2008 [desktop apps only] 63 | __DEFINE_THUNK( 64 | version, 65 | 12, 66 | DWORD, 67 | APIENTRY, 68 | GetFileVersionInfoSizeExW, 69 | _In_ DWORD dwFlags, 70 | _In_ LPCWSTR lpwstrFilename, 71 | _Out_ LPDWORD lpdwHandle 72 | ) 73 | { 74 | if (auto pGetFileVersionInfoSizeExW = try_get_GetFileVersionInfoSizeExW()) 75 | { 76 | return pGetFileVersionInfoSizeExW(dwFlags, lpwstrFilename, lpdwHandle); 77 | } 78 | 79 | return GetFileVersionInfoSizeW(lpwstrFilename, lpdwHandle); 80 | } 81 | #endif 82 | 83 | 84 | #if (YY_Thunks_Target < __WindowsNT6) 85 | 86 | //Windows Vista [desktop apps only] 87 | //Windows Server 2008 [desktop apps only] 88 | __DEFINE_THUNK( 89 | version, 90 | 12, 91 | DWORD, 92 | APIENTRY, 93 | GetFileVersionInfoSizeExA, 94 | _In_ DWORD dwFlags, 95 | _In_ LPCSTR lpwstrFilename, 96 | _Out_ LPDWORD lpdwHandle 97 | ) 98 | { 99 | if (auto pGetFileVersionInfoSizeExA = try_get_GetFileVersionInfoSizeExA()) 100 | { 101 | return pGetFileVersionInfoSizeExA(dwFlags, lpwstrFilename, lpdwHandle); 102 | } 103 | 104 | return GetFileVersionInfoSizeA(lpwstrFilename, lpdwHandle); 105 | } 106 | #endif 107 | } //namespace YY::Thunks 108 | -------------------------------------------------------------------------------- /src/def/x86/esent.def: -------------------------------------------------------------------------------- 1 | ;Windows Vista开始,新增了A后缀来代替统一表示ANSI版函数 2 | 3 | [Symbols] 4 | JetAddColumnA@28=JetAddColumn@28 5 | JetAttachDatabaseA@12=JetAttachDatabase@12 6 | JetAttachDatabase2A@16=JetAttachDatabase2@16 7 | JetAttachDatabaseWithStreamingA@24=JetAttachDatabaseWithStreaming@24 8 | JetBackupA@12=JetBackup@12 9 | JetBackupInstanceA@16=JetBackupInstance@16 10 | JetBeginSessionA@16=JetBeginSession@16 11 | JetCompactA@24=JetCompact@24 12 | JetConvertDDLA@20=JetConvertDDL@20 13 | JetCreateDatabaseA@20=JetCreateDatabase@20 14 | JetCreateDatabase2A@20=JetCreateDatabase2@20 15 | JetCreateDatabaseWithStreamingA@28=JetCreateDatabaseWithStreaming@28 16 | JetCreateIndexA@28=JetCreateIndex@28 17 | JetCreateIndex2A@16=JetCreateIndex2@16 18 | JetCreateInstanceA@8=JetCreateInstance@8 19 | JetCreateInstance2A@16=JetCreateInstance2@16 20 | JetCreateTableA@24=JetCreateTable@24 21 | JetCreateTableColumnIndexA@12=JetCreateTableColumnIndex@12 22 | JetCreateTableColumnIndex2A@12=JetCreateTableColumnIndex2@12 23 | JetDBUtilitiesA@4=JetDBUtilities@4 24 | JetDefragmentA@24=JetDefragment@24 25 | JetDefragment2A@28=JetDefragment2@28 26 | JetDeleteColumnA@12=JetDeleteColumn@12 27 | JetDeleteColumn2A@16=JetDeleteColumn2@16 28 | JetDeleteIndexA@12=JetDeleteIndex@12 29 | JetDeleteTableA@12=JetDeleteTable@12 30 | JetDetachDatabaseA@8=JetDetachDatabase@8 31 | JetDetachDatabase2A@12=JetDetachDatabase2@12 32 | JetEnableMultiInstanceA@12=JetEnableMultiInstance@12 33 | JetExternalRestoreA@32=JetExternalRestore@32 34 | JetExternalRestore2A@40=JetExternalRestore2@40 35 | JetGetAttachInfoA@12=JetGetAttachInfo@12 36 | JetGetAttachInfoInstanceA@16=JetGetAttachInfoInstance@16 37 | JetGetColumnInfoA@28=JetGetColumnInfo@28 38 | JetGetCurrentIndexA@16=JetGetCurrentIndex@16 39 | JetGetDatabaseFileInfoA@16=JetGetDatabaseFileInfo@16 40 | JetGetDatabaseInfoA@20=JetGetDatabaseInfo@20 41 | JetGetIndexInfoA@28=JetGetIndexInfo@28 42 | JetGetInstanceInfoA@8=JetGetInstanceInfo@8 43 | JetGetLogInfoA@12=JetGetLogInfo@12 44 | JetGetLogInfoInstanceA@16=JetGetLogInfoInstance@16 45 | JetGetLogInfoInstance2A@20=JetGetLogInfoInstance2@20 46 | JetGetObjectInfoA@32=JetGetObjectInfo@32 47 | JetGetSystemParameterA@24=JetGetSystemParameter@24 48 | JetGetTableColumnInfoA@24=JetGetTableColumnInfo@24 49 | JetGetTableIndexInfoA@24=JetGetTableIndexInfo@24 50 | JetGetTableInfoA@20=JetGetTableInfo@20 51 | JetGetTruncateLogInfoInstanceA@16=JetGetTruncateLogInfoInstance@16 52 | JetInit3A@12=JetInit3@12 53 | JetOpenDatabaseA@20=JetOpenDatabase@20 54 | JetOpenFileA@16=JetOpenFile@16 55 | JetOpenFileInstanceA@20=JetOpenFileInstance@20 56 | JetOpenTableA@28=JetOpenTable@28 57 | JetOSSnapshotFreezeA@16=JetOSSnapshotFreeze@16 58 | JetRenameColumnA@20=JetRenameColumn@20 59 | JetRenameTableA@16=JetRenameTable@16 60 | JetRestoreA@8=JetRestore@8 61 | JetRestore2A@12=JetRestore2@12 62 | JetRestoreInstanceA@16=JetRestoreInstance@16 63 | JetSetColumnDefaultValueA@28=JetSetColumnDefaultValue@28 64 | JetSetCurrentIndexA@12=JetSetCurrentIndex@12 65 | JetSetCurrentIndex2A@16=JetSetCurrentIndex2@16 66 | JetSetCurrentIndex3A@20=JetSetCurrentIndex3@20 67 | JetSetCurrentIndex4A@24=JetSetCurrentIndex4@24 68 | JetSetDatabaseSizeA@16=JetSetDatabaseSize@16 69 | JetSetSystemParameterA@20=JetSetSystemParameter@20 70 | JetSnapshotStartA@12=JetSnapshotStart@12 71 | JetUpgradeDatabaseA@16=JetUpgradeDatabase@16 72 | -------------------------------------------------------------------------------- /src/YY_Thunks.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.10.34916.146 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "YY-Thunks.UnitTest", "YY-Thunks.UnitTest\YY-Thunks.UnitTest.vcxproj", "{96B7018D-5985-44A9-A549-8FE86787CD90}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D2258BCB-A66B-4928-9CF9-23D705B72DBD}" 9 | ProjectSection(SolutionItems) = preProject 10 | ..\Readme.md = ..\Readme.md 11 | ..\Readme.osc.md = ..\Readme.osc.md 12 | ..\ThunksList.md = ..\ThunksList.md 13 | EndProjectSection 14 | EndProject 15 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MinimumRequiredVersionHelper", "MinimumRequiredVersionHelper\MinimumRequiredVersionHelper.vcxproj", "{B51C6D0B-798E-4EC2-956D-6743A6C462D0}" 16 | EndProject 17 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "YY.Depends.Analyzer", "YY.Depends.Analyzer\YY.Depends.Analyzer.vcxproj", "{EDF20351-1BF1-4101-9198-220C7E77EE74}" 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|x64 = Debug|x64 22 | Debug|x86 = Debug|x86 23 | Release|x64 = Release|x64 24 | Release|x86 = Release|x86 25 | EndGlobalSection 26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 27 | {96B7018D-5985-44A9-A549-8FE86787CD90}.Debug|x64.ActiveCfg = Debug|x64 28 | {96B7018D-5985-44A9-A549-8FE86787CD90}.Debug|x64.Build.0 = Debug|x64 29 | {96B7018D-5985-44A9-A549-8FE86787CD90}.Debug|x86.ActiveCfg = Debug|Win32 30 | {96B7018D-5985-44A9-A549-8FE86787CD90}.Debug|x86.Build.0 = Debug|Win32 31 | {96B7018D-5985-44A9-A549-8FE86787CD90}.Release|x64.ActiveCfg = Release|x64 32 | {96B7018D-5985-44A9-A549-8FE86787CD90}.Release|x64.Build.0 = Release|x64 33 | {96B7018D-5985-44A9-A549-8FE86787CD90}.Release|x86.ActiveCfg = Release|Win32 34 | {96B7018D-5985-44A9-A549-8FE86787CD90}.Release|x86.Build.0 = Release|Win32 35 | {B51C6D0B-798E-4EC2-956D-6743A6C462D0}.Debug|x64.ActiveCfg = Debug|x64 36 | {B51C6D0B-798E-4EC2-956D-6743A6C462D0}.Debug|x64.Build.0 = Debug|x64 37 | {B51C6D0B-798E-4EC2-956D-6743A6C462D0}.Debug|x86.ActiveCfg = Debug|Win32 38 | {B51C6D0B-798E-4EC2-956D-6743A6C462D0}.Debug|x86.Build.0 = Debug|Win32 39 | {B51C6D0B-798E-4EC2-956D-6743A6C462D0}.Release|x64.ActiveCfg = Release|x64 40 | {B51C6D0B-798E-4EC2-956D-6743A6C462D0}.Release|x64.Build.0 = Release|x64 41 | {B51C6D0B-798E-4EC2-956D-6743A6C462D0}.Release|x86.ActiveCfg = Release|Win32 42 | {B51C6D0B-798E-4EC2-956D-6743A6C462D0}.Release|x86.Build.0 = Release|Win32 43 | {EDF20351-1BF1-4101-9198-220C7E77EE74}.Debug|x64.ActiveCfg = Debug|x64 44 | {EDF20351-1BF1-4101-9198-220C7E77EE74}.Debug|x64.Build.0 = Debug|x64 45 | {EDF20351-1BF1-4101-9198-220C7E77EE74}.Debug|x86.ActiveCfg = Debug|Win32 46 | {EDF20351-1BF1-4101-9198-220C7E77EE74}.Debug|x86.Build.0 = Debug|Win32 47 | {EDF20351-1BF1-4101-9198-220C7E77EE74}.Release|x64.ActiveCfg = Release|x64 48 | {EDF20351-1BF1-4101-9198-220C7E77EE74}.Release|x64.Build.0 = Release|x64 49 | {EDF20351-1BF1-4101-9198-220C7E77EE74}.Release|x86.ActiveCfg = Release|Win32 50 | {EDF20351-1BF1-4101-9198-220C7E77EE74}.Release|x86.Build.0 = Release|Win32 51 | EndGlobalSection 52 | GlobalSection(SolutionProperties) = preSolution 53 | HideSolutionNode = FALSE 54 | EndGlobalSection 55 | GlobalSection(ExtensibilityGlobals) = postSolution 56 | SolutionGuid = {A4452926-FD5C-4FD0-AF1E-91ED99AA4091} 57 | EndGlobalSection 58 | EndGlobal 59 | -------------------------------------------------------------------------------- /src/Thunks/dcomp.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT10_10240) 2 | #include 3 | #endif 4 | 5 | #if (YY_Thunks_Target < __WindowsNT10_10240) && (YY_Thunks_Target >= __WindowsNT6_2 || __YY_Thunks_libs) && !defined(__Comment_Lib_dcomp) 6 | #define __Comment_Lib_dcomp 7 | #pragma comment(lib, "Dcomp.lib") 8 | #endif 9 | 10 | namespace YY::Thunks 11 | { 12 | #if (YY_Thunks_Target < __WindowsNT6_2) 13 | 14 | // 最低受支持的客户端 Windows 8 [仅限桌面应用] 15 | // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] 16 | __DEFINE_THUNK( 17 | dcomp, 18 | 12, 19 | HRESULT, 20 | WINAPI, 21 | DCompositionCreateDevice, 22 | _In_opt_ IDXGIDevice* _pDxgiDevice, 23 | _In_ REFIID iid, 24 | _Outptr_ void** _pDcompositionDevice 25 | ) 26 | { 27 | if (const auto _pfnDCompositionCreateDevice = try_get_DCompositionCreateDevice()) 28 | { 29 | return _pfnDCompositionCreateDevice(_pDxgiDevice, iid, _pDcompositionDevice); 30 | } 31 | 32 | if (!_pDcompositionDevice) 33 | return E_POINTER; 34 | 35 | *_pDcompositionDevice = nullptr; 36 | return E_NOTIMPL; 37 | } 38 | #endif 39 | 40 | 41 | #if (YY_Thunks_Target < __WindowsNT6_3) 42 | 43 | // 最低受支持的客户端 Windows 8.1 [仅限桌面应用] 44 | // 最低受支持的服务器 Windows Server 2012 R2[仅限桌面应用] 45 | __DEFINE_THUNK( 46 | dcomp, 47 | 12, 48 | HRESULT, 49 | WINAPI, 50 | DCompositionCreateDevice2, 51 | _In_opt_ IUnknown* _pRenderingDevice, 52 | _In_ REFIID iid, 53 | _Outptr_ void** _pDcompositionDevice 54 | ) 55 | { 56 | if (const auto _pfnDCompositionCreateDevice2 = try_get_DCompositionCreateDevice2()) 57 | { 58 | return _pfnDCompositionCreateDevice2(_pRenderingDevice, iid, _pDcompositionDevice); 59 | } 60 | 61 | if (!_pDcompositionDevice) 62 | return E_POINTER; 63 | 64 | *_pDcompositionDevice = nullptr; 65 | 66 | IDXGIDevice* _pDxgiDevice = nullptr; 67 | if (_pRenderingDevice) 68 | { 69 | auto _hr = _pRenderingDevice->QueryInterface(IID_PPV_ARGS(&_pDxgiDevice)); 70 | if(FAILED(_hr)) 71 | { 72 | return _hr; 73 | } 74 | 75 | if (!_pDxgiDevice) 76 | { 77 | return E_NOINTERFACE; 78 | } 79 | } 80 | 81 | auto _hr = DCompositionCreateDevice(_pDxgiDevice, iid, _pDcompositionDevice); 82 | if (_pDxgiDevice) 83 | { 84 | _pDxgiDevice->Release(); 85 | } 86 | 87 | return _hr; 88 | } 89 | #endif 90 | 91 | 92 | #if (YY_Thunks_Target < __WindowsNT10_10240) 93 | 94 | // 最低受支持的客户端 Windows 10.0.10240 95 | __DEFINE_THUNK( 96 | dcomp, 97 | 12, 98 | HRESULT, 99 | WINAPI, 100 | DCompositionCreateDevice3, 101 | _In_opt_ IUnknown* _pRenderingDevice, 102 | _In_ REFIID iid, 103 | _Outptr_ void** _pDcompositionDevice 104 | ) 105 | { 106 | if (const auto _pfnDCompositionCreateDevice3 = try_get_DCompositionCreateDevice3()) 107 | { 108 | return _pfnDCompositionCreateDevice3(_pRenderingDevice, iid, _pDcompositionDevice); 109 | } 110 | 111 | return DCompositionCreateDevice2(_pRenderingDevice, iid, _pDcompositionDevice); 112 | } 113 | #endif 114 | } 115 | -------------------------------------------------------------------------------- /src/YY.Depends.Analyzer/YY.Depends.Analyzer.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {1b2150a9-3ecd-466c-8ed6-4c05d2b5feb9} 18 | 19 | 20 | {bd9cc60a-cd73-4766-a69b-50fdfa675fc6} 21 | 22 | 23 | {367324e4-0b88-4554-b1e1-cb4204867029} 24 | 25 | 26 | {78ecf8b4-b05b-4c32-9e69-ffa7d56eae5b} 27 | 28 | 29 | 30 | 31 | 源文件 32 | 33 | 34 | 源文件\WinDepends.Core 35 | 36 | 37 | 38 | 39 | 资源文件\Config\x64 40 | 41 | 42 | 资源文件\Config\x64 43 | 44 | 45 | 资源文件\Config\x64 46 | 47 | 48 | 资源文件\Config\x64 49 | 50 | 51 | 资源文件\Config\x64 52 | 53 | 54 | 资源文件\Config\x64 55 | 56 | 57 | 资源文件\Config\x64 58 | 59 | 60 | 资源文件\Config\x86 61 | 62 | 63 | 资源文件\Config\x86 64 | 65 | 66 | 资源文件\Config\x86 67 | 68 | 69 | 资源文件\Config\x86 70 | 71 | 72 | 资源文件\Config\x86 73 | 74 | 75 | 资源文件\Config\x86 76 | 77 | 78 | 资源文件\Config\x86 79 | 80 | 81 | 82 | 83 | 源文件\WinDepends.Core 84 | 85 | 86 | -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/Crypt32.UnitTest.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Thunks/Crypt32.hpp" 3 | 4 | #include 5 | 6 | #pragma comment(lib, "Crypt32.lib") 7 | 8 | namespace Crypt32 9 | { 10 | TEST_CLASS(CryptBinaryToStringW) 11 | { 12 | AwaysNullGuard Guard; 13 | 14 | public: 15 | CryptBinaryToStringW() 16 | { 17 | g_uSystemVersion = MakeVersion(5, 1, 2600); 18 | } 19 | 20 | ~CryptBinaryToStringW() 21 | { 22 | g_uSystemVersion = 0; 23 | } 24 | 25 | TEST_METHOD(CRYPT_STRING_NOCRLF参数验证) 26 | { 27 | wchar_t _szUnitTestDll[512]; 28 | GetModuleFileNameW((HMODULE)&__ImageBase, _szUnitTestDll, std::size(_szUnitTestDll)); 29 | 30 | const auto _FileData = ReadFileData(_szUnitTestDll); 31 | Assert::AreNotEqual(_FileData.size(), size_t(0)); 32 | 33 | { 34 | DWORD _cchOut = 0; 35 | Assert::IsTrue(::CryptBinaryToStringW((const BYTE*)_FileData.c_str(), _FileData.size(), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, &_cchOut)); 36 | 37 | auto _szOutBuffer = new wchar_t[_cchOut]; 38 | Assert::IsNotNull(_szOutBuffer); 39 | 40 | Assert::IsTrue(::CryptBinaryToStringW((const BYTE*)_FileData.c_str(), _FileData.size(), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, _szOutBuffer, &_cchOut)); 41 | 42 | Assert::AreEqual(size_t(_cchOut), wcslen(_szOutBuffer)); 43 | 44 | Assert::IsNull(wcschr(_szOutBuffer, L'\r')); 45 | Assert::IsNull(wcschr(_szOutBuffer, L'\n')); 46 | 47 | DWORD _cbBinary = 0; 48 | Assert::IsTrue(::CryptStringToBinaryW(_szOutBuffer, _cchOut, CRYPT_STRING_BASE64, nullptr, &_cbBinary, nullptr, nullptr)); 49 | Assert::AreEqual(size_t(_cbBinary), _FileData.size()); 50 | 51 | std::string _Binary; 52 | _Binary.resize(_cbBinary); 53 | Assert::IsTrue(::CryptStringToBinaryW(_szOutBuffer, _cchOut, CRYPT_STRING_BASE64, (BYTE*)_Binary.data(), &_cbBinary, nullptr, nullptr)); 54 | Assert::AreEqual(_FileData, _Binary); 55 | 56 | delete[] _szOutBuffer; 57 | } 58 | 59 | { 60 | DWORD _cchOut = 0; 61 | Assert::IsTrue(::CryptBinaryToStringA((const BYTE*)_FileData.c_str(), _FileData.size(), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, &_cchOut)); 62 | 63 | auto _szOutBuffer = new char[_cchOut]; 64 | Assert::IsNotNull(_szOutBuffer); 65 | 66 | Assert::IsTrue(::CryptBinaryToStringA((const BYTE*)_FileData.c_str(), _FileData.size(), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, _szOutBuffer, &_cchOut)); 67 | 68 | Assert::AreEqual(size_t(_cchOut), strlen(_szOutBuffer)); 69 | 70 | Assert::IsNull(strchr(_szOutBuffer, '\r')); 71 | Assert::IsNull(strchr(_szOutBuffer, '\n')); 72 | 73 | DWORD _cbBinary = 0; 74 | Assert::IsTrue(::CryptStringToBinaryA(_szOutBuffer, _cchOut, CRYPT_STRING_BASE64, nullptr, &_cbBinary, nullptr, nullptr)); 75 | Assert::AreEqual(size_t(_cbBinary), _FileData.size()); 76 | 77 | std::string _Binary; 78 | _Binary.resize(_cbBinary); 79 | Assert::IsTrue(::CryptStringToBinaryA(_szOutBuffer, _cchOut, CRYPT_STRING_BASE64, (BYTE*)_Binary.data(), &_cbBinary, nullptr, nullptr)); 80 | Assert::AreEqual(_FileData, _Binary); 81 | 82 | delete[] _szOutBuffer; 83 | } 84 | } 85 | }; 86 | } 87 | -------------------------------------------------------------------------------- /src/Thunks/api-ms-win-core-errorhandling.hpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | namespace YY::Thunks 4 | { 5 | #if (YY_Thunks_Target < __WindowsNT6_1) 6 | 7 | //Windows 7 [desktop apps | UWP apps] 8 | //Windows Server 2008 R2 [desktop apps | UWP apps] 9 | __DEFINE_THUNK( 10 | kernel32, 11 | 12, 12 | VOID, 13 | WINAPI, 14 | RaiseFailFastException, 15 | _In_opt_ PEXCEPTION_RECORD pExceptionRecord, 16 | _In_opt_ PCONTEXT pContextRecord, 17 | _In_ DWORD dwFlags 18 | ) 19 | { 20 | if (auto pRaiseFailFastException = try_get_RaiseFailFastException()) 21 | { 22 | return pRaiseFailFastException(pExceptionRecord, pContextRecord, dwFlags); 23 | } 24 | 25 | //直接结束进程 26 | TerminateProcess(NtGetCurrentProcess(), pExceptionRecord ? pExceptionRecord->ExceptionCode : STATUS_FAIL_FAST_EXCEPTION); 27 | } 28 | #endif 29 | 30 | 31 | #if (YY_Thunks_Target < __WindowsNT6_1) 32 | 33 | //Windows 7 [desktop apps | UWP apps] 34 | //Windows Server 2008 R2 [desktop apps | UWP apps] 35 | __DEFINE_THUNK( 36 | kernel32, 37 | 8, 38 | BOOL, 39 | WINAPI, 40 | SetThreadErrorMode, 41 | _In_ DWORD dwNewMode, 42 | _In_opt_ LPDWORD lpOldMode 43 | ) 44 | { 45 | if (auto pSetThreadErrorMode = try_get_SetThreadErrorMode()) 46 | { 47 | return pSetThreadErrorMode(dwNewMode, lpOldMode); 48 | } 49 | 50 | auto dwOldMode = SetErrorMode(dwNewMode); 51 | if (lpOldMode) 52 | *lpOldMode = dwOldMode; 53 | 54 | return TRUE; 55 | } 56 | #endif 57 | 58 | 59 | #if (YY_Thunks_Target < __WindowsNT6_1) 60 | 61 | //Windows 7 [desktop apps | UWP apps] 62 | //Windows Server 2008 R2 [desktop apps | UWP apps] 63 | __DEFINE_THUNK( 64 | kernel32, 65 | 0, 66 | DWORD, 67 | WINAPI, 68 | GetThreadErrorMode, 69 | VOID 70 | ) 71 | { 72 | if (auto pGetThreadErrorMode = try_get_GetThreadErrorMode()) 73 | { 74 | return pGetThreadErrorMode(); 75 | } 76 | 77 | return GetErrorMode(); 78 | } 79 | #endif 80 | 81 | 82 | #if (YY_Thunks_Target < __WindowsNT6) 83 | 84 | //Windows Vista [desktop apps only] 85 | //Windows Server 2008 [desktop apps only] 86 | __DEFINE_THUNK( 87 | kernel32, 88 | 0, 89 | UINT, 90 | WINAPI, 91 | GetErrorMode, 92 | VOID 93 | ) 94 | { 95 | if (auto pGetErrorMode = try_get_GetErrorMode()) 96 | { 97 | return pGetErrorMode(); 98 | } 99 | 100 | #if !defined(__USING_NTDLL_LIB) 101 | const auto NtQueryInformationProcess = try_get_NtQueryInformationProcess(); 102 | if (!NtQueryInformationProcess) 103 | { 104 | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 105 | return 0; 106 | } 107 | #endif 108 | DWORD dwDefaultHardErrorMode; 109 | 110 | LONG Status = NtQueryInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &dwDefaultHardErrorMode, sizeof(dwDefaultHardErrorMode), nullptr); 111 | 112 | if (Status >= 0) 113 | { 114 | if (dwDefaultHardErrorMode & 0x00000001) 115 | { 116 | return dwDefaultHardErrorMode & 0xFFFFFFFE; 117 | } 118 | else 119 | { 120 | return dwDefaultHardErrorMode | 0x00000001; 121 | } 122 | } 123 | 124 | internal::BaseSetLastNTError(Status); 125 | return 0; 126 | } 127 | #endif 128 | } //namespace YY::Thunks 129 | -------------------------------------------------------------------------------- /src/Thunks/wevtapi.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6) 2 | #include 3 | #endif 4 | 5 | #if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_wevtapi) 6 | #define __Comment_Lib_wevtapi 7 | #pragma comment(lib, "wevtapi.lib") 8 | #endif 9 | 10 | namespace YY::Thunks 11 | { 12 | #if (YY_Thunks_Target < __WindowsNT6) 13 | 14 | // Minimum supported client Windows Vista [desktop apps only] 15 | // Minimum supported server Windows Server 2008[desktop apps only] 16 | __DEFINE_THUNK( 17 | wevtapi, 18 | 4, 19 | BOOL, 20 | WINAPI, 21 | EvtClose, 22 | _In_ _Post_invalid_ EVT_HANDLE Object 23 | ) 24 | { 25 | if (auto const _pfnEvtClose = try_get_EvtClose()) 26 | { 27 | return _pfnEvtClose(Object); 28 | } 29 | 30 | return TRUE; 31 | } 32 | #endif 33 | 34 | 35 | #if (YY_Thunks_Target < __WindowsNT6) 36 | 37 | // Minimum supported client Windows Vista [desktop apps only] 38 | // Minimum supported server Windows Server 2008[desktop apps only] 39 | __DEFINE_THUNK( 40 | wevtapi, 41 | 12, 42 | EVT_HANDLE, 43 | WINAPI, 44 | EvtCreateRenderContext, 45 | DWORD ValuePathsCount, 46 | _In_reads_opt_(ValuePathsCount) LPCWSTR* ValuePaths, 47 | DWORD Flags 48 | ) 49 | { 50 | if (auto const _pfnEvtCreateRenderContext = try_get_EvtCreateRenderContext()) 51 | { 52 | return _pfnEvtCreateRenderContext(ValuePathsCount, ValuePaths, Flags); 53 | } 54 | 55 | SetLastError(ERROR_NOT_SUPPORTED); 56 | return NULL; 57 | } 58 | #endif 59 | 60 | 61 | #if (YY_Thunks_Target < __WindowsNT6) 62 | 63 | // Minimum supported client Windows Vista [desktop apps only] 64 | // Minimum supported server Windows Server 2008[desktop apps only] 65 | __DEFINE_THUNK( 66 | wevtapi, 67 | 24, 68 | BOOL, 69 | WINAPI, 70 | EvtNext, 71 | _In_ EVT_HANDLE ResultSet, 72 | DWORD EventsSize, 73 | _Out_writes_to_(EventsSize, *Returned) PEVT_HANDLE Events, 74 | DWORD Timeout, 75 | DWORD Flags, 76 | _Out_range_(0, EventsSize) PDWORD Returned 77 | ) 78 | { 79 | if (auto const _pfnEvtNext = try_get_EvtNext()) 80 | { 81 | return _pfnEvtNext(ResultSet, EventsSize, Events, Timeout, Flags, Returned); 82 | } 83 | 84 | SetLastError(ERROR_NOT_SUPPORTED); 85 | return FALSE; 86 | } 87 | #endif 88 | 89 | 90 | #if (YY_Thunks_Target < __WindowsNT6) 91 | 92 | // Minimum supported client Windows Vista [desktop apps only] 93 | // Minimum supported server Windows Server 2008[desktop apps only] 94 | __DEFINE_THUNK( 95 | wevtapi, 96 | 16, 97 | EVT_HANDLE, 98 | WINAPI, 99 | EvtQuery, 100 | _In_opt_ EVT_HANDLE Session, 101 | _In_opt_z_ LPCWSTR Path, 102 | _In_opt_z_ LPCWSTR Query, 103 | DWORD Flags 104 | ) 105 | { 106 | if (auto const _pfnEvtQuery = try_get_EvtQuery()) 107 | { 108 | return _pfnEvtQuery(Session, Path, Query, Flags); 109 | } 110 | SetLastError(ERROR_NOT_SUPPORTED); 111 | return NULL; 112 | } 113 | #endif 114 | 115 | 116 | #if (YY_Thunks_Target < __WindowsNT6) 117 | 118 | // Minimum supported client Windows Vista [desktop apps only] 119 | // Minimum supported server Windows Server 2008[desktop apps only] 120 | __DEFINE_THUNK( 121 | wevtapi, 122 | 28, 123 | BOOL, 124 | WINAPI, 125 | EvtRender, 126 | _In_opt_ EVT_HANDLE Context, 127 | _In_ EVT_HANDLE Fragment, 128 | DWORD Flags, 129 | DWORD BufferSize, 130 | _Out_writes_bytes_to_opt_(BufferSize, *BufferUsed) PVOID Buffer, 131 | _Out_ PDWORD BufferUsed, 132 | _Out_ PDWORD PropertyCount 133 | ) 134 | { 135 | if (auto const _pfnEvtRender = try_get_EvtRender()) 136 | { 137 | return _pfnEvtRender(Context, Fragment, Flags, BufferSize, Buffer, BufferUsed, PropertyCount); 138 | } 139 | SetLastError(ERROR_NOT_SUPPORTED); 140 | return FALSE; 141 | } 142 | #endif 143 | } //namespace YY::Thunks 144 | -------------------------------------------------------------------------------- /src/Thunks/userenv.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6_2) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #if (YY_Thunks_Target < __WindowsNT6_2) 8 | 9 | // 最低受支持的客户端 Windows 8 [仅限桌面应用] 10 | // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] 11 | __DEFINE_THUNK( 12 | userenv, 13 | 24, 14 | HRESULT, 15 | WINAPI, 16 | CreateAppContainerProfile, 17 | _In_ PCWSTR _szAppContainerName, 18 | _In_ PCWSTR _szDisplayName, 19 | _In_ PCWSTR _szDescription, 20 | _In_reads_opt_(_uCapabilityCount) PSID_AND_ATTRIBUTES _pCapabilities, 21 | _In_ DWORD _uCapabilityCount, 22 | _Outptr_ PSID* _ppSidAppContainerSid 23 | ) 24 | { 25 | if (const auto _pfnCreateAppContainerProfile = try_get_CreateAppContainerProfile()) 26 | { 27 | return _pfnCreateAppContainerProfile(_szAppContainerName, _szDisplayName, _szDescription, _pCapabilities, _uCapabilityCount, _ppSidAppContainerSid); 28 | } 29 | 30 | if (!_ppSidAppContainerSid) 31 | return E_INVALIDARG; 32 | *_ppSidAppContainerSid = nullptr; 33 | return E_NOTIMPL; 34 | } 35 | #endif 36 | 37 | 38 | #if (YY_Thunks_Target < __WindowsNT6_2) 39 | 40 | // 最低受支持的客户端 Windows 8 [仅限桌面应用] 41 | // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] 42 | __DEFINE_THUNK( 43 | userenv, 44 | 4, 45 | HRESULT, 46 | WINAPI, 47 | DeleteAppContainerProfile, 48 | _In_ PCWSTR _szAppContainerName 49 | ) 50 | { 51 | if (const auto _pfnDeleteAppContainerProfile = try_get_DeleteAppContainerProfile()) 52 | { 53 | return _pfnDeleteAppContainerProfile(_szAppContainerName); 54 | } 55 | 56 | return E_NOTIMPL; 57 | } 58 | #endif 59 | 60 | 61 | #if (YY_Thunks_Target < __WindowsNT6_2) 62 | 63 | // 最低受支持的客户端 Windows 8 [仅限桌面应用] 64 | // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] 65 | __DEFINE_THUNK( 66 | userenv, 67 | 8, 68 | HRESULT, 69 | WINAPI, 70 | DeriveAppContainerSidFromAppContainerName, 71 | _In_ PCWSTR _szAppContainerName, 72 | _Outptr_ PSID* _ppsidAppContainerSid 73 | ) 74 | { 75 | if (const auto _pfnDeriveAppContainerSidFromAppContainerName = try_get_DeriveAppContainerSidFromAppContainerName()) 76 | { 77 | return _pfnDeriveAppContainerSidFromAppContainerName(_szAppContainerName, _ppsidAppContainerSid); 78 | } 79 | if (!_ppsidAppContainerSid) 80 | return E_INVALIDARG; 81 | *_ppsidAppContainerSid = nullptr; 82 | return E_NOTIMPL; 83 | } 84 | #endif 85 | 86 | 87 | #if (YY_Thunks_Target < __WindowsNT6_2) 88 | 89 | // 最低受支持的客户端 Windows 8 [仅限桌面应用] 90 | // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] 91 | __DEFINE_THUNK( 92 | userenv, 93 | 8, 94 | HRESULT, 95 | WINAPI, 96 | GetAppContainerFolderPath, 97 | _In_ PCWSTR _szAppContainerSid, 98 | _Outptr_ PWSTR* _ppszPath 99 | ) 100 | { 101 | if (const auto _pfnGetAppContainerFolderPath = try_get_GetAppContainerFolderPath()) 102 | { 103 | return _pfnGetAppContainerFolderPath(_szAppContainerSid, _ppszPath); 104 | } 105 | if (!_ppszPath) 106 | return E_INVALIDARG; 107 | *_ppszPath = nullptr; 108 | return E_NOTIMPL; 109 | } 110 | #endif 111 | 112 | 113 | #if (YY_Thunks_Target < __WindowsNT6_2) 114 | 115 | // 最低受支持的客户端 Windows 8 [仅限桌面应用] 116 | // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] 117 | __DEFINE_THUNK( 118 | userenv, 119 | 8, 120 | HRESULT, 121 | WINAPI, 122 | GetAppContainerRegistryLocation, 123 | _In_ REGSAM _DesiredAccess, 124 | _Outptr_ PHKEY _phAppContainerKey 125 | ) 126 | { 127 | if (const auto _pfnGetAppContainerRegistryLocation = try_get_GetAppContainerRegistryLocation()) 128 | { 129 | return _pfnGetAppContainerRegistryLocation(_DesiredAccess, _phAppContainerKey); 130 | } 131 | if (!_phAppContainerKey) 132 | return E_INVALIDARG; 133 | *_phAppContainerKey = NULL; 134 | return E_NOTIMPL; 135 | } 136 | #endif 137 | } // namespace YY::Thunks 138 | -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/api-ms-win-core-fibers.UnitTest.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Thunks/api-ms-win-core-fibers.hpp" 3 | 4 | 5 | namespace api_ms_win_core_fibers 6 | { 7 | __if_exists(YY::Thunks::aways_null_try_get_FlsAlloc) 8 | { 9 | TEST_CLASS(FlsGet_SetValue) 10 | { 11 | AwaysNullGuard Guard; 12 | 13 | public: 14 | FlsGet_SetValue() 15 | { 16 | Guard |= YY::Thunks::aways_null_try_get_FlsAlloc; 17 | Guard |= YY::Thunks::aways_null_try_get_FlsFree; 18 | Guard |= YY::Thunks::aways_null_try_get_FlsGetValue; 19 | Guard |= YY::Thunks::aways_null_try_get_FlsSetValue; 20 | } 21 | 22 | TEST_METHOD(单线程验证) 23 | { 24 | auto Index = ::FlsAlloc(nullptr); 25 | 26 | Assert::AreNotEqual(Index, FLS_OUT_OF_INDEXES); 27 | 28 | Assert::AreEqual((long)::FlsGetValue(Index), 0l); 29 | 30 | 31 | Assert::IsTrue(::FlsSetValue(Index, (void*)77)); 32 | 33 | Assert::AreEqual((long)::FlsGetValue(Index), 77l); 34 | 35 | Assert::IsTrue(::FlsFree(Index)); 36 | } 37 | 38 | TEST_METHOD(多线程验证) 39 | { 40 | auto Index = ::FlsAlloc(nullptr); 41 | 42 | Assert::AreNotEqual(Index, FLS_OUT_OF_INDEXES); 43 | 44 | Assert::IsTrue(::FlsSetValue(Index, (void*)-1)); 45 | 46 | HANDLE hHandles[100]; 47 | 48 | for (auto& hHandle : hHandles) 49 | { 50 | hHandle = (HANDLE)_beginthreadex(nullptr, 0, [](void* Index) -> unsigned 51 | { 52 | Assert::AreEqual((long)::FlsGetValue((DWORD)Index), 0l); 53 | 54 | 55 | Assert::IsTrue(::FlsSetValue((DWORD)Index, (void*)GetCurrentThreadId())); 56 | 57 | Sleep(100); 58 | 59 | Assert::AreEqual((long)::FlsGetValue((DWORD)Index), (long)GetCurrentThreadId()); 60 | 61 | 62 | return 0; 63 | }, (void*)Index, 0, nullptr); 64 | 65 | Assert::IsNotNull(hHandle); 66 | } 67 | 68 | for (auto hHandle : hHandles) 69 | { 70 | Assert::AreEqual(WaitForSingleObject(hHandle, 1000), (DWORD)WAIT_OBJECT_0); 71 | 72 | CloseHandle(hHandle); 73 | } 74 | 75 | Assert::AreEqual((long)::FlsGetValue((DWORD)Index), -1l); 76 | 77 | Assert::IsTrue(::FlsFree(Index)); 78 | } 79 | 80 | TEST_METHOD(Fls释放销毁回调验证) 81 | { 82 | auto Index = ::FlsAlloc([](void* pFlsData) 83 | { 84 | InterlockedIncrement((long*)pFlsData); 85 | 86 | }); 87 | 88 | Assert::AreNotEqual(Index, FLS_OUT_OF_INDEXES); 89 | 90 | 91 | volatile long RunCount = 0; 92 | 93 | 94 | Assert::IsTrue(::FlsSetValue(Index, (void*)&RunCount)); 95 | 96 | Assert::IsTrue(::FlsFree(Index)); 97 | 98 | Assert::AreEqual((long)RunCount, 1l); 99 | } 100 | 101 | TEST_METHOD(线程退出销毁回调验证) 102 | { 103 | struct MyData 104 | { 105 | union 106 | { 107 | DWORD dwThreadId; 108 | DWORD Index; 109 | }; 110 | volatile long* pRunCount; 111 | }; 112 | 113 | auto Index = ::FlsAlloc([](void* pFlsData) 114 | { 115 | auto pData = (MyData*)pFlsData; 116 | 117 | Assert::AreEqual(GetCurrentThreadId(), pData->dwThreadId); 118 | 119 | InterlockedIncrement(pData->pRunCount); 120 | 121 | }); 122 | 123 | Assert::AreNotEqual(Index, FLS_OUT_OF_INDEXES); 124 | 125 | 126 | volatile long RunCount = 0; 127 | 128 | 129 | MyData Data; 130 | Data.Index = Index; 131 | Data.pRunCount = &RunCount; 132 | 133 | 134 | 135 | HANDLE hHandles[100]; 136 | 137 | for (auto& hHandle : hHandles) 138 | { 139 | hHandle = (HANDLE)_beginthreadex(nullptr, 0, [](void* pMyData) -> unsigned 140 | { 141 | auto& Data = *(MyData*)pMyData; 142 | 143 | Assert::AreEqual((long)::FlsGetValue(Data.Index), 0l); 144 | 145 | auto pFlsData = new MyData; 146 | 147 | pFlsData->dwThreadId = GetCurrentThreadId(); 148 | pFlsData->pRunCount = Data.pRunCount; 149 | 150 | Assert::IsTrue(::FlsSetValue(Data.Index, pFlsData)); 151 | 152 | Sleep(100); 153 | 154 | return 0; 155 | }, &Data, 0, nullptr); 156 | 157 | Assert::IsNotNull(hHandle); 158 | } 159 | 160 | 161 | for (auto hHandle : hHandles) 162 | { 163 | Assert::AreEqual(WaitForSingleObject(hHandle, 1000), (DWORD)WAIT_OBJECT_0); 164 | 165 | CloseHandle(hHandle); 166 | } 167 | 168 | 169 | Assert::AreEqual((long)RunCount, (long)_countof(hHandles)); 170 | 171 | 172 | Assert::IsTrue(::FlsFree(Index)); 173 | } 174 | 175 | 176 | 177 | }; 178 | } 179 | } 180 | 181 | -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/pch.h: -------------------------------------------------------------------------------- 1 | // pch.h: 这是预编译标头文件。 2 | // 下方列出的文件仅编译一次,提高了将来生成的生成性能。 3 | // 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。 4 | // 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。 5 | // 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。 6 | 7 | #ifndef PCH_H 8 | #define PCH_H 9 | 10 | #include 11 | 12 | // 添加要在此处预编译的标头 13 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 14 | #define UMDF_USING_NTSTATUS 15 | #define _Disallow_YY_KM_Namespace 16 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 1 17 | #include 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "CppUnitTest.h" 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | EXTERN_C uint64_t g_uSystemVersion; 31 | 32 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 33 | 34 | #define __DEFINE_THUNK(_MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) \ 35 | extern bool _CRT_CONCATENATE(aways_null_try_get_, _FUNCTION); \ 36 | EXTERN_C _RETURN_ _CONVENTION_ _FUNCTION(__VA_ARGS__); \ 37 | __if_not_exists(_FUNCTION) 38 | 39 | //#undef TEST_METHOD 40 | // 41 | //#define TEST_METHOD(methodName)\ 42 | // static const EXPORT_METHOD ::Microsoft::VisualStudio::CppUnitTestFramework::MemberMethodInfo* CALLING_CONVENTION CATNAME(__GetTestMethodInfo_, __COUNTER__)()\ 43 | // {\ 44 | // __GetTestClassInfo();\ 45 | // __GetTestVersion();\ 46 | // ALLOCATE_TESTDATA_SECTION_METHOD\ 47 | // static const ::Microsoft::VisualStudio::CppUnitTestFramework::MethodMetadata s_Metadata = {L"TestMethodInfo", L## #methodName, reinterpret_cast(__FUNCTION__), reinterpret_cast(__FUNCDNAME__), __WFILE__, __LINE__};\ 48 | //\ 49 | // static ::Microsoft::VisualStudio::CppUnitTestFramework::MemberMethodInfo s_Info = {::Microsoft::VisualStudio::CppUnitTestFramework::MemberMethodInfo::TestMethod, {NULL}, &s_Metadata};\ 50 | // s_Info.method.pVoidMethod = static_cast<::Microsoft::VisualStudio::CppUnitTestFramework::TestClassImpl::__voidFunc>(&ThisClass::methodName);\ 51 | // return &s_Info;\ 52 | // }\ 53 | // void methodName() 54 | 55 | 56 | class AwaysNullGuard 57 | { 58 | private: 59 | std::vector GuardAddress; 60 | 61 | public: 62 | 63 | ~AwaysNullGuard() 64 | { 65 | for (auto& _pValue : GuardAddress) 66 | { 67 | *_pValue = false; 68 | } 69 | } 70 | 71 | void Add(bool& _bValue) 72 | { 73 | if (_bValue) 74 | { 75 | // 已经是true 76 | return; 77 | } 78 | _bValue = true; 79 | GuardAddress.push_back(&_bValue); 80 | } 81 | 82 | void operator|=(bool& _bValue) 83 | { 84 | Add(_bValue); 85 | } 86 | }; 87 | 88 | inline std::string ToHexString(const void* _pData, size_t _cbData) 89 | { 90 | std::string _szResult; 91 | _szResult.reserve(_cbData * 2); 92 | constexpr const char kHex[] = "0123456789ABCDEF"; 93 | 94 | for (auto _pItem = reinterpret_cast(_pData); _cbData; --_cbData, ++_pItem) 95 | { 96 | _szResult += kHex[*_pItem >> 4]; 97 | _szResult += kHex[*_pItem & 0xFu]; 98 | } 99 | 100 | return _szResult; 101 | } 102 | 103 | inline std::string ToHexString(const std::vector _Data) 104 | { 105 | return ToHexString(_Data.data(), _Data.size()); 106 | } 107 | 108 | template 109 | inline std::string ToHexString(const BYTE (&_Data)[kDataLength]) 110 | { 111 | return ToHexString(_Data, kDataLength); 112 | } 113 | 114 | __forceinline constexpr uint64_t __fastcall MakeVersion(_In_ uint16_t _uMajor, _In_ uint16_t _uMinor, uint16_t _uBuild = 0, UINT16 _uRevision = 0) 115 | { 116 | uint64_t _uVersion = uint64_t(_uMajor) << 48; 117 | _uVersion |= uint64_t(_uMinor) << 32; 118 | _uVersion |= uint64_t(_uBuild) << 16; 119 | _uVersion |= _uRevision; 120 | return _uVersion; 121 | } 122 | 123 | std::string ReadFileData(LPCWSTR _szFilePath); 124 | 125 | namespace Microsoft::VisualStudio::CppUnitTestFramework 126 | { 127 | template<> 128 | inline std::wstring ToString(const GUID& t) 129 | { 130 | wchar_t _szResult[128] = {}; 131 | 132 | swprintf_s(_szResult, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", t.Data1, t.Data2, t.Data3, 133 | t.Data4[0], t.Data4[1], t.Data4[2], t.Data4[3], t.Data4[4], t.Data4[5], t.Data4[7], t.Data4[7]); 134 | 135 | return _szResult; 136 | } 137 | } 138 | 139 | #endif //PCH_H 140 | -------------------------------------------------------------------------------- /NuGet/build/net8.0-windows7.0/YY-Thunks.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | x64 9 | x86 10 | 5.02 11 | 5.01 12 | 13 | 14 | YY_Thunks_for_Win10.0.19041.obj 15 | YY_Thunks_for_Win10.0.10240.obj 16 | 17 | 18 | YY_Thunks_for_Win8.obj 19 | YY_Thunks_for_Win7.obj 20 | 21 | 22 | YY_Thunks_for_Win8.obj 23 | YY_Thunks_for_Win7.obj 24 | YY_Thunks_for_Vista.obj 25 | YY_Thunks_for_WinXP.obj 26 | 27 | $(YY_Thunks_File) 28 | 29 | YY_Thunks_for_WinXP.obj 30 | YY_Thunks_for_Win2K.obj 31 | 32 | 33 | $(LinkerSubsystem),$(YY_Thunks_LinkerSubsystemMinVersion) 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/Thunks/uxtheme.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6) 2 | #include 3 | #endif 4 | 5 | #if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_uxtheme) 6 | #define __Comment_Lib_uxtheme 7 | #pragma comment(lib, "UxTheme.lib") 8 | #endif 9 | 10 | #if defined(YY_Thunks_Implemented) && (YY_Thunks_Target < __WindowsNT6) 11 | namespace YY::Thunks::Fallback 12 | { 13 | static void* __fastcall try_get_DrawThemeTextEx(const ProcInfo& _ProcInfo) noexcept 14 | { 15 | auto _pProc = try_get_proc_address_from_dll(_ProcInfo); 16 | if (_pProc) 17 | return _pProc; 18 | 19 | static constexpr const ProcOffsetInfo kProcInfo[] = 20 | { 21 | #if defined(_X86_) 22 | { 0x3B901769ul, 0x5ADC5C2Ful - 0x5ADC0000ul }, // 6.0.2600.0 (Windows XP RTM) 23 | { 0x3D7D2609ul, 0x5ADC5AEDul - 0x5ADC0000ul }, // 6.0.2800.1106 (Windows XP SP1) 24 | { 0x4121457Aul, 0x5ADC645Cul - 0x5ADC0000ul }, // 6.0.2900.2180 (Windows XP SP2) 25 | { 0x4802BDC0ul, 0x5ADC2FF8ul - 0x5ADC0000ul }, // 6.0.2900.5512 (Windows XP SP3) 26 | { 0x3E8024BEul, 0x71B8ACA0ul - 0x71B70000ul }, // 6.0.3790.0 (Windows 2003) 27 | { 0x42437794ul, 0x7DF64466ul - 0x7DF50000ul }, // 6.0.3790.1830 (Windows 2003 SP1) 28 | { 0x45D70ACBul, 0x71B91D41ul - 0x71B70000ul }, // 6.0.3790.3959 (Windows 2003 SP2) 29 | #elif defined(_AMD64_) 30 | { 0x42438B57ul, 0x7FF77069A60ull - 0x7FF77060000ull }, // 6.0.3790.1830 (Windows 2003 SP1) 31 | { 0x45D6CCAEul, 0x000007FF77239A70ull - 0x7FF77230000ull }, // 6.0.3790.3959 (Windows 2003 SP2) 32 | #endif 33 | }; 34 | 35 | __WarningMessage__("try_get_DrawThemeTextEx 可能遗漏某些XP/2003补丁中的uxtheme.dll,如果你知道详细可以提交PR。"); 36 | return try_get_proc_address_from_offset(try_get_module_uxtheme(), kProcInfo); 37 | } 38 | } 39 | #endif 40 | 41 | 42 | namespace YY::Thunks 43 | { 44 | #if (YY_Thunks_Target < __WindowsNT6) 45 | 46 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 47 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 48 | __DEFINE_THUNK( 49 | uxtheme, 50 | 36, 51 | HRESULT, 52 | WINAPI, 53 | DrawThemeTextEx, 54 | _In_ HTHEME hTheme, 55 | _In_ HDC hdc, 56 | _In_ int iPartId, 57 | _In_ int iStateId, 58 | _In_reads_(cchText) LPCWSTR pszText, 59 | _In_ int cchText, 60 | _In_ DWORD dwTextFlags, 61 | _Inout_ LPRECT pRect, 62 | _In_opt_ const DTTOPTS *pOptions 63 | ) 64 | { 65 | if (const auto _pfnDrawThemeTextEx = try_get_DrawThemeTextEx()) 66 | { 67 | return _pfnDrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, pRect, pOptions); 68 | } 69 | 70 | return DrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, 0, pRect); 71 | } 72 | #endif 73 | 74 | 75 | #if (YY_Thunks_Target < __WindowsNT6) 76 | 77 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 78 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 79 | __DEFINE_THUNK( 80 | uxtheme, 81 | 24, 82 | HRESULT, 83 | WINAPI, 84 | GetThemeTransitionDuration, 85 | _In_ HTHEME hTheme, 86 | _In_ int iPartId, 87 | _In_ int iStateIdFrom, 88 | _In_ int iStateIdTo, 89 | _In_ int iPropId, 90 | _Out_ DWORD *pdwDuration 91 | ) 92 | { 93 | if (const auto _pfnGetThemeTransitionDuration = try_get_GetThemeTransitionDuration()) 94 | { 95 | return _pfnGetThemeTransitionDuration(hTheme, iPartId, iStateIdFrom, iStateIdTo, iPropId, pdwDuration); 96 | } 97 | 98 | if (pdwDuration == nullptr || iStateIdFrom <= 0 || iStateIdTo <= 0) 99 | { 100 | return E_INVALIDARG; 101 | } 102 | 103 | *pdwDuration = 0; 104 | return E_NOTIMPL; 105 | } 106 | #endif 107 | 108 | 109 | #if (YY_Thunks_Target < __WindowsNT6) 110 | 111 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 112 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 113 | __DEFINE_THUNK( 114 | uxtheme, 115 | 16, 116 | HRESULT, 117 | WINAPI, 118 | SetWindowThemeAttribute, 119 | _In_ HWND hwnd, 120 | _In_ enum WINDOWTHEMEATTRIBUTETYPE eAttribute, 121 | _In_reads_bytes_(cbAttribute) PVOID pvAttribute, 122 | _In_ DWORD cbAttribute 123 | ) 124 | { 125 | if (const auto _pfnSetWindowThemeAttribute = try_get_SetWindowThemeAttribute()) 126 | { 127 | return _pfnSetWindowThemeAttribute(hwnd, eAttribute, pvAttribute, cbAttribute); 128 | } 129 | 130 | return E_NOTIMPL; 131 | } 132 | #endif 133 | } 134 | -------------------------------------------------------------------------------- /src/Thunks/ext-ms-win-ntuser-powermanagement.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6_2) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #ifndef CONST_DEVICE_NOTIFY_WINDOW_HANDLE 8 | #define CONST_DEVICE_NOTIFY_WINDOW_HANDLE (HPOWERNOTIFY)0x1001 9 | #endif 10 | 11 | #if (YY_Thunks_Target < __WindowsNT6_2) 12 | 13 | // Windows 8 [仅限桌面应用],Windows Server 2012 [仅限桌面应用] 14 | __DEFINE_THUNK( 15 | user32, 16 | 8, 17 | HPOWERNOTIFY, 18 | WINAPI, 19 | RegisterSuspendResumeNotification, 20 | IN HANDLE _hRecipient, 21 | IN DWORD _fFlags 22 | ) 23 | { 24 | if (const auto _pfnRegisterSuspendResumeNotification = try_get_RegisterSuspendResumeNotification()) 25 | { 26 | return _pfnRegisterSuspendResumeNotification(_hRecipient, _fFlags); 27 | } 28 | 29 | if (DEVICE_NOTIFY_CALLBACK == _fFlags) 30 | { 31 | HPOWERNOTIFY _hRegistrationHandle = nullptr; 32 | 33 | auto _lStatus = PowerRegisterSuspendResumeNotificationDownlevel(DEVICE_NOTIFY_CALLBACK, _hRecipient, &_hRegistrationHandle); 34 | if (_lStatus == ERROR_SUCCESS) 35 | { 36 | return _hRegistrationHandle; 37 | } 38 | else 39 | { 40 | SetLastError(_lStatus); 41 | return nullptr; 42 | } 43 | } 44 | else if (DEVICE_NOTIFY_WINDOW_HANDLE == _fFlags) 45 | { 46 | // 这种情况需要向窗口发送电源通知,但是老版本系统不支持 现代化睡眠 47 | // 本身就是可以正确处理这种情况的。所以我们忽略参数,直接返回一个标记常量即可。 48 | UNREFERENCED_PARAMETER(_hRecipient); 49 | 50 | return CONST_DEVICE_NOTIFY_WINDOW_HANDLE; 51 | } 52 | else 53 | { 54 | // 仅支持这二个参数 55 | SetLastError(ERROR_INVALID_PARAMETER); 56 | return nullptr; 57 | } 58 | } 59 | #endif 60 | 61 | #if (YY_Thunks_Target < __WindowsNT6_2) 62 | 63 | // Windows 8 [仅限桌面应用],Windows Server 2012 [仅限桌面应用] 64 | __DEFINE_THUNK( 65 | user32, 66 | 4, 67 | BOOL, 68 | WINAPI, 69 | UnregisterSuspendResumeNotification, 70 | IN HPOWERNOTIFY _hHandle 71 | ) 72 | { 73 | if (const auto _pfnUnregisterSuspendResumeNotification = try_get_UnregisterSuspendResumeNotification()) 74 | { 75 | return _pfnUnregisterSuspendResumeNotification(_hHandle); 76 | } 77 | 78 | if (_hHandle == nullptr) 79 | { 80 | SetLastError(ERROR_INVALID_PARAMETER); 81 | return FALSE; 82 | } 83 | else if (_hHandle == CONST_DEVICE_NOTIFY_WINDOW_HANDLE) 84 | { 85 | // 忽略,这是 DEVICE_NOTIFY_WINDOW_HANDLE 的常量 86 | return TRUE; 87 | } 88 | else 89 | { 90 | // 来自 DEVICE_NOTIFY_CALLBACK的注册 91 | auto _lStatus = PowerUnregisterSuspendResumeNotificationDownlevel(_hHandle); 92 | if (_lStatus == ERROR_SUCCESS) 93 | { 94 | return TRUE; 95 | } 96 | else 97 | { 98 | SetLastError(_lStatus); 99 | return FALSE; 100 | } 101 | } 102 | } 103 | #endif 104 | 105 | 106 | #if (YY_Thunks_Target < __WindowsNT6) 107 | 108 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 109 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 110 | __DEFINE_THUNK( 111 | user32, 112 | 12, 113 | HPOWERNOTIFY, 114 | WINAPI, 115 | RegisterPowerSettingNotification, 116 | IN HANDLE hRecipient, 117 | IN LPCGUID PowerSettingGuid, 118 | IN DWORD Flags 119 | ) 120 | { 121 | if (const auto _pfnRegisterPowerSettingNotification = try_get_RegisterPowerSettingNotification()) 122 | { 123 | return _pfnRegisterPowerSettingNotification(hRecipient, PowerSettingGuid, Flags); 124 | } 125 | 126 | return reinterpret_cast(5); 127 | } 128 | #endif 129 | 130 | 131 | #if (YY_Thunks_Target < __WindowsNT6) 132 | 133 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 134 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 135 | __DEFINE_THUNK( 136 | user32, 137 | 4, 138 | BOOL, 139 | WINAPI, 140 | UnregisterPowerSettingNotification, 141 | IN HPOWERNOTIFY Handle 142 | ) 143 | { 144 | if (const auto _pfnUnregisterPowerSettingNotification = try_get_UnregisterPowerSettingNotification()) 145 | { 146 | return _pfnUnregisterPowerSettingNotification(Handle); 147 | } 148 | 149 | if (Handle == reinterpret_cast(5)) 150 | { 151 | return TRUE; 152 | } 153 | 154 | SetLastError(ERROR_INVALID_HANDLE); 155 | return FALSE; 156 | } 157 | #endif 158 | } 159 | -------------------------------------------------------------------------------- /src/Thunks/api-ms-win-core-interlocked.hpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | namespace YY::Thunks 4 | { 5 | #if (YY_Thunks_Target < __WindowsNT5_2) 6 | 7 | #pragma push_macro("InterlockedCompareExchange64") 8 | #undef InterlockedCompareExchange64 9 | 10 | //Windows Vista [desktop apps | UWP apps] 11 | //Windows Server 2003 [desktop apps | UWP apps] 12 | __DEFINE_THUNK( 13 | kernel32, 14 | 20, 15 | LONG64, 16 | WINAPI, 17 | InterlockedCompareExchange64, 18 | _Inout_ _Interlocked_operand_ LONG64 volatile *Destination, 19 | _In_ LONG64 ExChange, 20 | _In_ LONG64 Comperand 21 | ) 22 | { 23 | return _InterlockedCompareExchange64(Destination, ExChange, Comperand); 24 | } 25 | #pragma pop_macro("InterlockedCompareExchange64") 26 | 27 | #endif 28 | 29 | 30 | #if (YY_Thunks_Target < __WindowsNT5_1) 31 | 32 | //Windows XP [desktop apps | UWP apps] 33 | //Windows Server 2003 [desktop apps | UWP apps] 34 | __DEFINE_THUNK( 35 | kernel32, 36 | 4, 37 | VOID, 38 | WINAPI, 39 | InitializeSListHead, 40 | _Out_ PSLIST_HEADER ListHead 41 | ) 42 | { 43 | *ListHead = SLIST_HEADER{}; 44 | } 45 | #endif 46 | 47 | 48 | #if (YY_Thunks_Target < __WindowsNT5_1) 49 | 50 | //Windows XP [desktop apps | UWP apps] 51 | //Windows Server 2003 [desktop apps | UWP apps] 52 | __DEFINE_THUNK( 53 | kernel32, 54 | 4, 55 | PSLIST_ENTRY, 56 | WINAPI, 57 | InterlockedFlushSList, 58 | _Inout_ PSLIST_HEADER ListHead 59 | ) 60 | { 61 | if (const auto pInterlockedFlushSList = try_get_InterlockedFlushSList()) 62 | { 63 | return pInterlockedFlushSList(ListHead); 64 | } 65 | 66 | __asm 67 | { 68 | mov ebp, [ListHead] 69 | xor ebx, ebx 70 | mov edx, [ebp + 4] 71 | mov eax, [ebp + 0] 72 | 73 | _Loop: 74 | or eax, eax 75 | jz _End 76 | mov ecx, edx 77 | mov cx, bx 78 | lock cmpxchg8b qword ptr[ebp] 79 | jnz _Loop 80 | _End: 81 | } 82 | 83 | //直接返回eax即可。 84 | } 85 | #endif 86 | 87 | 88 | #if (YY_Thunks_Target < __WindowsNT5_1) 89 | 90 | //Windows XP [desktop apps | UWP apps] 91 | //Windows Server 2003 [desktop apps | UWP apps] 92 | __DEFINE_THUNK( 93 | kernel32, 94 | 4, 95 | USHORT, 96 | WINAPI, 97 | QueryDepthSList, 98 | _In_ PSLIST_HEADER ListHead 99 | ) 100 | { 101 | if (const auto pQueryDepthSList = try_get_QueryDepthSList()) 102 | { 103 | return pQueryDepthSList(ListHead); 104 | } 105 | 106 | return ListHead->Depth; 107 | } 108 | #endif 109 | 110 | 111 | #if (YY_Thunks_Target < __WindowsNT5_1) 112 | 113 | //Windows XP [desktop apps | UWP apps] 114 | //Windows Server 2003 [desktop apps | UWP apps] 115 | __DEFINE_THUNK( 116 | kernel32, 117 | 8, 118 | PSLIST_ENTRY, 119 | WINAPI, 120 | InterlockedPushEntrySList, 121 | _Inout_ PSLIST_HEADER ListHead, 122 | _Inout_ __drv_aliasesMem PSLIST_ENTRY ListEntry 123 | ) 124 | { 125 | if (const auto pInterlockedPushEntrySList = try_get_InterlockedPushEntrySList()) 126 | { 127 | return pInterlockedPushEntrySList(ListHead, ListEntry); 128 | } 129 | 130 | __asm 131 | { 132 | mov ebx, [ListEntry] 133 | mov ebp, [ListHead] 134 | 135 | mov edx, [ebp + 4] 136 | mov eax, [ebp + 0] 137 | 138 | _Loop: 139 | mov [ebx], eax 140 | lea ecx, [edx + 10001h] 141 | lock cmpxchg8b qword ptr [ebp] 142 | jnz _Loop 143 | } 144 | 145 | //asm会更新eax 146 | } 147 | #endif 148 | 149 | 150 | #if (YY_Thunks_Target < __WindowsNT5_1) 151 | 152 | //Windows XP [desktop apps | UWP apps] 153 | //Windows Server 2003 [desktop apps | UWP apps] 154 | __DEFINE_THUNK( 155 | kernel32, 156 | 4, 157 | PSLIST_ENTRY, 158 | WINAPI, 159 | InterlockedPopEntrySList, 160 | _Inout_ PSLIST_HEADER ListHead 161 | ) 162 | { 163 | if (const auto pInterlockedPopEntrySList = try_get_InterlockedPopEntrySList()) 164 | { 165 | return pInterlockedPopEntrySList(ListHead); 166 | } 167 | 168 | __asm 169 | { 170 | mov ebp, [ListHead] 171 | mov edx, [ebp + 4] 172 | mov eax, [ebp + 0] 173 | _Loop: 174 | or eax, eax 175 | jz _End 176 | lea ecx, [edx-1] 177 | mov ebx, [eax] 178 | lock cmpxchg8b qword ptr [ebp] 179 | jnz _Loop 180 | _End: 181 | 182 | } 183 | 184 | //asm 会修改eax 185 | } 186 | #endif 187 | } //namespace YY::Thunks 188 | -------------------------------------------------------------------------------- /src/MinimumRequiredVersionHelper/MinimumRequiredVersionHelper.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int __cdecl wmain(int argc, wchar_t* argv[]) 12 | { 13 | _tsetlocale(0, _T(".936")); 14 | 15 | if (argc != 3) 16 | { 17 | return ERROR_INVALID_PARAMETER; 18 | } 19 | 20 | auto szMinimumRequiredVersion = argv[2]; 21 | 22 | if (_wcsnicmp(szMinimumRequiredVersion, L"/MinimumRequiredVersion:", _countof(L"/MinimumRequiredVersion:") -1) == 0) 23 | { 24 | szMinimumRequiredVersion += _countof(L"/MinimumRequiredVersion:") - 1; 25 | } 26 | else 27 | { 28 | wprintf(L"无法识别参数:%ws。\n", szMinimumRequiredVersion); 29 | 30 | return ERROR_INVALID_PARAMETER; 31 | } 32 | 33 | UINT16 MinimumRequiredVersion[2] = { }; 34 | 35 | if (swscanf(szMinimumRequiredVersion, L"%hu.%hu", MinimumRequiredVersion + 1, MinimumRequiredVersion + 0) != 2) 36 | { 37 | wprintf(L"无法识别MinimumRequiredVersion:%ws。\n", szMinimumRequiredVersion); 38 | return ERROR_INVALID_PARAMETER; 39 | } 40 | 41 | 42 | LSTATUS lStatus = ERROR_SUCCESS; 43 | auto szFilePath = argv[1]; 44 | 45 | auto hFile = CreateFileW(szFilePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); 46 | if (hFile == INVALID_HANDLE_VALUE) 47 | { 48 | lStatus = GetLastError(); 49 | 50 | wprintf(L"%ws 无法打开,错误代码:%u。\n", szFilePath, lStatus); 51 | return ERROR_SUCCESS; 52 | } 53 | 54 | do 55 | { 56 | DWORD cbRead; 57 | IMAGE_DOS_HEADER DosHeader; 58 | 59 | IMAGE_NT_HEADERS32 Header32; 60 | 61 | if (ReadFile(hFile, &DosHeader, sizeof(DosHeader), &cbRead, nullptr) == FALSE) 62 | { 63 | lStatus = GetLastError(); 64 | 65 | wprintf(L"%ws 无法访问,错误代码:%u。\n", szFilePath, lStatus); 66 | break; 67 | } 68 | 69 | if (cbRead != sizeof(DosHeader) || DosHeader.e_magic != IMAGE_DOS_SIGNATURE) 70 | { 71 | lStatus = ERROR_BAD_FORMAT; 72 | wprintf(L"%ws 不是有效的PE文件。\n", szFilePath); 73 | break; 74 | } 75 | 76 | SetFilePointer(hFile, DosHeader.e_lfanew, nullptr, FILE_BEGIN); 77 | 78 | if (ReadFile(hFile, &Header32, sizeof(Header32), &cbRead, nullptr) == FALSE) 79 | { 80 | lStatus = GetLastError(); 81 | 82 | wprintf(L"%ws 无法访问,错误代码:%u。\n", szFilePath, lStatus); 83 | break; 84 | } 85 | 86 | if (cbRead != sizeof(Header32) || Header32.Signature != IMAGE_NT_SIGNATURE) 87 | { 88 | lStatus = ERROR_BAD_FORMAT; 89 | wprintf(L"%ws 不是有效的PE文件。\n", szFilePath); 90 | break; 91 | } 92 | 93 | if (Header32.FileHeader.Machine != IMAGE_FILE_MACHINE_I386 94 | || UFIELD_OFFSET(decltype(Header32.OptionalHeader), DataDirectory) > Header32.OptionalHeader.SizeOfHeaders) 95 | { 96 | wprintf(L"%ws 不是i386 PE文件,无需更新。\n", szFilePath); 97 | break; 98 | } 99 | 100 | if (Header32.OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI && Header32.OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI) 101 | { 102 | wprintf(L"%ws 不是GUI 或者 GUI PE文件,无需更新。\n", szFilePath); 103 | break; 104 | } 105 | 106 | 107 | #define MakeMiniVersion(v1,v2) (DWORD)(v2|(v1<<16)) 108 | 109 | bool bNeedUpdate = false; 110 | 111 | if (MakeMiniVersion(Header32.OptionalHeader.MajorOperatingSystemVersion, Header32.OptionalHeader.MinorOperatingSystemVersion) > *(DWORD*)MinimumRequiredVersion) 112 | { 113 | Header32.OptionalHeader.MajorOperatingSystemVersion = MinimumRequiredVersion[1]; 114 | Header32.OptionalHeader.MinorOperatingSystemVersion = MinimumRequiredVersion[0]; 115 | bNeedUpdate = true; 116 | } 117 | 118 | if (MakeMiniVersion(Header32.OptionalHeader.MajorSubsystemVersion, Header32.OptionalHeader.MinorSubsystemVersion) > *(DWORD*)MinimumRequiredVersion) 119 | { 120 | Header32.OptionalHeader.MajorSubsystemVersion = MinimumRequiredVersion[1]; 121 | Header32.OptionalHeader.MinorSubsystemVersion = MinimumRequiredVersion[0]; 122 | bNeedUpdate = true; 123 | } 124 | 125 | if (!bNeedUpdate) 126 | { 127 | wprintf(L"%ws 最低系统版本无需更新。\n", szFilePath); 128 | break; 129 | } 130 | 131 | auto hFileWriter = ReOpenFile(hFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0); 132 | 133 | if (hFileWriter == INVALID_HANDLE_VALUE) 134 | { 135 | lStatus = GetLastError(); 136 | 137 | wprintf(L"%ws 无法更新,错误代码:%u。\n", szFilePath, lStatus); 138 | break; 139 | } 140 | 141 | SetFilePointer(hFileWriter, DosHeader.e_lfanew + UFIELD_OFFSET(decltype(Header32), OptionalHeader), nullptr, FILE_BEGIN); 142 | 143 | auto& cbWriter = cbRead; 144 | if (WriteFile(hFileWriter, &Header32.OptionalHeader, UFIELD_OFFSET(decltype(Header32.OptionalHeader), DataDirectory), &cbWriter, nullptr)) 145 | { 146 | wprintf(L"%ws 最低支持版本成功更新到 %hu.%hu!\n", szFilePath, MinimumRequiredVersion[1], MinimumRequiredVersion[0]); 147 | } 148 | else 149 | { 150 | lStatus = GetLastError(); 151 | 152 | wprintf(L"%ws 无法更新,错误代码:%u。\n", szFilePath, lStatus); 153 | } 154 | 155 | CloseHandle(hFileWriter); 156 | 157 | } while (false); 158 | 159 | 160 | CloseHandle(hFile); 161 | 162 | return ERROR_SUCCESS; 163 | } 164 | -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/api-ms-win-appmodel-runtime.UnitTest.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Thunks/api-ms-win-appmodel-runtime.hpp" 3 | 4 | #include 5 | #include 6 | 7 | namespace api_ms_win_appmodel_runtime 8 | { 9 | struct PackageInfo 10 | { 11 | CStringW szPackageFullName; 12 | UINT32 uPackagePropertiy; 13 | 14 | bool operator==(const PackageInfo& _oOther) const 15 | { 16 | return szPackageFullName == _oOther.szPackageFullName && uPackagePropertiy == _oOther.uPackagePropertiy; 17 | } 18 | }; 19 | 20 | void AreEqual(const std::vector& _oLeft, const std::vector& _Right, CStringW _szMessage) 21 | { 22 | Assert::AreEqual(_oLeft.size(), _Right.size(), _szMessage); 23 | 24 | for (auto& _Item : _oLeft) 25 | { 26 | Assert::IsTrue(std::find(_Right.begin(), _Right.end(), _Item) != _Right.end(), _szMessage + _Item.szPackageFullName); 27 | } 28 | } 29 | 30 | static std::vector __fastcall FindPackagesByPackageFamilyHelper(_In_ PCWSTR packageFamilyName, _In_ UINT32 packageFilters) 31 | { 32 | std::vector _Result; 33 | CStringW _szBuffer; 34 | std::vector _szNames; 35 | UINT32 _uCount = 0; 36 | UINT32 _cchBuffer = 0; 37 | auto _lStatus = ::FindPackagesByPackageFamily(packageFamilyName, packageFilters, &_uCount, nullptr, &_cchBuffer, nullptr, nullptr); 38 | if (_lStatus != ERROR_INSUFFICIENT_BUFFER) 39 | return _Result; 40 | 41 | std::vector _PackageProperties; 42 | _szNames.resize(_uCount); 43 | _PackageProperties.resize(_uCount); 44 | _lStatus = ::FindPackagesByPackageFamily(packageFamilyName, packageFilters, &_uCount, _szNames.data(), &_cchBuffer, _szBuffer.GetBuffer(_cchBuffer), _PackageProperties.data()); 45 | if (_lStatus != ERROR_SUCCESS) 46 | return _Result; 47 | 48 | _Result.resize(_uCount); 49 | 50 | for (UINT32 i = 0; i != _uCount; ++i) 51 | { 52 | _Result[i].szPackageFullName = _szNames[i]; 53 | _Result[i].uPackagePropertiy = _PackageProperties[i]; 54 | } 55 | 56 | return _Result; 57 | } 58 | 59 | TEST_CLASS(GetPackagePathByFullName) 60 | { 61 | public: 62 | GetPackagePathByFullName() 63 | { 64 | } 65 | 66 | TEST_METHOD(常规) 67 | { 68 | for (auto& _Pacakge : FindPackagesByPackageFamilyHelper(L"Microsoft.WindowsNotepad_8wekyb3d8bbwe", PACKAGE_FILTER_HEAD | PACKAGE_FILTER_DIRECT)) 69 | { 70 | wchar_t _szPath1[MAX_PATH] = {}; 71 | UINT32 _cchPathLength1 = _countof(_szPath1); 72 | ::GetPackagePathByFullName(_Pacakge.szPackageFullName, &_cchPathLength1, _szPath1); 73 | 74 | AwaysNullGuard Guard; 75 | Guard |= YY::Thunks::aways_null_try_get_GetPackagePathByFullName; 76 | 77 | wchar_t _szPath2[MAX_PATH] = {}; 78 | UINT32 _cchPathLength2 = _countof(_szPath2); 79 | ::GetPackagePathByFullName(_Pacakge.szPackageFullName, &_cchPathLength2, _szPath2); 80 | 81 | Assert::AreEqual(_cchPathLength1, _cchPathLength1, _Pacakge.szPackageFullName); 82 | Assert::AreEqual(_szPath1, _szPath2, _Pacakge.szPackageFullName); 83 | } 84 | } 85 | }; 86 | 87 | TEST_CLASS(FindPackagesByPackageFamily) 88 | { 89 | public: 90 | FindPackagesByPackageFamily() 91 | { 92 | } 93 | TEST_METHOD(常规) 94 | { 95 | constexpr UINT32 kPackageFilters[] = 96 | { 97 | 0, 98 | PACKAGE_FILTER_HEAD | PACKAGE_FILTER_DIRECT, 99 | PACKAGE_FILTER_HEAD, 100 | PACKAGE_FILTER_DIRECT, 101 | PACKAGE_FILTER_RESOURCE, 102 | PACKAGE_FILTER_RESOURCE | PACKAGE_FILTER_DIRECT | PACKAGE_FILTER_HEAD, 103 | PACKAGE_FILTER_RESOURCE | PACKAGE_FILTER_HEAD, 104 | // PACKAGE_FILTER_BUNDLE, 改单元测试无法通过 105 | }; 106 | 107 | for(auto _uFilters: kPackageFilters) 108 | { 109 | const auto _szSystem = FindPackagesByPackageFamilyHelper(L"Microsoft.WindowsNotepad_8wekyb3d8bbwe", _uFilters); 110 | AwaysNullGuard Guard; 111 | Guard |= YY::Thunks::aways_null_try_get_FindPackagesByPackageFamily; 112 | const auto _szThunks = FindPackagesByPackageFamilyHelper(L"Microsoft.WindowsNotepad_8wekyb3d8bbwe", _uFilters); 113 | 114 | CStringW _szPackageFilter; 115 | _szPackageFilter.Format(L"PackageFilter = 0x%X, ", _uFilters); 116 | AreEqual(_szSystem, _szThunks, _szPackageFilter); 117 | } 118 | } 119 | }; 120 | } 121 | -------------------------------------------------------------------------------- /src/Shared/SharedDefs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #define YY_APPLY_ENUM_CALSS_BIT_OPERATOR(_ENUM) \ 5 | inline constexpr _ENUM& operator|=(_ENUM& _eLeft, _ENUM _eRight) \ 6 | { \ 7 | using _Type = std::underlying_type<_ENUM>::type; \ 8 | (_Type&)_eLeft |= (_Type)_eRight; \ 9 | return _eLeft; \ 10 | } \ 11 | \ 12 | inline constexpr _ENUM operator|(_ENUM _eLeft, _ENUM _eRight) \ 13 | { \ 14 | using _Type = std::underlying_type<_ENUM>::type; \ 15 | auto _Result = (_Type)_eLeft | (_Type)_eRight; \ 16 | return _ENUM(_Result); \ 17 | } \ 18 | \ 19 | inline constexpr _ENUM operator&(_ENUM _eLeft, _ENUM _eRight) \ 20 | { \ 21 | using _Type = std::underlying_type<_ENUM>::type; \ 22 | return _ENUM((_Type)_eLeft & (_Type)_eRight); \ 23 | } \ 24 | \ 25 | inline constexpr _ENUM operator~(_ENUM _eLeft) \ 26 | { \ 27 | using _Type = std::underlying_type<_ENUM>::type; \ 28 | return _ENUM(~(_Type)_eLeft); \ 29 | } \ 30 | \ 31 | inline constexpr bool HasFlags(_ENUM _eLeft, _ENUM _eRight) \ 32 | { \ 33 | using _Type = std::underlying_type<_ENUM>::type; \ 34 | return (_Type)_eLeft & (_Type)_eRight; \ 35 | } 36 | 37 | #define __Version(Major, Minor, Build, Revision) (Major * 0x1000000000000ull + Minor * 0x100000000ull + Build * 0x10000ull + Revision) 38 | 39 | // 版本号参考来源: 40 | // https://github.com/MouriNaruto/MouriDocs/tree/main/docs/18 41 | 42 | // Windows 2000 RTM x86 43 | #define __WindowsNT5 __Version(5, 0, 2195, 0) 44 | 45 | // Windows XP RTM x86 46 | #define __WindowsNT5_1 __Version(5, 1, 2600, 0) 47 | 48 | #define __WindowsNT5_1_SP1 __Version(5, 1, 2600, 1106) 49 | 50 | #define __WindowsNT5_1_SP2 __Version(5, 1, 2600, 2180) 51 | 52 | #define __WindowsNT5_1_SP3 __Version(5, 1, 2600, 5512) 53 | 54 | // Windows 2003 RTM x86 55 | #define __WindowsNT5_2 __Version(5, 2, 3790, 0) 56 | 57 | // Windows XP RTM x64,Windows 2003 SP1 58 | #define __WindowsNT5_2_SP1 __Version(5, 2, 3790, 1830) 59 | 60 | // Windows Vista RTM 61 | #define __WindowsNT6 __Version(6, 0, 6000, 0) 62 | 63 | // Windows Vista SP1、Windows Server 2008 RTM 64 | #define __WindowsNT6_SP1 __Version(6, 0, 6001, 0) 65 | 66 | #define __WindowsNT6_SP2 __Version(6, 0, 6002, 0) 67 | 68 | // Windows 7 RTM, Windows Server 2008 R2 RTM 69 | #define __WindowsNT6_1 __Version(6, 1, 7600, 0) 70 | 71 | #define __WindowsNT6_1_SP1 __Version(6, 1, 7601, 0) 72 | 73 | // Windows 8 RTM, Windows Server 2012 RTM 74 | #define __WindowsNT6_2 __Version(6, 2, 9200, 0) 75 | 76 | // Windows 8.1 RTM, Windows Server 2012 R2 RTM 77 | #define __WindowsNT6_3 __Version(6, 3, 9600, 0) 78 | 79 | // Windows 10 1507 80 | #define __WindowsNT10_10240 __Version(10, 0, 10240, 0) 81 | 82 | // Windows 10 1607(RS1) 83 | #define __WindowsNT10_14393 __Version(10, 0, 14393, 0) 84 | 85 | // Windows 10 1703(RS2) 86 | #define __WindowsNT10_15063 __Version(10, 0, 15063, 0) 87 | 88 | // Windows 10 1709(RS3),注意ARM64从这个版本开始才支持。 89 | #define __WindowsNT10_16299 __Version(10, 0, 16299, 0) 90 | 91 | // Windows 10 1803(RS4) 92 | #define __WindowsNT10_17134 __Version(10, 0, 17134, 0) 93 | 94 | // Windows 10 2004(VB) 95 | #define __WindowsNT10_19041 __Version(10, 0, 19041, 0) 96 | 97 | // Windows Server 2022(FE) 98 | #define __WindowsNT10_20348 __Version(10, 0, 20348, 0) 99 | 100 | // Windows 11 24H2、Windows Server 2025 101 | #define __WindowsNT10_26100 __Version(10, 0, 26100, 0) 102 | 103 | #if defined(_M_IX86) 104 | #define __WindowsMinTarget __WindowsNT5 105 | #elif defined(_M_AMD64) 106 | #define __WindowsMinTarget __WindowsNT5_2_SP1 107 | #elif defined(_M_ARM) 108 | #define __WindowsMinTarget __WindowsNT6_2 109 | #elif defined(_M_ARM64) 110 | #define __WindowsMinTarget __WindowsNT10_16299 111 | #endif 112 | 113 | #ifndef YY_Thunks_Target 114 | #define YY_Thunks_Target __WindowsMinTarget 115 | #endif 116 | 117 | // 输错了版本号? 118 | #if YY_Thunks_Target < __WindowsMinTarget 119 | #undef YY_Thunks_Target 120 | #define YY_Thunks_Target __WindowsMinTarget 121 | #endif 122 | 123 | #if defined(_M_IX86) 124 | // __ftoul2_legacy v143新增 125 | #pragma comment(linker, "/alternatename:__ftoul2_legacy=__ftol2") 126 | #endif 127 | -------------------------------------------------------------------------------- /src/Thunks/shlwapi.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT5_1) 2 | #include 3 | #endif 4 | 5 | #ifdef YY_Thunks_Implemented 6 | namespace YY::Thunks::internal 7 | { 8 | namespace 9 | { 10 | template 11 | static 12 | _Success_(return) 13 | BOOL 14 | WINAPI 15 | StrToInt64ExT( 16 | _In_ const Char* pszString, 17 | _In_ STIF_FLAGS dwFlags, 18 | _Out_ LONGLONG* pllRet 19 | ) 20 | { 21 | if (!pszString) 22 | return FALSE; 23 | 24 | 25 | for (; ; ++pszString) 26 | { 27 | const auto ch = *pszString; 28 | 29 | if (ch == Char(' ') || ch == Char('\n') || ch == Char('\t')) 30 | { 31 | continue; 32 | } 33 | 34 | break; 35 | } 36 | 37 | bool Sign = true; 38 | if (*pszString == Char('+')) 39 | { 40 | ++pszString; 41 | } 42 | else if (*pszString == Char('-')) 43 | { 44 | ++pszString; 45 | Sign = false; 46 | } 47 | 48 | ULONGLONG result = 0; 49 | 50 | if (dwFlags & STIF_SUPPORT_HEX) 51 | { 52 | //二种形式0x????, 0X????? 53 | if (*pszString == Char('0') && (pszString[1] == Char('x') || pszString[1] == Char('X'))) 54 | { 55 | pszString += 2; 56 | 57 | for (auto String = pszString; ; ++String) 58 | { 59 | const auto ch = *String; 60 | if (ch >= Char('0') && ch <= Char('9')) 61 | { 62 | result = (result << 4) | ((ULONGLONG)ch - Char('0')); 63 | } 64 | else if (ch >= Char('a') && ch <= Char('f')) 65 | { 66 | result = (result << 4) | ((ULONGLONG)ch - Char('a') + 10); 67 | } 68 | else if (ch >= Char('A') && ch <= Char('F')) 69 | { 70 | result = (result << 4) | ((ULONGLONG)ch - Char('A') + 10); 71 | } 72 | else 73 | { 74 | if (String == pszString) 75 | { 76 | return FALSE; 77 | } 78 | 79 | if (pllRet) 80 | { 81 | *pllRet = result; 82 | } 83 | 84 | return TRUE; 85 | } 86 | } 87 | } 88 | } 89 | 90 | for (auto String = pszString; ; ++String) 91 | { 92 | const auto ch = *String; 93 | if (ch >= Char('0') && ch <= ('9')) 94 | { 95 | result = (result * 10) + ((ULONGLONG)ch - Char('0')); 96 | } 97 | else 98 | { 99 | if (String == pszString) 100 | { 101 | return FALSE; 102 | } 103 | 104 | if (pllRet) 105 | { 106 | if (!Sign) 107 | { 108 | result = ~result + 1; 109 | } 110 | 111 | *pllRet = result; 112 | } 113 | 114 | return TRUE; 115 | } 116 | } 117 | 118 | return FALSE; 119 | } 120 | } 121 | } 122 | #endif 123 | 124 | 125 | namespace YY::Thunks 126 | { 127 | #if (YY_Thunks_Target < __WindowsNT5_1) 128 | 129 | // Windows 2000 Professional, Windows XP [desktop apps only] 130 | // Windows 2000 Server [desktop apps only] 131 | // 虽然Windows 2000支持,但是在IE6里面而IE6不一定所有Windows 2000都有,因此低于5.1我们就静态引入。 132 | __DEFINE_THUNK( 133 | shlwapi, 134 | 12, 135 | BOOL, 136 | WINAPI, 137 | StrToInt64ExA, 138 | _In_ PCSTR pszString, 139 | STIF_FLAGS dwFlags, 140 | _Out_ LONGLONG* pllRet 141 | ) 142 | { 143 | if (const auto pStrToInt64ExA = try_get_StrToInt64ExA()) 144 | { 145 | return pStrToInt64ExA(pszString, dwFlags, pllRet); 146 | } 147 | 148 | return internal::StrToInt64ExT(pszString, dwFlags, pllRet); 149 | } 150 | #endif //YY_Thunks_Target < __WindowsNT5_1 151 | 152 | 153 | #if (YY_Thunks_Target < __WindowsNT5_1) 154 | 155 | // Windows 2000 Professional, Windows XP [desktop apps only] 156 | // Windows 2000 Server [desktop apps only] 157 | // 虽然Windows 2000支持,但是在IE6里面而IE6不一定所有Windows 2000都有,因此低于5.1我们就静态引入。 158 | __DEFINE_THUNK( 159 | shlwapi, 160 | 12, 161 | BOOL, 162 | WINAPI, 163 | StrToInt64ExW, 164 | _In_ PCWSTR pszString, 165 | STIF_FLAGS dwFlags, 166 | _Out_ LONGLONG* pllRet 167 | ) 168 | { 169 | if (const auto pStrToInt64ExW = try_get_StrToInt64ExW()) 170 | { 171 | return pStrToInt64ExW(pszString, dwFlags, pllRet); 172 | } 173 | 174 | return internal::StrToInt64ExT(pszString, dwFlags, pllRet); 175 | } 176 | #endif //YY_Thunks_Target < __WindowsNT5_1 177 | } 178 | -------------------------------------------------------------------------------- /NuGet/build/native/YY-Thunks.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | YY_Thunks_for_Win10.0.19041.obj 9 | YY_Thunks_for_Win10.0.10240.obj 10 | 11 | 12 | YY_Thunks_for_Win8.obj 13 | YY_Thunks_for_Win7.obj 14 | 15 | 16 | YY_Thunks_for_Win8.obj 17 | YY_Thunks_for_Win7.obj 18 | YY_Thunks_for_Vista.obj 19 | YY_Thunks_for_WinXP.obj 20 | YY_Thunks_for_WinXP.obj 21 | YY_Thunks_for_Win2K.obj 22 | 23 | $(YY_Thunks_File) 24 | YY_Thunks_for_WinXP.obj 25 | 26 | 27 | YY_Thunks_for_Vista.obj 28 | 29 | 30 | 31 | 32 | 5.01 33 | 5.02 34 | $(MSBuildThisFileDirectory)objs\$(PlatformShortName)\$(Internal_YY_Thunks_File);%(AdditionalDependencies) 35 | DllMainCRTStartupForYY_Thunks 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/YY-Thunks.UnitTest/TestProject/Example/SymbolBuildTest.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Static 6 | Win32 7 | 8 | 9 | Static 10 | x64 11 | 12 | 13 | 14 | 16.0 15 | Win32Proj 16 | {d9038cfe-f467-4db0-8609-e9f0b77e2fce} 17 | SymbolBuildTest 18 | $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) 19 | $(SymbolsTestCppRootPath) 20 | $(Platform)\$(Configuration)\ 21 | 22 | 23 | 24 | Application 25 | false 26 | $(DefaultPlatformToolset) 27 | true 28 | Unicode 29 | 30 | 31 | Application 32 | false 33 | $(DefaultPlatformToolset) 34 | true 35 | Unicode 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | false 49 | $(SymbolsTestCppRootPathTmp) 50 | $(SymbolsTestCppRootPathTmp) 51 | $(VC_LibraryPath_x86);$(WindowsSdkDir_60A)\lib 52 | $(YY_Thunks_Libs);$(LibraryPath) 53 | 54 | 55 | false 56 | $(SymbolsTestCppRootPathTmp) 57 | $(SymbolsTestCppRootPathTmp) 58 | $(VC_LibraryPath_x64);$(WindowsSdkDir_60A)\lib\x64 59 | $(YY_Thunks_Libs);$(LibraryPath) 60 | 61 | 62 | 63 | Level3 64 | true 65 | true 66 | true 67 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 68 | true 69 | MultiThreaded 70 | 71 | 72 | Console 73 | true 74 | true 75 | $(YY_Thunks_File_Path) 76 | 77 | 78 | 79 | 80 | Level3 81 | true 82 | true 83 | true 84 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 85 | true 86 | MultiThreaded 87 | 88 | 89 | Console 90 | true 91 | true 92 | $(YY_Thunks_File_Path) 93 | LinkVerboseLib 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /src/Thunks/api-ms-win-core-winrt-error.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6_3) 2 | #include 3 | #endif 4 | 5 | #if (YY_Thunks_Target < __WindowsNT6_3) && (YY_Thunks_Target >= __WindowsNT6_2 || __YY_Thunks_libs) && !defined(__Comment_Lib_runtimeobject) 6 | #define __Comment_Lib_runtimeobject 7 | // RoOriginateError 8 | #pragma comment(lib, "runtimeobject.lib") 9 | #endif 10 | 11 | namespace YY::Thunks 12 | { 13 | #if (YY_Thunks_Target < __WindowsNT6_2) 14 | 15 | // 最低受支持的客户端 Windows 8 [桌面应用 |UWP 应用] 16 | // 最低受支持的服务器 Windows Server 2012[桌面应用 | UWP 应用] 17 | __DEFINE_THUNK( 18 | api_ms_win_core_winrt_error_l1_1_0, 19 | 8, 20 | BOOL, 21 | WINAPI, 22 | RoOriginateError, 23 | _In_ HRESULT _hrError, 24 | _In_opt_ HSTRING _szMessage 25 | ) 26 | { 27 | if (const auto _pfnRoOriginateError = try_get_RoOriginateError()) 28 | { 29 | return _pfnRoOriginateError(_hrError, _szMessage); 30 | } 31 | 32 | return FAILED(_hrError); 33 | } 34 | #endif 35 | 36 | 37 | #if (YY_Thunks_Target < __WindowsNT6_2) 38 | 39 | // 最低受支持的客户端 Windows 8 [桌面应用 |UWP 应用] 40 | // 最低受支持的服务器 Windows Server 2012[桌面应用 | UWP 应用] 41 | __DEFINE_THUNK( 42 | api_ms_win_core_winrt_error_l1_1_0, 43 | 12, 44 | BOOL, 45 | WINAPI, 46 | RoOriginateErrorW, 47 | _In_ HRESULT _hrError, 48 | _In_ UINT _cchMax, 49 | _When_(_cchMax == 0, _In_reads_or_z_opt_(MAX_ERROR_MESSAGE_CHARS) ) 50 | _When_(_cchMax > 0 && _cchMax < MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(_cchMax) ) 51 | _When_(_cchMax >= MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(MAX_ERROR_MESSAGE_CHARS) ) PCWSTR _szMessage 52 | ) 53 | { 54 | if (const auto _pfnRoOriginateErrorW = try_get_RoOriginateErrorW()) 55 | { 56 | return _pfnRoOriginateErrorW(_hrError, _cchMax, _szMessage); 57 | } 58 | 59 | return FAILED(_hrError); 60 | } 61 | #endif 62 | 63 | 64 | #if (YY_Thunks_Target < __WindowsNT6_2) 65 | 66 | // 最低受支持的客户端 Windows 8 [桌面应用 |UWP 应用] 67 | // 最低受支持的服务器 Windows Server 2012[桌面应用 | UWP 应用] 68 | __DEFINE_THUNK( 69 | api_ms_win_core_winrt_error_l1_1_0, 70 | 4, 71 | void, 72 | WINAPI, 73 | RoFailFastWithErrorContext, 74 | HRESULT _hrError 75 | ) 76 | { 77 | if (const auto _pfnRoFailFastWithErrorContext = try_get_RoFailFastWithErrorContext()) 78 | { 79 | return _pfnRoFailFastWithErrorContext(_hrError); 80 | } 81 | 82 | RaiseFailFastException(nullptr, nullptr, 0); 83 | } 84 | #endif 85 | 86 | 87 | #if (YY_Thunks_Target < __WindowsNT6_3) 88 | 89 | // 最低受支持的客户端 Windows 8.1 [桌面应用 |UWP 应用] 90 | // 最低受支持的服务器 Windows Server 2012 R2[桌面应用 | UWP 应用] 91 | __DEFINE_THUNK( 92 | api_ms_win_core_winrt_error_l1_1_1, 93 | 12, 94 | BOOL, 95 | WINAPI, 96 | RoOriginateLanguageException, 97 | _In_ HRESULT _hrError, 98 | _In_opt_ HSTRING _szMessage, 99 | _In_opt_ IUnknown* _pLanguageException 100 | ) 101 | { 102 | if (const auto _pfnRoOriginateLanguageException = try_get_RoOriginateLanguageException()) 103 | { 104 | return _pfnRoOriginateLanguageException(_hrError, _szMessage, _pLanguageException); 105 | } 106 | 107 | return RoOriginateError(_hrError, _szMessage); 108 | } 109 | #endif 110 | 111 | 112 | #if (YY_Thunks_Target < __WindowsNT6_2) 113 | 114 | // 最低受支持的客户端 Windows 8 [桌面应用 |UWP 应用] 115 | // 最低受支持的服务器 Windows Server 2012[桌面应用 | UWP 应用] 116 | __DEFINE_THUNK( 117 | api_ms_win_core_winrt_error_l1_1_0, 118 | 12, 119 | BOOL, 120 | WINAPI, 121 | RoTransformError, 122 | _In_ HRESULT _hrOldError, 123 | _In_ HRESULT _hrNewError, 124 | _In_opt_ HSTRING _szMessage 125 | ) 126 | { 127 | if (const auto _pfnRoTransformError = try_get_RoTransformError()) 128 | { 129 | return _pfnRoTransformError(_hrOldError, _hrNewError, _szMessage); 130 | } 131 | 132 | if (_hrOldError == _hrNewError || (SUCCEEDED(_hrOldError) && SUCCEEDED(_hrNewError))) 133 | { 134 | return FALSE; 135 | } 136 | 137 | return TRUE; 138 | } 139 | #endif 140 | 141 | 142 | #if (YY_Thunks_Target < __WindowsNT6_2) 143 | 144 | // 最低受支持的客户端 Windows 8 [桌面应用 |UWP 应用] 145 | // 最低受支持的服务器 Windows Server 2012[桌面应用 | UWP 应用] 146 | __DEFINE_THUNK( 147 | api_ms_win_core_winrt_error_l1_1_0, 148 | 16, 149 | BOOL, 150 | WINAPI, 151 | RoTransformErrorW, 152 | _In_ HRESULT _hrOldError, 153 | _In_ HRESULT _hrNewError, 154 | _In_ UINT _cchMax, 155 | _When_(_cchMax == 0, _In_reads_or_z_opt_(MAX_ERROR_MESSAGE_CHARS)) 156 | _When_(_cchMax > 0 && _cchMax < MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(_cchMax) ) 157 | _When_(_cchMax >= MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(MAX_ERROR_MESSAGE_CHARS) ) PCWSTR _szMessage 158 | ) 159 | { 160 | if (const auto _pfnRoTransformErrorW = try_get_RoTransformErrorW()) 161 | { 162 | return _pfnRoTransformErrorW(_hrOldError, _hrNewError, _cchMax, _szMessage); 163 | } 164 | 165 | if (_hrOldError == _hrNewError || (SUCCEEDED(_hrOldError) && SUCCEEDED(_hrNewError))) 166 | { 167 | return FALSE; 168 | } 169 | 170 | return TRUE; 171 | } 172 | #endif 173 | } 174 | -------------------------------------------------------------------------------- /src/Shared/HookThunk.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | 跨模块ABI兼容的Thunk逻辑。 5 | */ 6 | 7 | namespace YY::Thunks::internal 8 | { 9 | namespace 10 | { 11 | union HookThunkData 12 | { 13 | private: 14 | static HookThunkData* volatile pFreeRoot; 15 | // Windows最小地址管理粒度是64K,所以我们就直接申请一个64K 16 | static constexpr size_t kAllocBufferBytesCount = 64 * 1024; 17 | 18 | public: 19 | HookThunkData* volatile pNext; 20 | // 可以供内存执行权限的一段区域 21 | struct 22 | { 23 | unsigned char ShellCode[60]; 24 | // 内存块的引用计数。 25 | // 1. 如果是Buffer第一块内存的引用计数,那么引用归零时彻底释放整个缓冲区。 26 | // 2. 如果不是Buffer第一块内存的引用计数,引用归零时减少一次该缓冲区第一块内存的引用计数。 27 | ULONG uRef; 28 | }; 29 | 30 | static HookThunkData* __fastcall Alloc() 31 | { 32 | __declspec(allocate(".YYThr$AAB")) static void* s_FreeAllHookThunkData = reinterpret_cast(&HookThunkData::FreeAll); 33 | __foreinclude(s_FreeAllHookThunkData); 34 | 35 | for (auto _pLast = pFreeRoot; _pLast;) 36 | { 37 | auto _pNext = _pLast->pNext; 38 | 39 | auto _pResult = (HookThunkData*)InterlockedCompareExchange((volatile uintptr_t*)&pFreeRoot, (uintptr_t)_pNext, (uintptr_t)_pLast); 40 | if (_pResult == _pLast) 41 | { 42 | _pResult->pNext = nullptr; 43 | 44 | InterlockedIncrement(&_pResult->uRef); 45 | return _pResult; 46 | } 47 | _pLast = _pResult; 48 | } 49 | 50 | // 缓存区域已经耗尽,申请新的内存。 51 | auto _pResult = (HookThunkData*)VirtualAlloc(nullptr, kAllocBufferBytesCount, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 52 | if (!_pResult) 53 | return nullptr; 54 | 55 | // 因为当前需要返回 _pResult,所以引用计数额外 + 1 56 | _pResult->uRef = kAllocBufferBytesCount / sizeof(HookThunkData) + 1; 57 | 58 | static_assert(kAllocBufferBytesCount % sizeof(HookThunkData) == 0, ""); 59 | // 因为等会需要返回一块内存,所以第一快内存我们就需要跳过,不添加到pFreeRoot了。 60 | const auto _pFirstBuffer = _pResult + 1; 61 | const auto _pLastBuffer = reinterpret_cast((uintptr_t)_pResult + kAllocBufferBytesCount - sizeof(HookThunkData)); 62 | 63 | for (auto _pItem = _pFirstBuffer; ;) 64 | { 65 | _pItem->uRef = 1; 66 | if (_pItem == _pLastBuffer) 67 | break; 68 | auto _pNext = _pItem + 1; 69 | _pItem->pNext = _pNext; 70 | _pItem = _pNext; 71 | } 72 | 73 | for (auto _pLast = pFreeRoot; ;) 74 | { 75 | _pLastBuffer->pNext = _pLast; 76 | auto _pResult = (HookThunkData*)InterlockedCompareExchange((volatile uintptr_t*)&pFreeRoot, (uintptr_t)_pFirstBuffer, (uintptr_t)_pLast); 77 | if (_pResult == _pLast) 78 | { 79 | break; 80 | } 81 | _pLast = _pResult; 82 | } 83 | return _pResult; 84 | } 85 | 86 | void __fastcall Free() 87 | { 88 | // 防止内存执行区域被人利用,数据全部清除!! 89 | memset(ShellCode, 0, sizeof(ShellCode)); 90 | 91 | if (Release() == 0) 92 | return; 93 | 94 | // 重新将内存加入缓存区域。 95 | for (auto _pLast = pFreeRoot; ;) 96 | { 97 | pNext = _pLast; 98 | auto _pResult = (HookThunkData*)InterlockedCompareExchange((volatile uintptr_t*)&pFreeRoot, (uintptr_t)this, (uintptr_t)_pLast); 99 | if (_pResult == _pLast) 100 | { 101 | return; 102 | } 103 | _pLast = _pResult; 104 | } 105 | } 106 | 107 | private: 108 | static void __cdecl FreeAll() noexcept 109 | { 110 | HookThunkData* _pRoot = (HookThunkData*)InterlockedExchange((volatile uintptr_t*)&pFreeRoot, (uintptr_t)nullptr); 111 | for (auto _pItem = _pRoot; _pItem; ) 112 | { 113 | auto _pNext = _pItem->pNext; 114 | _pItem->Release(); 115 | 116 | _pItem = _pNext; 117 | } 118 | } 119 | 120 | /// 121 | /// 减少一次内存引用。 122 | /// 123 | /// 返回新的引用计数。 124 | ULONG __fastcall Release() noexcept 125 | { 126 | const auto _uNewRef = InterlockedDecrement(&uRef); 127 | if (_uNewRef == 0) 128 | { 129 | // 引用归0,这块内存可能来自于其他模块,并且目标模块已经释放。 130 | auto _pFirstBlock = reinterpret_cast(uintptr_t(this) & (~(kAllocBufferBytesCount - 1))); 131 | if (_pFirstBlock == this || InterlockedDecrement(&_pFirstBlock->uRef) == 0) 132 | { 133 | VirtualFree(_pFirstBlock, 0, MEM_RELEASE); 134 | } 135 | } 136 | 137 | return _uNewRef; 138 | } 139 | }; 140 | 141 | HookThunkData* volatile HookThunkData::pFreeRoot = nullptr; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/Thunks/api-ms-win-power-base.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6_2) 2 | #include 3 | #endif 4 | 5 | #if (YY_Thunks_Target < __WindowsNT6_2) && !defined(__Comment_Lib_powrprof) 6 | #define __Comment_Lib_powrprof 7 | #pragma comment(lib, "PowrProf.lib") 8 | #endif 9 | 10 | #if (YY_Thunks_Target < __WindowsNT6_2) && defined(YY_Thunks_Implemented) 11 | namespace YY::Thunks 12 | { 13 | namespace 14 | { 15 | static 16 | DWORD 17 | WINAPI 18 | PowerRegisterSuspendResumeNotificationDownlevel( 19 | _In_ DWORD _fFlags, 20 | _In_ HANDLE _hRecipient, 21 | _Out_ PHPOWERNOTIFY _phRegistrationHandle 22 | ) 23 | { 24 | if (!_phRegistrationHandle) 25 | return ERROR_INVALID_PARAMETER; 26 | *_phRegistrationHandle = NULL; 27 | 28 | const auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; 29 | 30 | 31 | if (DEVICE_NOTIFY_CALLBACK == _fFlags) 32 | { 33 | auto _pDeviceNotifyInfo = (DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS*)_hRecipient; 34 | if(!_pDeviceNotifyInfo) 35 | return ERROR_INVALID_PARAMETER; 36 | 37 | struct DeviceNotifyTaskItem : public internal::TaskItem 38 | { 39 | DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS Parameters; 40 | }; 41 | 42 | auto _pTask = (DeviceNotifyTaskItem*)HeapAlloc(_hProcessHeap, 0, sizeof(DeviceNotifyTaskItem)); 43 | if (!_pTask) 44 | return ERROR_OUTOFMEMORY; 45 | 46 | _pTask->Parameters = *_pDeviceNotifyInfo; 47 | _pTask->pfnCallback = []( 48 | internal::TaskItem* _pWork, 49 | UINT _uMsg, 50 | WPARAM _wParam, 51 | LPARAM _lParam) -> BOOL 52 | { 53 | auto _pWork2 = (DeviceNotifyTaskItem*)_pWork; 54 | 55 | if (WM_POWERBROADCAST == _uMsg) 56 | { 57 | _pWork2->Parameters.Callback(_pWork2->Parameters.Context, static_cast(_wParam), (PVOID)_lParam); 58 | } 59 | 60 | return TRUE; 61 | }; 62 | 63 | if (internal::GetGlobalThreadRunner()->AddTask(_pTask)) 64 | { 65 | *_phRegistrationHandle = _pTask; 66 | return ERROR_SUCCESS; 67 | } 68 | 69 | HeapFree(_hProcessHeap, 0, _pTask); 70 | return ERROR_OUTOFMEMORY; 71 | } 72 | else 73 | { 74 | return ERROR_INVALID_PARAMETER; 75 | } 76 | } 77 | 78 | static 79 | DWORD 80 | WINAPI 81 | PowerUnregisterSuspendResumeNotificationDownlevel( 82 | _Inout_ HPOWERNOTIFY _hRegistrationHandle 83 | ) 84 | { 85 | if (!_hRegistrationHandle) 86 | return ERROR_INVALID_PARAMETER; 87 | 88 | return internal::GetGlobalThreadRunner()->RemoveTask((internal::TaskItem*)_hRegistrationHandle); 89 | } 90 | } 91 | } 92 | #endif // (YY_Thunks_Target < __WindowsNT6_2) && defined(YY_Thunks_Implemented) 93 | 94 | namespace YY::Thunks 95 | { 96 | #if (YY_Thunks_Target < __WindowsNT6_2) 97 | 98 | // 最低受支持的客户端 Windows 8 [桌面应用|UWP 应用] 99 | // 最低受支持的服务器 Windows Server 2012[桌面应用 | UWP 应用] 100 | __DEFINE_THUNK( 101 | powrprof, 102 | 4, 103 | POWER_PLATFORM_ROLE, 104 | WINAPI, 105 | PowerDeterminePlatformRoleEx, 106 | _In_ ULONG _uVersion 107 | ) 108 | { 109 | if (auto const _pfnPowerDeterminePlatformRoleEx = try_get_PowerDeterminePlatformRoleEx()) 110 | { 111 | return _pfnPowerDeterminePlatformRoleEx(_uVersion); 112 | } 113 | 114 | if (_uVersion == POWER_PLATFORM_ROLE_V1) 115 | { 116 | return PowerDeterminePlatformRole(); 117 | } 118 | else 119 | { 120 | return PlatformRoleUnspecified; 121 | } 122 | } 123 | #endif 124 | 125 | 126 | #if (YY_Thunks_Target < __WindowsNT6_2) 127 | 128 | // 最低受支持的客户端 Windows 8 [仅限桌面应用] 129 | // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] 130 | __DEFINE_THUNK( 131 | powrprof, 132 | 12, 133 | DWORD, 134 | WINAPI, 135 | PowerRegisterSuspendResumeNotification, 136 | _In_ DWORD _fFlags, 137 | _In_ HANDLE _hRecipient, 138 | _Out_ PHPOWERNOTIFY _phRegistrationHandle 139 | ) 140 | { 141 | if (auto const _pfnPowerRegisterSuspendResumeNotification = try_get_PowerRegisterSuspendResumeNotification()) 142 | { 143 | return _pfnPowerRegisterSuspendResumeNotification(_fFlags, _hRecipient, _phRegistrationHandle); 144 | } 145 | 146 | return PowerRegisterSuspendResumeNotificationDownlevel(_fFlags, _hRecipient, _phRegistrationHandle); 147 | } 148 | #endif 149 | 150 | 151 | #if (YY_Thunks_Target < __WindowsNT6_2) 152 | 153 | // 最低受支持的客户端 Windows 8 [仅限桌面应用] 154 | // 最低受支持的服务器 Windows Server 2012[仅限桌面应用] 155 | __DEFINE_THUNK( 156 | powrprof, 157 | 4, 158 | DWORD, 159 | WINAPI, 160 | PowerUnregisterSuspendResumeNotification, 161 | _Inout_ HPOWERNOTIFY _hRegistrationHandle 162 | ) 163 | { 164 | if (auto const _pfnPowerUnregisterSuspendResumeNotification = try_get_PowerUnregisterSuspendResumeNotification()) 165 | { 166 | return _pfnPowerUnregisterSuspendResumeNotification(_hRegistrationHandle); 167 | } 168 | 169 | return PowerUnregisterSuspendResumeNotificationDownlevel(_hRegistrationHandle); 170 | } 171 | #endif 172 | } 173 | -------------------------------------------------------------------------------- /src/Thunks/psapi.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef PSAPI_VERSION 3 | #define PSAPI_VERSION 1 4 | #endif 5 | 6 | #if (YY_Thunks_Target < __WindowsNT6) 7 | #include 8 | #endif 9 | 10 | #if (YY_Thunks_Target < __WindowsNT6) && !defined(__Comment_Lib_psapi) 11 | #define __Comment_Lib_psapi 12 | #pragma comment(lib, "Psapi.lib") 13 | #endif 14 | 15 | namespace YY::Thunks 16 | { 17 | #if (YY_Thunks_Target < __WindowsNT6) 18 | 19 | //Windows Vista [desktop apps only] 20 | //Windows Server 2008 [desktop apps only] 21 | __DEFINE_THUNK( 22 | psapi, 23 | 20, 24 | BOOL, 25 | WINAPI, 26 | EnumProcessModulesEx, 27 | _In_ HANDLE hProcess, 28 | _Out_writes_bytes_(cb) HMODULE* lphModule, 29 | _In_ DWORD cb, 30 | _Out_ LPDWORD lpcbNeeded, 31 | _In_ DWORD dwFilterFlag 32 | ) 33 | { 34 | if (auto pEnumProcessModulesEx = try_get_EnumProcessModulesEx()) 35 | { 36 | return pEnumProcessModulesEx(hProcess, lphModule, cb, lpcbNeeded, dwFilterFlag); 37 | } 38 | 39 | return EnumProcessModules(hProcess, lphModule, cb, lpcbNeeded); 40 | } 41 | #endif 42 | 43 | 44 | #if (YY_Thunks_Target < __WindowsNT6) 45 | 46 | //Windows Vista [desktop apps only] 47 | //Windows Server 2008 [desktop apps only] 48 | __DEFINE_THUNK( 49 | psapi, 50 | 12, 51 | BOOL, 52 | WINAPI, 53 | GetWsChangesEx, 54 | _In_ HANDLE hProcess, 55 | _Out_writes_bytes_to_(*cb, *cb) PPSAPI_WS_WATCH_INFORMATION_EX lpWatchInfoEx, 56 | _Inout_ PDWORD cb 57 | ) 58 | { 59 | if (auto pGetWsChangesEx = try_get_GetWsChangesEx()) 60 | { 61 | return pGetWsChangesEx(hProcess, lpWatchInfoEx, cb); 62 | } 63 | 64 | PPSAPI_WS_WATCH_INFORMATION pWatchInfo = nullptr; 65 | DWORD cbWatchInfo = 1024 * sizeof(pWatchInfo[0]); 66 | const auto ProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; 67 | LSTATUS lStatus = ERROR_SUCCESS; 68 | 69 | for (;;) 70 | { 71 | if (pWatchInfo) 72 | { 73 | cbWatchInfo *= 2; 74 | 75 | auto pNewWatchInfo = (PPSAPI_WS_WATCH_INFORMATION)HeapReAlloc(ProcessHeap, 0, pWatchInfo, cbWatchInfo); 76 | 77 | if (!pNewWatchInfo) 78 | { 79 | lStatus = ERROR_OUTOFMEMORY; 80 | break; 81 | } 82 | 83 | pWatchInfo = pNewWatchInfo; 84 | } 85 | else 86 | { 87 | pWatchInfo = (PPSAPI_WS_WATCH_INFORMATION)HeapAlloc(ProcessHeap, 0, cbWatchInfo); 88 | if (!pWatchInfo) 89 | { 90 | lStatus = ERROR_OUTOFMEMORY; 91 | break; 92 | } 93 | } 94 | 95 | if (!GetWsChanges(hProcess, pWatchInfo, cbWatchInfo)) 96 | { 97 | lStatus = GetLastError(); 98 | 99 | if (lStatus == ERROR_INSUFFICIENT_BUFFER) 100 | { 101 | continue; 102 | 103 | } 104 | else 105 | { 106 | break; 107 | } 108 | } 109 | 110 | //确定实际个数 111 | const auto pWatchInfoMax = (PPSAPI_WS_WATCH_INFORMATION)((byte*)pWatchInfo + cbWatchInfo); 112 | auto pWatchInfoTerminated = pWatchInfo; 113 | for (; pWatchInfoTerminated < pWatchInfoMax && pWatchInfoTerminated->FaultingPc != nullptr; ++pWatchInfoTerminated); 114 | 115 | auto ccWatchInfo = pWatchInfoTerminated - pWatchInfo; 116 | 117 | auto cbWatchInfoExRequest = (ccWatchInfo + 1) * sizeof(lpWatchInfoEx[0]); 118 | if (cbWatchInfoExRequest > MAXUINT32) 119 | { 120 | lStatus = ERROR_FUNCTION_FAILED; 121 | break; 122 | } 123 | 124 | auto cbBuffer = *cb; 125 | *cb = static_cast(cbWatchInfoExRequest); 126 | 127 | if (cbBuffer < cbWatchInfoExRequest) 128 | { 129 | lStatus = ERROR_INSUFFICIENT_BUFFER; 130 | break; 131 | } 132 | 133 | 134 | //复制到新缓冲区 135 | for (int i = 0; i != ccWatchInfo; ++i) 136 | { 137 | lpWatchInfoEx[i].BasicInfo = pWatchInfo[i]; 138 | lpWatchInfoEx[i].FaultingThreadId = 0; 139 | lpWatchInfoEx[i].Flags = 0; 140 | } 141 | 142 | //插入终止标记 143 | lpWatchInfoEx[ccWatchInfo] = PSAPI_WS_WATCH_INFORMATION_EX{}; 144 | 145 | lStatus = ERROR_SUCCESS; 146 | break; 147 | } 148 | 149 | if (pWatchInfo) 150 | { 151 | HeapFree(ProcessHeap, 0, pWatchInfo); 152 | } 153 | 154 | if (lStatus == ERROR_SUCCESS) 155 | { 156 | return TRUE; 157 | } 158 | else 159 | { 160 | SetLastError(lStatus); 161 | return FALSE; 162 | } 163 | } 164 | #endif 165 | 166 | 167 | #if (YY_Thunks_Target < __WindowsNT5_2_SP1) 168 | 169 | //Windows Vista, Windows XP Professional x64 Edition [desktop apps only] 170 | //Windows Server 2008, Windows Server 2003 with SP1 [desktop apps only] 171 | __DEFINE_THUNK( 172 | psapi, 173 | 12, 174 | BOOL, 175 | WINAPI, 176 | QueryWorkingSetEx, 177 | _In_ HANDLE hProcess, 178 | _Out_writes_bytes_(cb) PVOID pv, 179 | _In_ DWORD cb 180 | ) 181 | { 182 | if (const auto pQueryWorkingSetEx = try_get_QueryWorkingSetEx()) 183 | { 184 | return pQueryWorkingSetEx(hProcess, pv, cb); 185 | } 186 | else 187 | { 188 | SetLastError(ERROR_INVALID_FUNCTION); 189 | return FALSE; 190 | } 191 | } 192 | #endif 193 | } //namespace YY::Thunks 194 | -------------------------------------------------------------------------------- /src/Thunks/ext-ms-win-ntuser-window.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6_3) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #if (YY_Thunks_Target < __WindowsNT6_2) 8 | // Windows 8 [仅限桌面应用],Windows Server 2012 [仅限桌面应用] 9 | __DEFINE_THUNK( 10 | user32, 11 | 20, 12 | UINT_PTR, 13 | WINAPI, 14 | SetCoalescableTimer, 15 | _In_opt_ HWND _hWnd, 16 | _In_ UINT_PTR _nIDEvent, 17 | _In_ UINT _uElapse, 18 | _In_opt_ TIMERPROC _lpTimerFunc, 19 | _In_ ULONG _uToleranceDelay 20 | ) 21 | { 22 | auto _pfnSetCoalescableTimer = try_get_SetCoalescableTimer(); 23 | if (_pfnSetCoalescableTimer) 24 | { 25 | return _pfnSetCoalescableTimer(_hWnd, _nIDEvent, _uElapse, _lpTimerFunc, _uToleranceDelay); 26 | } 27 | 28 | return SetTimer(_hWnd, _nIDEvent, _uElapse, _lpTimerFunc); 29 | } 30 | #endif 31 | 32 | 33 | #if (YY_Thunks_Target < __WindowsNT6) 34 | 35 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 36 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 37 | __DEFINE_THUNK( 38 | user32, 39 | 8, 40 | BOOL, 41 | WINAPI, 42 | PhysicalToLogicalPoint, 43 | _In_ HWND _hWnd, 44 | _Inout_ LPPOINT _pPoint 45 | ) 46 | { 47 | if (auto const _pfnPhysicalToLogicalPoint = try_get_PhysicalToLogicalPoint()) 48 | { 49 | return _pfnPhysicalToLogicalPoint(_hWnd, _pPoint); 50 | } 51 | 52 | return TRUE; 53 | } 54 | #endif 55 | 56 | 57 | #if (YY_Thunks_Target < __WindowsNT6) 58 | 59 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 60 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 61 | __DEFINE_THUNK( 62 | user32, 63 | 8, 64 | BOOL, 65 | WINAPI, 66 | LogicalToPhysicalPoint, 67 | _In_ HWND _hWnd, 68 | _Inout_ LPPOINT _pPoint 69 | ) 70 | { 71 | if (auto const _pfnLogicalToPhysicalPoint = try_get_LogicalToPhysicalPoint()) 72 | { 73 | return _pfnLogicalToPhysicalPoint(_hWnd, _pPoint); 74 | } 75 | 76 | return TRUE; 77 | } 78 | #endif 79 | 80 | 81 | #if (YY_Thunks_Target < __WindowsNT6_3) 82 | 83 | // 最低受支持的客户端 Windows 8.1 [仅限桌面应用] 84 | // 最低受支持的服务器 Windows Server 2012 R2[仅限桌面应用] 85 | __DEFINE_THUNK( 86 | user32, 87 | 8, 88 | BOOL, 89 | WINAPI, 90 | PhysicalToLogicalPointForPerMonitorDPI, 91 | _In_ HWND _hWnd, 92 | _Inout_ LPPOINT _pPoint 93 | ) 94 | { 95 | if (auto const _pfnPhysicalToLogicalPointForPerMonitorDPI = try_get_PhysicalToLogicalPointForPerMonitorDPI()) 96 | { 97 | return _pfnPhysicalToLogicalPointForPerMonitorDPI(_hWnd, _pPoint); 98 | } 99 | 100 | return PhysicalToLogicalPoint(_hWnd, _pPoint); 101 | } 102 | #endif 103 | 104 | 105 | #if (YY_Thunks_Target < __WindowsNT6_3) 106 | 107 | // 最低受支持的客户端 Windows 8.1 [仅限桌面应用] 108 | // 最低受支持的服务器 Windows Server 2012 R2[仅限桌面应用] 109 | __DEFINE_THUNK( 110 | user32, 111 | 8, 112 | BOOL, 113 | WINAPI, 114 | LogicalToPhysicalPointForPerMonitorDPI, 115 | _In_ HWND _hWnd, 116 | _Inout_ LPPOINT _pPoint 117 | ) 118 | { 119 | if (auto const _pfnLogicalToPhysicalPointForPerMonitorDPI = try_get_LogicalToPhysicalPointForPerMonitorDPI()) 120 | { 121 | return _pfnLogicalToPhysicalPointForPerMonitorDPI(_hWnd, _pPoint); 122 | } 123 | 124 | return LogicalToPhysicalPoint(_hWnd, _pPoint); 125 | } 126 | #endif 127 | 128 | 129 | #if (YY_Thunks_Target < __WindowsNT6_1) 130 | 131 | // 最低受支持的客户端 Windows Vista [仅限桌面应用] 132 | // 最低受支持的服务器 Windows Server 2008[仅限桌面应用] 133 | __DEFINE_THUNK( 134 | user32, 135 | 8, 136 | HWND, 137 | WINAPI, 138 | WindowFromPhysicalPoint, 139 | _In_ POINT _oPoint 140 | ) 141 | { 142 | if (auto const _pfnWindowFromPhysicalPoint = try_get_WindowFromPhysicalPoint()) 143 | { 144 | return _pfnWindowFromPhysicalPoint(_oPoint); 145 | } 146 | 147 | return WindowFromPoint(_oPoint); 148 | } 149 | #endif 150 | 151 | 152 | #if (YY_Thunks_Target < __WindowsNT6) 153 | 154 | // 6.0开始:WH_KEYBOARD_LL/WH_MOUSE_LL且dwThreadId为0时,hMod可以为NULL 155 | __DEFINE_THUNK( 156 | user32, 157 | 16, 158 | HHOOK, 159 | WINAPI, 160 | SetWindowsHookExW, 161 | _In_ int _idHook, 162 | _In_ HOOKPROC _pfn, 163 | _In_opt_ HINSTANCE _hMod, 164 | _In_ DWORD _uThreadId 165 | ) 166 | { 167 | if (auto const _pfnSetWindowsHookExW = try_get_SetWindowsHookExW()) 168 | { 169 | if(_hMod == nullptr && _uThreadId == 0 && (_idHook == WH_KEYBOARD_LL || _idHook == WH_MOUSE_LL)) 170 | { 171 | _hMod = reinterpret_cast(&__ImageBase); 172 | } 173 | 174 | return _pfnSetWindowsHookExW(_idHook, _pfn, _hMod, _uThreadId); 175 | } 176 | 177 | SetLastError(ERROR_INVALID_FUNCTION); 178 | return nullptr; 179 | } 180 | #endif 181 | 182 | 183 | #if (YY_Thunks_Target < __WindowsNT6) 184 | 185 | // 6.0开始:WH_KEYBOARD_LL/WH_MOUSE_LL且dwThreadId为0时,hMod可以为NULL 186 | __DEFINE_THUNK( 187 | user32, 188 | 16, 189 | HHOOK, 190 | WINAPI, 191 | SetWindowsHookExA, 192 | _In_ int _idHook, 193 | _In_ HOOKPROC _pfn, 194 | _In_opt_ HINSTANCE _hMod, 195 | _In_ DWORD _uThreadId 196 | ) 197 | { 198 | if (auto const _pfnSetWindowsHookExA = try_get_SetWindowsHookExA()) 199 | { 200 | if(_hMod == nullptr && _uThreadId == 0 && (_idHook == WH_KEYBOARD_LL || _idHook == WH_MOUSE_LL)) 201 | { 202 | _hMod = reinterpret_cast(&__ImageBase); 203 | } 204 | 205 | return _pfnSetWindowsHookExA(_idHook, _pfn, _hMod, _uThreadId); 206 | } 207 | 208 | SetLastError(ERROR_INVALID_FUNCTION); 209 | return nullptr; 210 | } 211 | #endif 212 | } 213 | -------------------------------------------------------------------------------- /src/Thunks/ntdll.hpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #if defined(YY_Thunks_Implemented) && (YY_Thunks_Target < __WindowsNT6) 4 | namespace YY::Thunks::Fallback 5 | { 6 | static NTSTATUS NTAPI NtCancelIoFileEx( 7 | HANDLE _hHandle, 8 | IO_STATUS_BLOCK* _pIo, 9 | IO_STATUS_BLOCK* _pIoStatus 10 | ) 11 | { 12 | // NtCancelIoFile无法模拟特定的IO取消工作,因此需要取消特定IO时立即失败处理 13 | if (_pIo != nullptr) 14 | { 15 | // Not supported 16 | return STATUS_NOT_FOUND; 17 | } 18 | 19 | #ifndef __USING_NTDLL_LIB 20 | const auto NtCancelIoFile = try_get_NtCancelIoFile(); 21 | if (!NtCancelIoFile) 22 | { 23 | // 正常来说不应该走到这里 24 | return STATUS_NOT_SUPPORTED; 25 | } 26 | #endif 27 | 28 | auto _Status = NtCancelIoFile(_hHandle, _pIoStatus); 29 | if (_Status < 0) 30 | return _Status; 31 | 32 | internal::StringBuffer _Buffer; 33 | auto _pProcessInfo = internal::GetCurrentProcessInfo(_Buffer); 34 | if (!_pProcessInfo) 35 | return _Status; 36 | 37 | const auto _uCurrentThreadId = GetCurrentThreadId(); 38 | for (ULONG i = 0; i != _pProcessInfo->ThreadCount; ++i) 39 | { 40 | auto& _Thread = _pProcessInfo->Threads[i]; 41 | 42 | if (_uCurrentThreadId == static_cast(reinterpret_cast(_Thread.ClientId.UniqueThread))) 43 | continue; 44 | 45 | auto _hThread = OpenThread(THREAD_SET_CONTEXT, FALSE, static_cast(reinterpret_cast(_Thread.ClientId.UniqueThread))); 46 | if (!_hThread) 47 | continue; 48 | 49 | QueueUserAPC( 50 | [](ULONG_PTR _hHandle) 51 | { 52 | #ifndef __USING_NTDLL_LIB 53 | const auto NtCancelIoFile = try_get_NtCancelIoFile(); 54 | #endif 55 | IO_STATUS_BLOCK _IoStatus; 56 | // 故意不判断空指针,NtCancelIoFileEx开头已经判断过了。 57 | // 如果真的崩溃,那么说明内存被改坏了。 58 | NtCancelIoFile(reinterpret_cast(_hHandle), &_IoStatus); 59 | }, _hThread, (ULONG_PTR)_hHandle); 60 | CloseHandle(_hThread); 61 | } 62 | 63 | return _Status; 64 | } 65 | } 66 | #endif 67 | 68 | 69 | namespace YY::Thunks 70 | { 71 | #if (YY_Thunks_Target < __WindowsNT6) 72 | 73 | // 最低受支持的客户端 Windows Vista [桌面应用|UWP 应用] 74 | // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] 75 | __DEFINE_THUNK( 76 | ntdll, 77 | 12, 78 | NTSTATUS, 79 | NTAPI, 80 | NtCancelIoFileEx, 81 | HANDLE _hHandle, 82 | IO_STATUS_BLOCK* _pIo, 83 | IO_STATUS_BLOCK* _pIoStatus 84 | ) 85 | { 86 | if (const auto _pfnNtCancelIoFileEx = try_get_NtCancelIoFileEx()) 87 | { 88 | return _pfnNtCancelIoFileEx(_hHandle, _pIo, _pIoStatus); 89 | } 90 | 91 | return Fallback::NtCancelIoFileEx(_hHandle, _pIo, _pIoStatus); 92 | } 93 | #endif 94 | 95 | 96 | #if (YY_Thunks_Target < __WindowsNT6_1) 97 | 98 | // 最低受支持的客户端 在 Windows 7 和更高版本的 Windows 中可用。 99 | __DEFINE_THUNK( 100 | ntdll, 101 | 16, 102 | NTSTATUS, 103 | NTAPI, 104 | NtOpenKeyEx, 105 | __out PHANDLE _phKeyHandle, 106 | __in ACCESS_MASK _fDesiredAccess, 107 | __in POBJECT_ATTRIBUTES _pObjectAttributes, 108 | __in ULONG _fOpenOptions 109 | ) 110 | { 111 | if (const auto _pfnNtOpenKeyEx = try_get_NtOpenKeyEx()) 112 | { 113 | return _pfnNtOpenKeyEx(_phKeyHandle, _fDesiredAccess, _pObjectAttributes, _fOpenOptions); 114 | } 115 | 116 | #ifndef __USING_NTDLL_LIB 117 | const auto NtOpenKey = try_get_NtOpenKey(); 118 | if (!NtOpenKey) 119 | { 120 | // 正常来说不应该走到这里,XP存在此函数 121 | return STATUS_NOT_SUPPORTED; 122 | } 123 | #endif 124 | 125 | if (_fOpenOptions & (~(REG_OPTION_OPEN_LINK | REG_OPTION_BACKUP_RESTORE))) 126 | return STATUS_INVALID_PARAMETER_4; 127 | 128 | OBJECT_ATTRIBUTES _ObjectAttributes; 129 | if (_fOpenOptions & REG_OPTION_OPEN_LINK) 130 | { 131 | __try 132 | { 133 | // 避免 ObjectAttributes 指针非法 134 | // 我们抓异常为了模拟原版函数行为,内存无效时可以返回错误代码。 135 | _ObjectAttributes = *_pObjectAttributes; 136 | } 137 | __except (EXCEPTION_EXECUTE_HANDLER) 138 | { 139 | return GetExceptionCode(); 140 | } 141 | 142 | _ObjectAttributes.Attributes |= OBJ_OPENLINK; 143 | _pObjectAttributes = &_ObjectAttributes; 144 | } 145 | 146 | if ((_fOpenOptions & REG_OPTION_BACKUP_RESTORE) == 0) 147 | return NtOpenKey(_phKeyHandle, _fDesiredAccess, _pObjectAttributes); 148 | 149 | #ifndef __USING_NTDLL_LIB 150 | const auto NtCreateKey = try_get_NtCreateKey(); 151 | const auto NtDeleteKey = try_get_NtDeleteKey(); 152 | const auto NtClose = try_get_NtClose(); 153 | if (NtCreateKey == nullptr || NtDeleteKey == nullptr || NtClose == nullptr) 154 | return STATUS_NOT_SUPPORTED; 155 | #endif 156 | 157 | // 先测试一下 Key在不在,如果确定不在就没有必要继续了。 158 | HANDLE _hKey = NULL; 159 | LONG _Status = NtOpenKey(&_hKey, STANDARD_RIGHTS_READ, _pObjectAttributes); 160 | if (_Status < 0 && _Status != STATUS_ACCESS_DENIED) 161 | return _Status; 162 | 163 | do 164 | { 165 | ULONG Disposition; 166 | _Status = NtCreateKey(_phKeyHandle, _fDesiredAccess, _pObjectAttributes, 0, nullptr, REG_OPTION_BACKUP_RESTORE, &Disposition); 167 | if (_Status < 0) 168 | break; 169 | 170 | if (Disposition == REG_CREATED_NEW_KEY) 171 | { 172 | // 新建的话就重新删除,毕竟NtOpenKeyEx是没有创建功能的。 173 | NtDeleteKey(*_phKeyHandle); 174 | NtClose(*_phKeyHandle); 175 | *_phKeyHandle = NULL; 176 | _Status = STATUS_OBJECT_NAME_NOT_FOUND; 177 | } 178 | } while (false); 179 | 180 | if(_hKey) 181 | NtClose(_hKey); 182 | 183 | return _Status; 184 | } 185 | #endif 186 | } // namespace YY::Thunks 187 | -------------------------------------------------------------------------------- /src/Thunks/Crypt32.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6) 2 | #include 3 | #endif 4 | 5 | namespace YY::Thunks 6 | { 7 | #if (YY_Thunks_Target < __WindowsNT6) 8 | 9 | // 最低受支持的客户端 Windows Vista [桌面应用|UWP 应用] 10 | // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] 11 | __DEFINE_THUNK( 12 | crypt32, 13 | 12, 14 | BOOL, 15 | WINAPI, 16 | CryptProtectMemory, 17 | _Inout_ LPVOID pDataIn, 18 | _In_ DWORD cbDataIn, 19 | _In_ DWORD dwFlags 20 | ) 21 | { 22 | if (const auto _pfnCryptProtectMemory = try_get_CryptProtectMemory()) 23 | { 24 | return _pfnCryptProtectMemory(pDataIn, cbDataIn, dwFlags); 25 | } 26 | 27 | return TRUE; 28 | } 29 | #endif 30 | 31 | 32 | #if (YY_Thunks_Target < __WindowsNT6) 33 | 34 | // 最低受支持的客户端 Windows Vista [桌面应用|UWP 应用] 35 | // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] 36 | __DEFINE_THUNK( 37 | crypt32, 38 | 12, 39 | BOOL, 40 | WINAPI, 41 | CryptUnprotectMemory, 42 | _Inout_ LPVOID pDataIn, 43 | _In_ DWORD cbDataIn, 44 | _In_ DWORD dwFlags 45 | ) 46 | { 47 | if (const auto _pfnCryptUnprotectMemory = try_get_CryptUnprotectMemory()) 48 | { 49 | return _pfnCryptUnprotectMemory(pDataIn, cbDataIn, dwFlags); 50 | } 51 | 52 | return TRUE; 53 | } 54 | #endif 55 | 56 | 57 | #if (YY_Thunks_Target < __WindowsNT6) 58 | 59 | // 最低受支持的客户端 Windows XP [桌面应用 | UWP 应用] 60 | // 最低受支持的服务器 Windows Server 2003[桌面应用 | UWP 应用] 61 | // CRYPT_STRING_NOCRLF 需要Windows Vista或者更高 62 | __DEFINE_THUNK( 63 | crypt32, 64 | 20, 65 | BOOL, 66 | WINAPI, 67 | CryptBinaryToStringW, 68 | _In_reads_bytes_(_cbBinary) CONST BYTE* _pBinary, 69 | _In_ DWORD _cbBinary, 70 | _In_ DWORD _fFlags, 71 | _Out_writes_to_opt_(*_pcString, *_pcString) LPWSTR _szString, 72 | _Inout_ DWORD* _pcString 73 | ) 74 | { 75 | const auto _pfnCryptBinaryToStringW = try_get_CryptBinaryToStringW(); 76 | if (!_pfnCryptBinaryToStringW) 77 | { 78 | // Windows 2000? 79 | SetLastError(ERROR_FUNCTION_FAILED); 80 | return FALSE; 81 | } 82 | 83 | // CRYPT_STRING_NOCRLF 需要 Windows Vista 84 | if ((_fFlags & CRYPT_STRING_NOCRLF) && internal::GetSystemVersion() < internal::MakeVersion(6, 0)) 85 | { 86 | _fFlags &= ~CRYPT_STRING_NOCRLF; 87 | if (!_szString) 88 | { 89 | // 少了 CRYPT_STRING_NOCRLF 所需的缓冲区只可能比原版多,所以这样做是安全的。 90 | return _pfnCryptBinaryToStringW(_pBinary, _cbBinary, _fFlags, _szString, _pcString); 91 | } 92 | 93 | if (!_pfnCryptBinaryToStringW(_pBinary, _cbBinary, _fFlags, _szString, _pcString)) 94 | return FALSE; 95 | 96 | // 删除所有的 "\r\n",模拟 CRYPT_STRING_NOCRLF 行为 97 | const auto _szStringEnd = _szString + *_pcString; 98 | auto _szStringNew = _szString; 99 | bool _bHasSkip = false; 100 | for (auto _szCurrent = _szString; _szCurrent != _szStringEnd; ++_szCurrent) 101 | { 102 | const auto _ch = *_szCurrent; 103 | if (_ch == L'\r' || _ch == L'\n') 104 | { 105 | _bHasSkip = true; 106 | } 107 | else 108 | { 109 | if (_bHasSkip) 110 | { 111 | *_szStringNew = *_szCurrent; 112 | } 113 | 114 | ++_szStringNew; 115 | } 116 | } 117 | 118 | *_szStringNew = L'\0'; 119 | *_pcString = _szStringNew - _szString; 120 | return TRUE; 121 | } 122 | 123 | return _pfnCryptBinaryToStringW(_pBinary, _cbBinary, _fFlags, _szString, _pcString); 124 | } 125 | #endif 126 | 127 | 128 | #if (YY_Thunks_Target < __WindowsNT6) 129 | 130 | // 最低受支持的客户端 Windows XP [桌面应用 | UWP 应用] 131 | // 最低受支持的服务器 Windows Server 2003[桌面应用 | UWP 应用] 132 | // CRYPT_STRING_NOCRLF 需要Windows Vista或者更高 133 | __DEFINE_THUNK( 134 | crypt32, 135 | 20, 136 | BOOL, 137 | WINAPI, 138 | CryptBinaryToStringA, 139 | _In_reads_bytes_(_cbBinary) CONST BYTE* _pBinary, 140 | _In_ DWORD _cbBinary, 141 | _In_ DWORD _fFlags, 142 | _Out_writes_to_opt_(*_pcString, *_pcString) LPSTR _szString, 143 | _Inout_ DWORD* _pcString 144 | ) 145 | { 146 | const auto _pfnCryptBinaryToStringA = try_get_CryptBinaryToStringA(); 147 | if (!_pfnCryptBinaryToStringA) 148 | { 149 | // Windows 2000? 150 | SetLastError(ERROR_FUNCTION_FAILED); 151 | return FALSE; 152 | } 153 | 154 | // CRYPT_STRING_NOCRLF 需要 Windows Vista 155 | if ((_fFlags & CRYPT_STRING_NOCRLF) && internal::GetSystemVersion() < internal::MakeVersion(6, 0)) 156 | { 157 | _fFlags &= ~CRYPT_STRING_NOCRLF; 158 | if (!_szString) 159 | { 160 | // 少了 CRYPT_STRING_NOCRLF 所需的缓冲区只可能比原版多,所以这样做是安全的。 161 | return _pfnCryptBinaryToStringA(_pBinary, _cbBinary, _fFlags, _szString, _pcString); 162 | } 163 | 164 | if (!_pfnCryptBinaryToStringA(_pBinary, _cbBinary, _fFlags, _szString, _pcString)) 165 | return FALSE; 166 | 167 | // 删除所有的 "\r\n",模拟 CRYPT_STRING_NOCRLF 行为 168 | const auto _szStringEnd = _szString + *_pcString; 169 | auto _szStringNew = _szString; 170 | bool _bHasSkip = false; 171 | for (auto _szCurrent = _szString; _szCurrent != _szStringEnd; ++_szCurrent) 172 | { 173 | const auto _ch = *_szCurrent; 174 | if (_ch == '\r' || _ch == '\n') 175 | { 176 | _bHasSkip = true; 177 | } 178 | else 179 | { 180 | if (_bHasSkip) 181 | { 182 | *_szStringNew = *_szCurrent; 183 | } 184 | 185 | ++_szStringNew; 186 | } 187 | } 188 | 189 | *_szStringNew = L'\0'; 190 | *_pcString = _szStringNew - _szString; 191 | return TRUE; 192 | } 193 | 194 | return _pfnCryptBinaryToStringA(_pBinary, _cbBinary, _fFlags, _szString, _pcString); 195 | } 196 | #endif 197 | } // namespace YY::Thunks 198 | -------------------------------------------------------------------------------- /src/Thunks/api-ms-win-core-com.hpp: -------------------------------------------------------------------------------- 1 | #if (YY_Thunks_Target < __WindowsNT6_2) 2 | #include 3 | #endif 4 | 5 | #if (YY_Thunks_Target < __WindowsNT6_1) && !defined(__Comment_Lib_ole32) 6 | #define __Comment_Lib_ole32 7 | #pragma comment(lib, "ole32.lib") 8 | #endif 9 | 10 | namespace YY::Thunks 11 | { 12 | #if (YY_Thunks_Target < __WindowsNT6_1) 13 | 14 | // Windows 7 [桌面应用|UWP 应用], Windows Server 2008 R2 [桌面应用|UWP 应用] 15 | __DEFINE_THUNK( 16 | ole32, 17 | 8, 18 | HRESULT, 19 | WINAPI, 20 | CoGetApartmentType, 21 | _Out_ APTTYPE* _pAptType, 22 | _Out_ APTTYPEQUALIFIER* _pAptQualifier 23 | ) 24 | { 25 | if (auto _pfnCoGetApartmentType = try_get_CoGetApartmentType()) 26 | { 27 | return _pfnCoGetApartmentType(_pAptType, _pAptQualifier); 28 | } 29 | 30 | if (_pAptType == nullptr || _pAptQualifier == nullptr) 31 | return E_INVALIDARG; 32 | 33 | *_pAptType = APTTYPE_CURRENT; 34 | *_pAptQualifier = APTTYPEQUALIFIER_NONE; 35 | 36 | IUnknown* _pContextToken; 37 | auto _hr = CoGetContextToken((ULONG_PTR*)&_pContextToken); 38 | if (FAILED(_hr)) 39 | return _hr; 40 | 41 | IComThreadingInfo* _pComThreadingInfo; 42 | _hr = _pContextToken->QueryInterface(&_pComThreadingInfo); 43 | if (FAILED(_hr)) 44 | return _hr; 45 | 46 | _hr = _pComThreadingInfo->GetCurrentApartmentType(_pAptType); 47 | _pComThreadingInfo->Release(); 48 | if (FAILED(_hr)) 49 | return _hr; 50 | 51 | switch (*_pAptType) 52 | { 53 | case APTTYPE_STA: 54 | *_pAptQualifier = APTTYPEQUALIFIER_APPLICATION_STA; 55 | break; 56 | case APTTYPE_MTA: 57 | // todo: 无法区分: 58 | // APTTYPEQUALIFIER_NONE 59 | // APTTYPEQUALIFIER_IMPLICIT_MTA 60 | break; 61 | case APTTYPE_NA: 62 | // todo: 无法区分 63 | // APTTYPEQUALIFIER_NA_ON_MTA 64 | // APTTYPEQUALIFIER_NA_ON_STA 65 | // APTTYPEQUALIFIER_NA_ON_IMPLICIT_MTA 66 | // APTTYPEQUALIFIER_NA_ON_MAINSTA 67 | break; 68 | case APTTYPE_MAINSTA: 69 | break; 70 | default: 71 | break; 72 | } 73 | 74 | return S_OK; 75 | } 76 | #endif 77 | 78 | 79 | #if (YY_Thunks_Target < __WindowsNT6_3) 80 | 81 | // 最低受支持的客户端 Windows 8.1 [桌面应用 |UWP 应用] 82 | // 最低受支持的服务器 Windows Server 2012 R2[桌面应用 | UWP 应用] 83 | __DEFINE_THUNK( 84 | ole32, 85 | 16, 86 | HRESULT, 87 | WINAPI, 88 | RoGetAgileReference, 89 | _In_ enum AgileReferenceOptions _eOptions, 90 | _In_ REFIID _Id, 91 | _In_ IUnknown* pUnk, 92 | _COM_Outptr_ IAgileReference** _ppAgileReference 93 | ) 94 | { 95 | if (const auto _pfnRoGetAgileReference = try_get_RoGetAgileReference()) 96 | { 97 | return _pfnRoGetAgileReference(_eOptions, _Id, pUnk, _ppAgileReference); 98 | } 99 | 100 | if (!_ppAgileReference) 101 | return E_POINTER; 102 | 103 | *_ppAgileReference = nullptr; 104 | if (!pUnk) 105 | return E_POINTER; 106 | 107 | return E_NOINTERFACE; 108 | } 109 | #endif 110 | 111 | 112 | #if (YY_Thunks_Target < __WindowsNT6_2) 113 | 114 | // 最低受支持的客户端 Windows 8 [桌面应用 |UWP 应用] 115 | // 最低受支持的服务器 Windows Server 2012 [桌面应用 | UWP 应用] 116 | __DEFINE_THUNK( 117 | ole32, 118 | 4, 119 | HRESULT, 120 | WINAPI, 121 | CoIncrementMTAUsage, 122 | _Out_ CO_MTA_USAGE_COOKIE* _pCookie 123 | ) 124 | { 125 | if (const auto _pfnCoIncrementMTAUsage = try_get_CoIncrementMTAUsage()) 126 | { 127 | return _pfnCoIncrementMTAUsage(_pCookie); 128 | } 129 | 130 | if (!_pCookie) 131 | return E_POINTER; 132 | 133 | *_pCookie = nullptr; 134 | 135 | auto _pSharedData = GetYY_ThunksSharedData(); 136 | 137 | if (_pSharedData->bHasCoInitializeMultithreaded) 138 | { 139 | *_pCookie = (CO_MTA_USAGE_COOKIE)_pSharedData; 140 | return S_OK; 141 | } 142 | 143 | HANDLE _hTimer = nullptr; 144 | auto _bRet = CreateTimerQueueTimer( 145 | &_hTimer, 146 | nullptr, 147 | [](PVOID _pUserData, BOOLEAN) 148 | { 149 | auto _pSharedData = GetYY_ThunksSharedData(); 150 | 151 | if (_pSharedData->bHasCoInitializeMultithreaded) 152 | { 153 | return; 154 | } 155 | 156 | auto _hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); 157 | if (SUCCEEDED(_hr)) 158 | { 159 | _pSharedData->bHasCoInitializeMultithreaded = TRUE; 160 | } 161 | 162 | return; 163 | }, 164 | nullptr, 165 | 0, 166 | 0, 167 | WT_EXECUTEINTIMERTHREAD); 168 | 169 | if (!_bRet) 170 | { 171 | return E_FAIL; 172 | } 173 | 174 | HRESULT _hr = E_FAIL; 175 | 176 | for (int i = 0; i != 10; i++) 177 | { 178 | if (_pSharedData->bHasCoInitializeMultithreaded) 179 | { 180 | *_pCookie = (CO_MTA_USAGE_COOKIE)_pSharedData; 181 | _hr = S_OK; 182 | break; 183 | } 184 | 185 | Sleep(1); 186 | } 187 | 188 | DeleteTimerQueueTimer(nullptr, _hTimer, nullptr); 189 | return _hr; 190 | } 191 | #endif 192 | 193 | 194 | #if (YY_Thunks_Target < __WindowsNT6_2) 195 | 196 | // 最低受支持的客户端 Windows 8 [桌面应用 |UWP 应用] 197 | // 最低受支持的服务器 Windows Server 2012 [桌面应用 | UWP 应用] 198 | __DEFINE_THUNK( 199 | ole32, 200 | 4, 201 | HRESULT, 202 | WINAPI, 203 | CoDecrementMTAUsage, 204 | _Out_ CO_MTA_USAGE_COOKIE _hCookie 205 | ) 206 | { 207 | if (const auto _pfnCoDecrementMTAUsage = try_get_CoDecrementMTAUsage()) 208 | { 209 | return _pfnCoDecrementMTAUsage(_hCookie); 210 | } 211 | 212 | if (_hCookie != reinterpret_cast(GetYY_ThunksSharedData())) 213 | return E_POINTER; 214 | 215 | return S_OK; 216 | } 217 | #endif 218 | } 219 | --------------------------------------------------------------------------------