Fea #29, 消除Chrome中Windows 7不支持的部分API

* PowerRegisterSuspendResumeNotification
* PowerUnregisterSuspendResumeNotification
* RegisterSuspendResumeNotification
* UnregisterSuspendResumeNotification
This commit is contained in:
mingkuang
2023-03-17 20:56:41 +08:00
parent cc1e3ca8a3
commit d58e79deda
8 changed files with 726 additions and 0 deletions
+4
View File
@@ -308,6 +308,8 @@
| ---- | -----------
| PowerDeterminePlatformRole | 不存在时,返回PlatformRoleDesktop。
| PowerDeterminePlatformRoleEx | 不存在时,调用PlatformRoleDesktop。
| PowerRegisterSuspendResumeNotification | 不存在时,使用窗口模拟。
| PowerUnregisterSuspendResumeNotification | 内部实现。
## psapi.dll
| 函数 | Fallback
@@ -364,6 +366,8 @@
| GetSystemMetricsForDpi | 不存在时,调用GetSystemMetrics。
| AdjustWindowRectExForDpi | 不存在时,调用AdjustWindowRectEx。
| SystemParametersInfoForDpi | 不存在时,调用SystemParametersInfoW。
| RegisterSuspendResumeNotification | 不存在时,使用窗口模拟。
| UnregisterSuspendResumeNotification | 不存在时,内部实现。
## userenv.dll
| 函数 | Fallback
+437
View File
@@ -0,0 +1,437 @@
#pragma once
namespace YY
{
namespace Thunks
{
namespace internal
{
typedef BOOL(WINAPI TaskCallback)(
struct TaskItem* _pWork,
UINT _uMsg,
WPARAM _wParam,
LPARAM _lParam
);
struct TaskItem
{
TaskItem* pNext;
TaskCallback* pfnCallback;
};
constexpr auto WM_RUNNER_CALL = WM_USER + 100;
struct ThreadRunner
{
TaskItem* pCallbackList;
volatile TaskItem* pPendingCallbackList;
volatile HWND hWnd;
volatile ULONG uRef;
static LRESULT WINAPI WindowProcW(
HWND _hWnd,
UINT _uMsg,
WPARAM _wParam,
LPARAM _lParam
)
{
if (_uMsg == WM_CLOSE)
{
auto _pData = (ThreadRunner*)GetWindowLongPtrW(_hWnd, GWLP_USERDATA);
if (_pData)
{
if (!_pData->TryClean())
{
if (_wParam == 0)
{
return 0;
}
else
{
// 表示强制清理,这时虽然上面释放失败,但是为了避免崩溃
// 我们仅仅停止窗口。
_pData->hWnd = NULL;
}
}
}
DestroyWindow(_hWnd);
return 0;
}
else if (_uMsg == WM_DESTROY)
{
PostQuitMessage(0);
}
else
{
auto _pData = (ThreadRunner*)GetWindowLongPtrW(_hWnd, GWLP_USERDATA);
if (_pData && (_pData->pCallbackList || _pData->pPendingCallbackList))
{
const auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap;
// 进行CallBack
TaskItem* _pLastCallbackPrev = (TaskItem*)&_pData->pCallbackList;
for (auto _pCallbackPrev = _pLastCallbackPrev; _pCallbackPrev;)
{
if (!_pCallbackPrev->pNext)
break;
auto _pNext = _pCallbackPrev->pNext;
if (!_pNext)
break;
if (auto _pfnCallback = _pNext->pfnCallback)
{
_pLastCallbackPrev = _pNext;
_pfnCallback(_pNext, _uMsg, _wParam, _lParam);
}
else
{
_pCallbackPrev->pNext = _pNext->pNext;
// 需要移除
HeapFree(_hProcessHeap, 0, _pNext);
}
}
// 合并 pPendingCallbackList 至 pCallbackList
auto _pPendingCallbackList = (TaskItem*)InterlockedExchangePointer((PVOID*)&_pData->pPendingCallbackList, NULL);
if (_pPendingCallbackList)
{
// 将顺序颠倒处理,因为插入后顺序就是倒的
auto _pPendingCallbackListFirst = _pPendingCallbackList;
for (; _pPendingCallbackList->pNext; _pPendingCallbackList = _pPendingCallbackList->pNext)
{
_pPendingCallbackListFirst->pNext = _pPendingCallbackList->pNext;
_pPendingCallbackListFirst = _pPendingCallbackList->pNext;
}
_pPendingCallbackList->pNext = nullptr;
_pLastCallbackPrev->pNext = _pPendingCallbackListFirst;
// 开始便利 新增的Callback元素
for (auto _pCallbackPrev = _pLastCallbackPrev; _pCallbackPrev;)
{
if (!_pCallbackPrev->pNext)
break;
auto _pNext = _pCallbackPrev->pNext;
if (!_pNext)
break;
if (auto _pfnCallback = _pNext->pfnCallback)
{
_pLastCallbackPrev = _pNext;
_pfnCallback(_pNext, _uMsg, _wParam, _lParam);
}
else
{
_pCallbackPrev->pNext = _pNext->pNext;
// 需要移除
HeapFree(_hProcessHeap, 0, _pNext);
}
}
}
}
}
return ::DefWindowProcW(_hWnd, _uMsg, _wParam, _lParam);
}
bool AddRef()
{
auto _uCurrentRef = uRef;
for (;;)
{
if (_uCurrentRef == MAXUINT32)
{
SwitchToThread();
_uCurrentRef = uRef;
continue;
}
else if (_uCurrentRef == 0)
{
// 第一次,尝试加锁
const auto _uLastRef = InterlockedCompareExchange(&uRef, MAXUINT32, 0);
if (_uLastRef != 0)
{
_uCurrentRef = _uLastRef;
continue;
}
struct ThreadInfo
{
HANDLE hEvent;
ThreadRunner* pWork;
};
LSTATUS _lStatus = ERROR_SUCCESS;
ThreadInfo _Info = { NULL, this };
do
{
_Info.hEvent = CreateEventW(nullptr, FALSE, FALSE, NULL);
if (!_Info.hEvent)
{
_lStatus = GetLastError();
break;
}
// 成功锁定 开始创建创建
auto _hThread = CreateThread(
nullptr,
0,
[](LPVOID lpParameter) -> DWORD
{
auto& _Info = *(ThreadInfo*)lpParameter;
static bool bRegister = false;
if (!bRegister)
{
WNDCLASSW wc = {};
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = &DefWindowProcW;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = NULL;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = L"YY_Thunks_Work_Wnd";
if (RegisterClassW(&wc) == FALSE && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
return FALSE;
bRegister = true;
}
auto _hWnd = CreateWindowExW(WS_EX_NOACTIVATE, L"YY_Thunks_Work_Wnd", nullptr, WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
if (!_hWnd)
return GetLastError();
_Info.pWork->hWnd = _hWnd;
SetWindowLongPtrW(_hWnd, GWLP_USERDATA, (LONG_PTR)_Info.pWork);
SetWindowLongPtrW(_hWnd, GWLP_WNDPROC, (LONG_PTR)&ThreadRunner::WindowProcW);
SetEvent(_Info.hEvent);
MSG _Msg;
for (;;)
{
auto _bRet = GetMessageW(&_Msg, NULL, 0, 0);
if (_bRet == -1)
continue;
if (!_bRet)
break;
TranslateMessage(&_Msg);
DispatchMessageW(&_Msg);
}
return 0;
},
&_Info,
0,
nullptr);
if (!_hThread)
{
_lStatus = GetLastError();
break;
}
HANDLE _Handles[] = { _Info.hEvent, _hThread };
const auto _uResult = WaitForMultipleObjects(_countof(_Handles), _Handles, FALSE, 15 * 1000);
switch (_uResult)
{
case WAIT_OBJECT_0:
// 成功初始化完成
break;
case WAIT_OBJECT_0 + 1:
// 失败
_lStatus = ERROR_FUNCTION_FAILED;
GetExitCodeThread(_hThread, (DWORD*)&_lStatus);
break;
default:
_lStatus = ERROR_FUNCTION_FAILED;
break;
}
if(_hThread)
CloseHandle(_hThread);
} while (false);
if (_Info.hEvent)
{
CloseHandle(_Info.hEvent);
}
if (_lStatus == ERROR_SUCCESS)
{
// 成功处理!这里给窗口额外增加一次引用
InterlockedExchange(&uRef, 2);
break;
}
else
{
// 失败
InterlockedExchange(&uRef, 0);
return false;
}
}
else
{
// 尝试增加一次引用
const auto _uLastRef = InterlockedCompareExchange(&uRef, _uCurrentRef + 1, _uCurrentRef);
if (_uLastRef != _uCurrentRef)
{
_uCurrentRef = _uLastRef;
continue;
}
break;
}
}
return true;
}
void Release()
{
// 尝试锁定
auto _uCurrentRef = uRef;
for (;;)
{
if (_uCurrentRef == MAXUINT32)
{
// 已经锁定,稍后再试
SwitchToThread();
_uCurrentRef = uRef;
}
else if (_uCurrentRef == 0 || _uCurrentRef == 1)
{
// 当前没有引用!!!
break;
}
else
{
// 成功锁定,通知线程释放……
if (InterlockedDecrement(&uRef) == 1)
{
// 引用归 1,异步通知窗口尝试退出。
PostMessageW(hWnd, WM_CLOSE, 0, 0);
}
break;
}
}
}
bool AddTask(TaskItem* _pWork)
{
if (_pWork == nullptr || _pWork->pfnCallback == nullptr)
return false;
if (!AddRef())
return nullptr;
// 先添加到 pPendingCallbackList,然后工作线程会将结果合并到 pCallbackList
auto _pLast = (TaskItem*)pPendingCallbackList;
for (;;)
{
_pWork->pNext = _pLast;
auto _pLastLast = (TaskItem*)InterlockedCompareExchangePointer((PVOID*)&pPendingCallbackList, _pWork, _pLast);
if (_pLastLast == _pLast)
{
break;
}
_pLast = _pLastLast;
}
return true;
}
LSTATUS RemoveTask(TaskItem* _pWork)
{
if(!_pWork)
return ERROR_INVALID_PARAMETER;
// Callback设置为 null 后再适合的时机会自动删除
if (!InterlockedExchangePointer((PVOID*)&_pWork->pfnCallback, nullptr))
return ERROR_INVALID_PARAMETER;
Release();
return ERROR_SUCCESS;
}
bool TryClean()
{
const auto _uLastRef = InterlockedCompareExchange(&uRef, MAXUINT32, 1);
if (_uLastRef != 1)
{
// 引用已经重新增加,所以不需要删除了。
return false;
}
// 成功锁定,将一些关键变量重置
auto _hWnd = hWnd;
hWnd = NULL;
auto _pCallbackList = (TaskItem*)InterlockedExchangePointer((PVOID*)&pCallbackList, nullptr);
auto _pPendingCallbackList = (TaskItem*)InterlockedExchangePointer((PVOID*)&pPendingCallbackList, nullptr);
SetWindowLongPtrW(_hWnd, GWLP_USERDATA, NULL);
// 解锁
InterlockedExchange(&uRef, 0);
const auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap;
// 删除List内存
for (; _pCallbackList; )
{
auto _pNext = _pCallbackList->pNext;
HeapFree(_hProcessHeap, 0, _pCallbackList);
_pCallbackList = _pNext;
}
for (; _pPendingCallbackList; )
{
auto _pNext = _pPendingCallbackList->pNext;
HeapFree(_hProcessHeap, 0, _pPendingCallbackList);
_pPendingCallbackList = _pNext;
}
return true;
}
};
static ThreadRunner* __fastcall GetGlobalThreadRunner()
{
static ThreadRunner g_YYWork;
static LONG g_RunOnce;
if (g_RunOnce == 0)
{
if (!InterlockedBitTestAndSet(&g_RunOnce, 0))
{
atexit(
[]()
{
if (auto _hWnd = GetGlobalThreadRunner()->hWnd)
{
SendMessageW(_hWnd, WM_CLOSE, 1, 0);
}
});
}
}
return &g_YYWork;
}
}
}
}
+2
View File
@@ -339,6 +339,8 @@ namespace YY
} //namespace YY
#include "ThreadRunner.h"
//导入实际的实现
#define YY_Thunks_Implemented
#define __DEFINE_THUNK(_MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) \
+127
View File
@@ -10,6 +10,87 @@ namespace YY
{
namespace Thunks
{
#if (YY_Thunks_Support_Version < NTDDI_WIN8) && defined(YY_Thunks_Implemented)
static
DWORD
WINAPI
PowerRegisterSuspendResumeNotificationDownlevel(
_In_ DWORD _fFlags,
_In_ HANDLE _hRecipient,
_Out_ PHPOWERNOTIFY _phRegistrationHandle
)
{
if (!_phRegistrationHandle)
return ERROR_INVALID_PARAMETER;
*_phRegistrationHandle = NULL;
const auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap;
if (DEVICE_NOTIFY_CALLBACK == _fFlags)
{
auto _pDeviceNotifyInfo = (DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS*)_hRecipient;
if(!_pDeviceNotifyInfo)
return ERROR_INVALID_PARAMETER;
struct DeviceNotifyTaskItem : public internal::TaskItem
{
DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS Parameters;
};
auto _pTask = (DeviceNotifyTaskItem*)HeapAlloc(_hProcessHeap, 0, sizeof(DeviceNotifyTaskItem));
if (!_pTask)
return ERROR_OUTOFMEMORY;
_pTask->Parameters = *_pDeviceNotifyInfo;
_pTask->pfnCallback = [](
internal::TaskItem* _pWork,
UINT _uMsg,
WPARAM _wParam,
LPARAM _lParam) -> BOOL
{
auto _pWork2 = (DeviceNotifyTaskItem*)_pWork;
if (WM_POWERBROADCAST == _uMsg)
{
_pWork2->Parameters.Callback(_pWork2->Parameters.Context, _wParam, (PVOID)_lParam);
}
return TRUE;
};
if (internal::GetGlobalThreadRunner()->AddTask(_pTask))
{
*_phRegistrationHandle = _pTask;
return ERROR_SUCCESS;
}
HeapFree(_hProcessHeap, 0, _pTask);
return ERROR_OUTOFMEMORY;
}
else
{
return ERROR_INVALID_PARAMETER;
}
}
static
DWORD
WINAPI
PowerUnregisterSuspendResumeNotificationDownlevel(
_Inout_ HPOWERNOTIFY _hRegistrationHandle
)
{
if (!_hRegistrationHandle)
return ERROR_INVALID_PARAMETER;
return internal::GetGlobalThreadRunner()->RemoveTask((internal::TaskItem*)_hRegistrationHandle);
}
#endif // (YY_Thunks_Support_Version < NTDDI_WIN8) && defined(YY_Thunks_Implemented)
#if (YY_Thunks_Support_Version < NTDDI_WIN8)
// 最低受支持的客户端 Windows 8 [桌面应用|UWP 应用]
@@ -38,5 +119,51 @@ namespace YY
}
}
#endif
#if (YY_Thunks_Support_Version < NTDDI_WIN8)
// 最低受支持的客户端 Windows 8 [仅限桌面应用]
// 最低受支持的服务器 Windows Server 2012[仅限桌面应用]
__DEFINE_THUNK(
powrprof,
12,
DWORD,
WINAPI,
PowerRegisterSuspendResumeNotification,
_In_ DWORD _fFlags,
_In_ HANDLE _hRecipient,
_Out_ PHPOWERNOTIFY _phRegistrationHandle
)
{
if (auto const _pfnPowerRegisterSuspendResumeNotification = try_get_PowerRegisterSuspendResumeNotification())
{
return _pfnPowerRegisterSuspendResumeNotification(_fFlags, _hRecipient, _phRegistrationHandle);
}
return PowerRegisterSuspendResumeNotificationDownlevel(_fFlags, _hRecipient, _phRegistrationHandle);
}
#endif
#if (YY_Thunks_Support_Version < NTDDI_WIN8)
// 最低受支持的客户端 Windows 8 [仅限桌面应用]
// 最低受支持的服务器 Windows Server 2012[仅限桌面应用]
__DEFINE_THUNK(
powrprof,
4,
DWORD,
WINAPI,
PowerUnregisterSuspendResumeNotification,
_Inout_ HPOWERNOTIFY _hRegistrationHandle
)
{
if (auto const _pfnPowerUnregisterSuspendResumeNotification = try_get_PowerUnregisterSuspendResumeNotification())
{
return _pfnPowerUnregisterSuspendResumeNotification(_hRegistrationHandle);
}
return PowerUnregisterSuspendResumeNotificationDownlevel(_hRegistrationHandle);
}
#endif
}
}
@@ -0,0 +1,107 @@
#if (YY_Thunks_Support_Version < NTDDI_WIN8)
#include <winuser.h>
#endif
namespace YY
{
namespace Thunks
{
#ifndef CONST_DEVICE_NOTIFY_WINDOW_HANDLE
#define CONST_DEVICE_NOTIFY_WINDOW_HANDLE (HPOWERNOTIFY)0x1001
#endif
#if (YY_Thunks_Support_Version < NTDDI_WIN8)
// Windows 8 [仅限桌面应用],Windows Server 2012 [仅限桌面应用]
__DEFINE_THUNK(
user32,
8,
HPOWERNOTIFY,
WINAPI,
RegisterSuspendResumeNotification,
IN HANDLE _hRecipient,
IN DWORD _fFlags
)
{
if (const auto _pfnRegisterSuspendResumeNotification = try_get_RegisterSuspendResumeNotification())
{
return _pfnRegisterSuspendResumeNotification(_hRecipient, _fFlags);
}
if (DEVICE_NOTIFY_CALLBACK == _fFlags)
{
HPOWERNOTIFY _hRegistrationHandle = nullptr;
auto _lStatus = PowerRegisterSuspendResumeNotificationDownlevel(DEVICE_NOTIFY_CALLBACK, _hRecipient, &_hRegistrationHandle);
if (_lStatus == ERROR_SUCCESS)
{
return _hRegistrationHandle;
}
else
{
SetLastError(_lStatus);
return nullptr;
}
}
else if (DEVICE_NOTIFY_WINDOW_HANDLE == _fFlags)
{
// 这种情况需要向窗口发送电源通知,但是老版本系统不支持 现代化睡眠
// 本身就是可以正确处理这种情况的。所以我们忽略参数,直接返回一个标记常量即可。
UNREFERENCED_PARAMETER(_hRecipient);
return CONST_DEVICE_NOTIFY_WINDOW_HANDLE;
}
else
{
// 仅支持这二个参数
SetLastError(ERROR_INVALID_PARAMETER);
return nullptr;
}
}
#endif
#if (YY_Thunks_Support_Version < NTDDI_WIN8)
// Windows 8 [仅限桌面应用],Windows Server 2012 [仅限桌面应用]
__DEFINE_THUNK(
user32,
4,
BOOL,
WINAPI,
UnregisterSuspendResumeNotification,
IN HPOWERNOTIFY _hHandle
)
{
if (const auto _pfnUnregisterSuspendResumeNotification = try_get_UnregisterSuspendResumeNotification())
{
return _pfnUnregisterSuspendResumeNotification(_hHandle);
}
if (_hHandle == nullptr)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
else if (_hHandle == CONST_DEVICE_NOTIFY_WINDOW_HANDLE)
{
// 忽略,这是 DEVICE_NOTIFY_WINDOW_HANDLE 的常量
return TRUE;
}
else
{
// 来自 DEVICE_NOTIFY_CALLBACK的注册
auto _lStatus = PowerUnregisterSuspendResumeNotificationDownlevel(_hHandle);
if (_lStatus == ERROR_SUCCESS)
{
return TRUE;
}
else
{
SetLastError(_lStatus);
return FALSE;
}
}
}
#endif
}
}
@@ -161,6 +161,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="api-ms-win-power-base.UnitTest.cpp" />
<ClCompile Include="bcrypt.UnitTest.cpp" />
<ClCompile Include="Iphlpapi.UnitTest.cpp" />
<ClCompile Include="pch.cpp">
@@ -188,12 +189,14 @@
<ClInclude Include="..\Thunks\api-ms-win-power-base.hpp" />
<ClInclude Include="..\Thunks\bcrypt.hpp" />
<ClInclude Include="..\Thunks\bluetoothapis.hpp" />
<ClInclude Include="..\Thunks\ext-ms-win-ntuser-powermanagement.hpp" />
<ClInclude Include="..\Thunks\ext-ms-win-ntuser-window.hpp" />
<ClInclude Include="..\Thunks\Iphlpapi.hpp" />
<ClInclude Include="..\Thunks\mfplat.hpp" />
<ClInclude Include="..\Thunks\netapi32.hpp" />
<ClInclude Include="..\Thunks\Pdh.hpp" />
<ClInclude Include="..\Thunks\powrprof.hpp" />
<ClInclude Include="..\Thunks\ThreadRunner.h" />
<ClInclude Include="..\Thunks\userenv.hpp" />
<ClInclude Include="pch.h" />
<ClInclude Include="..\Thunks\api-ms-win-core-datetime.hpp" />
@@ -60,6 +60,9 @@
<ClCompile Include="Iphlpapi.UnitTest.cpp">
<Filter>源文件\UnitTest</Filter>
</ClCompile>
<ClCompile Include="api-ms-win-power-base.UnitTest.cpp">
<Filter>源文件\UnitTest</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
@@ -206,6 +209,12 @@
<ClInclude Include="..\Thunks\powrprof.hpp">
<Filter>Thunks</Filter>
</ClInclude>
<ClInclude Include="..\Thunks\ext-ms-win-ntuser-powermanagement.hpp">
<Filter>Thunks</Filter>
</ClInclude>
<ClInclude Include="..\Thunks\ThreadRunner.h">
<Filter>源文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\def\x86\PSAPI2Kernel32.def">
@@ -0,0 +1,37 @@
#include "pch.h"
#include "Thunks/api-ms-win-power-base.hpp"
namespace api_ms_win_power_base
{
TEST_CLASS(PowerRegisterSuspendResumeNotification)
{
public:
PowerRegisterSuspendResumeNotification()
{
YY::Thunks::aways_null_try_get_PowerRegisterSuspendResumeNotification = true;
YY::Thunks::aways_null_try_get_PowerUnregisterSuspendResumeNotification = true;
}
TEST_METHOD(创建然后关闭)
{
DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS Parameters = {};
Parameters.Callback = [](_In_opt_ PVOID Context,
_In_ ULONG Type,
_In_ PVOID Setting) -> ULONG
{
return ERROR_SUCCESS;
};
HPOWERNOTIFY RegistrationHandle = nullptr;
auto _lStatus = ::PowerRegisterSuspendResumeNotification(DEVICE_NOTIFY_CALLBACK, &Parameters, &RegistrationHandle);
Assert::AreEqual(_lStatus, (DWORD)ERROR_SUCCESS);
Assert::IsNotNull(RegistrationHandle);
Sleep(500);
_lStatus = ::PowerUnregisterSuspendResumeNotification(RegistrationHandle);
Assert::AreEqual(_lStatus, (DWORD)ERROR_SUCCESS);
}
};
}