diff --git a/.editorconfig b/.editorconfig
index 96e3729..eb21893 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -14,3 +14,6 @@ indent_size = 4
[*.{vcxproj,xml,nuspec,targets}]
indent_style = space
indent_size = 2
+
+[*.cmd]
+charset = unset
diff --git a/.github/workflows/Build&Test.yml b/.github/workflows/Build&Test.yml
index f6fe6c5..a746482 100644
--- a/.github/workflows/Build&Test.yml
+++ b/.github/workflows/Build&Test.yml
@@ -132,13 +132,13 @@ jobs:
$RunFaild = 0
- &vstest.console src\Release\YY-Thunks.UnitTest.dll "/logger:trx;LogFileName=UnitTestWin32.trx" "/Blame:CollectDump;CollectAlways=false;DumpType=full /Diag:TestResults\Win32.log"
+ &vstest.console src\Release\YY-Thunks.UnitTest.dll "/logger:trx;LogFileName=UnitTestWin32.trx" "/Blame:CollectDump;CollectAlways=false;DumpType=full" "/Diag:TestResults\Win32.log"
if($lastexitcode -ne 0)
{
$RunFaild = 1
}
- &vstest.console src\x64\Release\YY-Thunks.UnitTest.dll "/logger:trx;LogFileName=UnitTestWin64.trx" "/Blame:CollectDump;CollectAlways=false;DumpType=full /Diag:TestResults\Win64.log"
+ &vstest.console src\x64\Release\YY-Thunks.UnitTest.dll "/logger:trx;LogFileName=UnitTestWin64.trx" "/Blame:CollectDump;CollectAlways=false;DumpType=full" "/Diag:TestResults\Win64.log"
if($lastexitcode -ne 0)
{
$RunFaild = 1
diff --git a/NuGet/build/native/YY-Thunks.targets b/NuGet/build/native/YY-Thunks.targets
index 81e2868..592bdba 100644
--- a/NuGet/build/native/YY-Thunks.targets
+++ b/NuGet/build/native/YY-Thunks.targets
@@ -10,6 +10,7 @@
5.01
5.02
$(MSBuildThisFileDirectory)objs\$(PlatformShortName)\$(YY_Thunks_File);%(AdditionalDependencies)
+ DllMainCRTStartupForYY_Thunks
@@ -21,4 +22,4 @@
-
\ No newline at end of file
+
diff --git a/ReadMe.md b/Readme.ocs.md
similarity index 89%
rename from ReadMe.md
rename to Readme.ocs.md
index a7b0d2f..6c67c15 100644
--- a/ReadMe.md
+++ b/Readme.ocs.md
@@ -6,6 +6,8 @@
[](https://www.nuget.org/packages/YY-Thunks)
[](https://github.com/Chuyu-Team/YY-Thunks/actions/workflows/Build&Test.yml)
+- [英语](Readme.md)
+
## 1. 关于 YY-Thunks
众所周知,从 Windows 的每次更新又会新增大量 API,这使得兼容不同版本的 Windows
@@ -22,8 +24,20 @@ YY-Thunks(鸭船),存在的目的就是抹平不同系统的差异,编
### 1.1. 原理
使用 `LoadLibrary` 以及 `GetProcAddress` 动态加载 API,不存在时做出补偿措施,
-最大限度模拟原始 API 行为,让你的程序正常运行。
+最大限度模拟原始 API 行为,让你的程序正常运行。大概就像下面这个`GetTickCount64`函数:
+```cpp
+// 注意:Windows XP 不支持 GetTickCount64
+ULONGLONG WINAPI GetTickCount64(VOID)
+{
+ if (auto const _pfnGetTickCount64 = try_get_GetTickCount64())
+ {
+ return _pfnGetTickCount64();
+ }
+ // Fallback
+ return GetTickCount();
+}
+```
### 1.2. 亮点
* 更快!更安全!`鸭船`内建2级缓存以及按需加载机制,同时自动加密所有函数指针,
@@ -57,7 +71,8 @@ YY-Thunks(鸭船),存在的目的就是抹平不同系统的差异,编
2. 【链接器】-【输入】-【附加依赖项】,添加
`objs\$(PlatformShortName)\YY_Thunks_for_WinXP.obj`。
3. 【链接器】-【系统】-【所需的最低版本】,根据实际情况填写 `5.01`(WinXP 32位) 或者 `5.02`(WinXP x64、2003)。
-4. 重新编译代码。
+4. 如果是编译DLL,那么【链接器】-【高级】-【自定义入口点】更改为`DllMainCRTStartupForYY_Thunks`(不这样做XP下使用thread_local可能崩溃!)
+5. 重新编译代码。
> 温馨提示:如果需要兼容 Vista,【所需的最低版本】无需修改,但是【附加依赖项】请选择
`objs\$(PlatformShortName)\YY_Thunks_for_Vista.obj`。
diff --git a/src/Build.cmd b/src/Build.cmd
index cb536be..724119f 100644
--- a/src/Build.cmd
+++ b/src/Build.cmd
@@ -1,8 +1,8 @@
-@echo off
+@echo off
setlocal
-::需要设置LibMaker.exe路径到环境变量Path。
-::如果你需要LibMaker.exe,请自行到 初雨开源项目交流QQ群(633710173)群文件中下载。
+::ÐèҪÉèÖÃLibMaker.exe·¾¶µ½»·¾³±äÁ¿Path¡£
+::Èç¹ûÄãÐèҪLibMaker.exe£¬Çë×ÔÐе½ ³õÓ꿪ԴÏîĿ½»Á÷QQȺ£¨633710173£©ȺÎļþÖÐÏÂÔء£
pushd "%~dp0.."
@@ -12,7 +12,7 @@ if "%Platform%"=="" set Platform=x86
md "objs\\%Platform%"
-::先生成 YY_Thunks_List.hpp
+::ÏÈÉú³É YY_Thunks_List.hpp
msbuild "%~dp0YY-Thunks.UnitTest\YY-Thunks.UnitTest.vcxproj" -t:Build_YY_Thunks_List_hpp
call:Build%Platform%
@@ -26,8 +26,8 @@ goto:eof
:BuildObj
cl /O1 /Os /Oi /GS- /std:c++17 /arch:IA32 /Z7 /MT /Fo"objs\\%Platform%\\%1" /Zl /c /D "NDEBUG" /D "YY_Thunks_Support_Version=%2" "%~dp0Thunks\YY_Thunks.cpp"
-::进行函数名称进行修正 __imp__%s_%u -> __imp__%s@%u
-LibMaker.exe FixObj "%~dp0..\\objs\\%Platform%\\%1" /WeakExternFix:__security_cookie=%PointType% /WeakExternFix:__YY_Thunks_Process_Terminating=4 /WeakExternFix:__acrt_atexit_table=%PointType%
+::½øÐк¯ÊýÃû³ƽøÐÐÐÞÕý __imp__%s_%u -> __imp__%s@%u
+LibMaker.exe FixObj "%~dp0..\\objs\\%Platform%\\%1" /WeakExternFix:__security_cookie=%PointType% /WeakExternFix:__YY_Thunks_Process_Terminating=4 /WeakExternFix:__acrt_atexit_table=%PointType% /WeakExternFix:__pfnDllMainCRTStartupForYY_Thunks=%PointType%
LibMaker.exe AppendWeak /MACHINE:%Platform% /DEF:"%~dp0def\\%Platform%\\PSAPI2Kernel32.def" /OUT:"%~dp0..\\objs\\%Platform%\\%1"
diff --git a/src/Thunks/DllMainCRTStartup.hpp b/src/Thunks/DllMainCRTStartup.hpp
new file mode 100644
index 0000000..5cd2d57
--- /dev/null
+++ b/src/Thunks/DllMainCRTStartup.hpp
@@ -0,0 +1,463 @@
+#if defined(YY_Thunks_Implemented)
+
+namespace YY::Thunks::internal
+{
+ extern "C" BOOL WINAPI _DllMainCRTStartup(
+ HINSTANCE const instance,
+ DWORD const reason,
+ LPVOID const reserved
+ );
+
+ // 如果希望自定义函数入口点,可以设置此函数
+ extern "C" extern decltype(_DllMainCRTStartup)* const __pfnDllMainCRTStartupForYY_Thunks;
+
+#if YY_Thunks_Support_Version < NTDDI_WIN6
+ extern "C" ULONG _tls_index;
+ static ULONG _tls_index_old;
+#ifdef _WIN64
+ extern "C" const IMAGE_TLS_DIRECTORY64 _tls_used;
+#else
+ extern "C" const IMAGE_TLS_DIRECTORY _tls_used;
+#endif
+
+#pragma section(".CRT$XLB", long, read) // First MS CRT Loader TLS Callback
+
+ enum class TlsMode
+ {
+ None,
+ ByFirstCallback,
+ ByDllMainCRTStartupForYY_Thunks,
+ };
+
+ // 用来记录第一次Tls回调的时机
+ // 如果来自ByFirstCallback,那么说明当前模块的TLS功能完全正常(模块是EXE或者来自于隐式依赖的DLL),YY-Thunks无需额外修复
+ // 如果来自ByDllMainCRTStartupForYY_Thunks,那么说明它是动态加载的DLL,TLS没有初始化
+ static TlsMode g_TlsMode;
+
+ static
+ VOID
+ NTAPI
+ FirstCallback(
+ PVOID DllHandle,
+ DWORD Reason,
+ PVOID Reserved
+ )
+ {
+ if (DLL_PROCESS_ATTACH == Reason)
+ {
+ if (g_TlsMode == TlsMode::None)
+ {
+ g_TlsMode = TlsMode::ByFirstCallback;
+ }
+ }
+ }
+
+ struct TlsRawItem
+ {
+ TlsRawItem* pNext;
+ TlsRawItem* pPrev;
+ BYTE* pBase;
+ void** pOldTlsIndex;
+ };
+ static thread_local TlsRawItem s_CurrentNode;
+
+ static volatile LONG uStatus = 0;
+ static TlsRawItem* volatile pRoot = nullptr;
+
+ static ULONG __fastcall GetTlsIndexBufferCount(TEB* _pTeb)
+ {
+ auto _ppThreadLocalStoragePointer = (void**)_pTeb->ThreadLocalStoragePointer;
+ if (!_ppThreadLocalStoragePointer)
+ return 0;
+
+ return HeapSize(_pTeb->ProcessEnvironmentBlock->ProcessHeap, 0, _ppThreadLocalStoragePointer) / sizeof(void*);
+ }
+ static PVOID NTAPI RtlImageDirectoryEntryToData(
+ __in PVOID pBaseAddress,
+ __in ULONG dwDirectory,
+ __out PULONG pSize
+ )
+ {
+ auto _pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress;
+ auto _pNtHerder = reinterpret_cast(PBYTE(pBaseAddress) + _pDosHeader->e_lfanew);
+ auto& _DataDirectory = _pNtHerder->OptionalHeader.DataDirectory[dwDirectory];
+
+ *pSize = _DataDirectory.Size;
+ if (_DataDirectory.Size == 0 || _DataDirectory.VirtualAddress == 0)
+ return nullptr;
+
+ return PBYTE(pBaseAddress) + _DataDirectory.VirtualAddress;
+ }
+
+ static ULONG __fastcall GetMaxTlsIndex() noexcept
+ {
+ ULONG uMaxTlsIndex = 0;
+
+ auto _pLdr = (_PEB_LDR_DATA_XP*)(TEB*)NtCurrentTeb()->ProcessEnvironmentBlock->Ldr;
+ auto _pHerder = &_pLdr->InLoadOrderModuleList;
+ for (auto _pItem = _pHerder->Flink; _pItem != _pHerder; )
+ {
+ auto _pEntry = CONTAINING_RECORD(_pItem, _LDR_DATA_TABLE_ENTRY_XP, InLoadOrderModuleList);
+ _pItem = _pItem->Flink;
+
+ __try
+ {
+ // XP不会为动态加载的DLL设置这个字段(符合预期,毕竟没有真的初始化)
+ /*if (!_pEntry->TlsIndex)
+ continue;*/
+ ULONG TlsSize;
+ auto pTlsImage = (PIMAGE_TLS_DIRECTORY)RtlImageDirectoryEntryToData(
+ _pEntry->BaseAddress,
+ IMAGE_DIRECTORY_ENTRY_TLS,
+ &TlsSize);
+
+ if (pTlsImage == nullptr || pTlsImage->AddressOfIndex == 0)
+ {
+ continue;
+ }
+
+ const auto _TlsIndex = *(ULONG*)pTlsImage->AddressOfIndex;
+ if (uMaxTlsIndex < _TlsIndex)
+ uMaxTlsIndex = _TlsIndex;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ }
+
+ return uMaxTlsIndex;
+
+ }
+
+ static SYSTEM_PROCESS_INFORMATION* __fastcall GetCurrentProcessInfo(StringBuffer& _szBuffer)
+ {
+ const auto _pfnNtQuerySystemInformation = try_get_NtQuerySystemInformation();
+ if (!_pfnNtQuerySystemInformation)
+ return nullptr;
+
+ ULONG _cbBuffer = max(4096, _szBuffer.uBufferLength);
+ ULONG _cbRet = 0;
+ for (;;)
+ {
+ auto _pBuffer = _szBuffer.GetBuffer(_cbBuffer);
+ if (!_pBuffer)
+ return nullptr;
+
+ LONG _Status = _pfnNtQuerySystemInformation(SystemProcessInformation, _pBuffer, _cbBuffer, &_cbRet);
+ if (_Status >= 0)
+ break;
+
+ if (STATUS_INFO_LENGTH_MISMATCH != _Status)
+ return nullptr;
+
+ _cbBuffer = _cbRet;
+ }
+
+ const auto _uCurrentProcessId = GetCurrentProcessId();
+ auto _pInfo = (SYSTEM_PROCESS_INFORMATION*)_szBuffer.GetBuffer(0);
+ for (;;)
+ {
+ if (_pInfo->ProcessId == (HANDLE)_uCurrentProcessId)
+ return _pInfo;
+
+ if (_pInfo->NextEntryDelta == 0)
+ break;
+
+ _pInfo = reinterpret_cast(reinterpret_cast(_pInfo) + _pInfo->NextEntryDelta);
+ }
+
+ return nullptr;
+ }
+
+ static bool __fastcall AllocTlsData(TEB* _pTeb = nullptr) noexcept
+ {
+ if (_tls_index == 0)
+ return false;
+ if (!_pTeb)
+ _pTeb = (TEB*)NtCurrentTeb();
+
+ auto _pTlsIndex = (void**)_pTeb->ThreadLocalStoragePointer;
+ void** _pOldTlsIndex = nullptr;
+ auto _cTlsIndexLength = GetTlsIndexBufferCount(_pTeb);
+ if (_cTlsIndexLength <= _tls_index)
+ {
+ // Index不足,扩充……
+ auto _cNewTlsIndexLength = _tls_index + 128;
+ auto _pNewTlsIndex = (void**)Alloc(_cNewTlsIndexLength * sizeof(void*), HEAP_ZERO_MEMORY);
+ if (!_pNewTlsIndex)
+ return false;
+
+ memcpy(_pNewTlsIndex, _pTlsIndex, _cTlsIndexLength * sizeof(void*));
+ if ((void*)InterlockedCompareExchange((uintptr_t*)&_pTeb->ThreadLocalStoragePointer, (uintptr_t)_pNewTlsIndex, (uintptr_t)_pTlsIndex) != _pTlsIndex)
+ {
+ Free(_pNewTlsIndex);
+ return false;
+ }
+
+ if (_pTeb == (TEB*)NtCurrentTeb())
+ {
+ Free(_pTlsIndex);
+ }
+ else
+ {
+ // 其他线程的无法直接释放,玩意缓存里恰好正在使用这块那么会崩溃的
+ _pOldTlsIndex = _pTlsIndex;
+ }
+ _pTlsIndex = _pNewTlsIndex;
+ }
+ const size_t _cbTlsRaw = _tls_used.EndAddressOfRawData - _tls_used.StartAddressOfRawData;
+ auto _pRawTlsData = (BYTE*)Alloc(_cbTlsRaw, HEAP_ZERO_MEMORY);
+ if (!_pRawTlsData)
+ {
+ // 释放不是安全的,极小的概率可能野,但是现在现在就这样吧。
+ Free(_pOldTlsIndex);
+ return false;
+ }
+
+ memcpy(_pRawTlsData, (void*)_tls_used.StartAddressOfRawData, _cbTlsRaw);
+ InterlockedExchange((uintptr_t*)&_pTlsIndex[_tls_index], (uintptr_t)_pRawTlsData);
+
+ s_CurrentNode.pBase = _pRawTlsData;
+ s_CurrentNode.pOldTlsIndex = _pOldTlsIndex;
+
+ for (;;)
+ {
+ if (!_interlockedbittestandset(&uStatus, 0))
+ {
+ s_CurrentNode.pNext = pRoot;
+ if (pRoot)
+ {
+ pRoot->pPrev = &s_CurrentNode;
+ }
+ pRoot = &s_CurrentNode;
+ _interlockedbittestandreset(&uStatus, 0);
+ break;
+ }
+ }
+ return true;
+ }
+
+ static void __fastcall FreeTlsData()
+ {
+ if (_tls_index == 0)
+ return;
+ auto _pTeb = (TEB*)NtCurrentTeb();
+ if (_tls_index >= GetTlsIndexBufferCount(_pTeb))
+ return;
+
+ auto _ppTlsIndex = (void**)_pTeb->ThreadLocalStoragePointer;
+ if (_ppTlsIndex[_tls_index] == nullptr)
+ return;
+
+ if (s_CurrentNode.pBase != _ppTlsIndex[_tls_index])
+ return;
+
+ if (s_CurrentNode.pOldTlsIndex)
+ {
+ Free(s_CurrentNode.pOldTlsIndex);
+ s_CurrentNode.pOldTlsIndex = nullptr;
+ }
+
+ s_CurrentNode.pBase = nullptr;
+
+ for (;;)
+ {
+ if (!_interlockedbittestandset(&uStatus, 0))
+ {
+ auto pPrev = s_CurrentNode.pPrev;
+ auto pNext = s_CurrentNode.pNext;
+ if (pPrev)
+ {
+ pPrev->pNext = pNext;
+ }
+ else
+ {
+ pRoot = pNext;
+ }
+
+ if (pNext)
+ {
+ pNext->pPrev = pPrev;
+ }
+ _interlockedbittestandreset(&uStatus, 0);
+
+ auto _pTlsRawData = (void*)InterlockedExchange((uintptr_t*)&_ppTlsIndex[_tls_index], 0);
+ Free(_pTlsRawData);
+ break;
+ }
+ }
+ }
+
+ static bool __fastcall CreateTlsIndex() noexcept
+ {
+ if (_tls_index != 0)
+ return false;
+
+ _tls_index = GetMaxTlsIndex() + 1;
+ AllocTlsData((TEB*)NtCurrentTeb());
+
+ // 同时给所有历史的线程追加新DLL产生的Tls内存
+ do
+ {
+ const auto _pfnNtQueryInformationThread = try_get_NtQueryInformationThread();
+ if (!_pfnNtQueryInformationThread)
+ break;
+
+ StringBuffer _Buffer;
+ auto _pProcessInfo = GetCurrentProcessInfo(_Buffer);
+ if (!_pProcessInfo)
+ {
+ break;
+ }
+
+ const auto _uCurrentThreadId = GetCurrentThreadId();
+
+ for (ULONG i = 0; i != _pProcessInfo->ThreadCount; ++i)
+ {
+ auto& _Thread = _pProcessInfo->Threads[i];
+
+ if (_uCurrentThreadId == (DWORD)_Thread.ClientId.UniqueThread)
+ continue;
+
+ auto _hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, (DWORD)_Thread.ClientId.UniqueThread);
+ if (!_hThread)
+ {
+ continue;
+ }
+
+ THREAD_BASIC_INFORMATION _ThreadBasicInfo = {};
+ LONG _Status = _pfnNtQueryInformationThread(_hThread, ThreadBasicInformation, &_ThreadBasicInfo, sizeof(_ThreadBasicInfo), nullptr);
+ if (_Status >= 0 && _ThreadBasicInfo.TebBaseAddress)
+ {
+ AllocTlsData((TEB*)_ThreadBasicInfo.TebBaseAddress);
+ }
+
+ CloseHandle(_hThread);
+ }
+ } while (false);
+
+ return true;
+ }
+
+ static void __fastcall FreeTlsIndex() noexcept
+ {
+ if (_tls_index == 0)
+ return;
+
+ // 故意不加锁……
+ for (auto _pItem = pRoot; _pItem;)
+ {
+ auto _pNext = _pItem->pNext;
+ if (_pItem->pOldTlsIndex)
+ {
+ Free(_pItem->pOldTlsIndex);
+ _pItem->pOldTlsIndex = nullptr;
+ }
+ Free(_pItem->pBase);
+ _pItem = _pNext;
+ }
+ }
+
+ static void __fastcall CallTlsCallback(
+ HINSTANCE const _hInstance,
+ DWORD const _uReason)
+ {
+ if (_tls_index == 0)
+ return;
+
+ auto _pTeb = (TEB*)NtCurrentTeb();
+ auto _ppThreadLocalStoragePointer = (void**)_pTeb->ThreadLocalStoragePointer;
+ if (!_ppThreadLocalStoragePointer)
+ return;
+
+ if (_tls_index >= GetTlsIndexBufferCount(_pTeb))
+ return;
+
+ if (!_ppThreadLocalStoragePointer[_tls_index])
+ return;
+
+ __try
+ {
+ auto _pfnTlsCallbacks = reinterpret_cast(_tls_used.AddressOfCallBacks);
+ if (_pfnTlsCallbacks)
+ {
+ for (; *_pfnTlsCallbacks; ++_pfnTlsCallbacks)
+ {
+ (*_pfnTlsCallbacks)(_hInstance, _uReason, nullptr);
+ }
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ }
+#endif // YY_Thunks_Support_Version < NTDDI_WIN6
+
+ // 我们始终提供DllMainCRTStartupForYY_Thunks函数,虽然理论上Vista(包含)以上就不用修正了,但是为了做到体验统一
+ // 避免Vista模式设置 DllMainCRTStartupForYY_Thunks 就发生链接失败问题。
+ // 这个函数的存在意义是修复Windows XP系统显式加载的DLL里无法使用TLS问题。
+ extern "C" BOOL WINAPI DllMainCRTStartupForYY_Thunks(
+ HINSTANCE const _hInstance,
+ DWORD const _uReason,
+ LPVOID const _pReserved
+ )
+ {
+ const auto _pfnDllMainCRTStartup = __pfnDllMainCRTStartupForYY_Thunks ? __pfnDllMainCRTStartupForYY_Thunks : &_DllMainCRTStartup;
+
+#if YY_Thunks_Support_Version < NTDDI_WIN6
+ __declspec(allocate(".CRT$XLB")) static const PIMAGE_TLS_CALLBACK s_FirstCallback = FirstCallback;
+ __foreinclude(s_FirstCallback);
+ __foreinclude(_tls_used);
+ if (internal::GetSystemVersion() < internal::MakeVersion(6, 0))
+ {
+ // Vista开始已经可以动态的处理TLS问题了,所以这里只针对老系统处理。
+ switch (_uReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ if (g_TlsMode == TlsMode::None)
+ {
+ g_TlsMode = TlsMode::ByDllMainCRTStartupForYY_Thunks;
+ }
+ _tls_index_old = _tls_index;
+ if (_tls_index == 0 && g_TlsMode == TlsMode::ByDllMainCRTStartupForYY_Thunks)
+ {
+ CreateTlsIndex();
+ return _pfnDllMainCRTStartup(_hInstance, _uReason, _pReserved);
+ }
+ break;
+ case DLL_THREAD_ATTACH:
+ if (_tls_index_old == 0 && g_TlsMode == TlsMode::ByDllMainCRTStartupForYY_Thunks)
+ {
+ AllocTlsData();
+ CallTlsCallback(_hInstance, _uReason);
+ return _pfnDllMainCRTStartup(_hInstance, _uReason, _pReserved);
+ }
+ break;
+ case DLL_THREAD_DETACH:
+ if (_tls_index_old == 0 && g_TlsMode == TlsMode::ByDllMainCRTStartupForYY_Thunks)
+ {
+ CallTlsCallback(_hInstance, _uReason);
+ auto _bRet = _pfnDllMainCRTStartup(_hInstance, _uReason, _pReserved);
+ FreeTlsData();
+ return _bRet;
+ }
+ break;
+ case DLL_PROCESS_DETACH:
+#if (YY_Thunks_Support_Version < NTDDI_WINXP)
+ __YY_Thunks_Process_Terminating = _pReserved != nullptr;
+#endif
+ if (_tls_index_old == 0 && g_TlsMode == TlsMode::ByDllMainCRTStartupForYY_Thunks)
+ {
+ CallTlsCallback(_hInstance, _uReason);
+ auto _bRet = _pfnDllMainCRTStartup(_hInstance, _uReason, _pReserved);
+ FreeTlsIndex();
+ return _bRet;
+ }
+ break;
+ }
+ }
+#endif
+ return _pfnDllMainCRTStartup(_hInstance, _uReason, _pReserved);
+ }
+}
+#endif
diff --git a/src/Thunks/YY_Thunks.h b/src/Thunks/YY_Thunks.h
index a6b6df5..2f209bd 100644
--- a/src/Thunks/YY_Thunks.h
+++ b/src/Thunks/YY_Thunks.h
@@ -174,11 +174,11 @@ static __forceinline unsigned __int64 __fastcall __crt_rotate_pointer_value(unsi
#ifdef _WIN64
#define __foreinclude(p) \
__pragma(warning(suppress:6031)) \
- _bittest64(reinterpret_cast(&p), 0)
+ _bittest64((LONG_PTR*)(&p), 0)
#else
#define __foreinclude(p) \
__pragma(warning(suppress:6031)) \
- _bittest(reinterpret_cast(&p), 0)
+ _bittest((LONG_PTR*)(&p), 0)
#endif
diff --git a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj
index 5f2fd8f..b7ce630 100644
--- a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj
+++ b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj
@@ -110,6 +110,7 @@
true
true
$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
+ DllMainCRTStartupForYY_Thunks
@@ -128,6 +129,7 @@
Windows
$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
+ DllMainCRTStartupForYY_Thunks
@@ -146,6 +148,7 @@
Windows
$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
+ DllMainCRTStartupForYY_Thunks
@@ -168,6 +171,7 @@
true
true
$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
+ DllMainCRTStartupForYY_Thunks
@@ -222,6 +226,7 @@
+
diff --git a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters
index b34511e..3cbda50 100644
--- a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters
+++ b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters
@@ -308,6 +308,9 @@
Thunks
+
+ Thunks
+
diff --git a/src/YY-Thunks.UnitTest/weak.c b/src/YY-Thunks.UnitTest/weak.c
index d5e8855..6cd4b85 100644
--- a/src/YY-Thunks.UnitTest/weak.c
+++ b/src/YY-Thunks.UnitTest/weak.c
@@ -2,3 +2,5 @@
const int __YY_Thunks_Process_Terminating;
const void* __acrt_atexit_table;
+
+const void* __pfnDllMainCRTStartupForYY_Thunks;