mirror of
https://github.com/Chuyu-Team/YY-Thunks.git
synced 2026-10-28 22:08:22 +08:00
Fea #29, 消除Chrome中Windows 7不支持的部分API
* PowerRegisterSuspendResumeNotification * PowerUnregisterSuspendResumeNotification * RegisterSuspendResumeNotification * UnregisterSuspendResumeNotification
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,6 +339,8 @@ namespace YY
|
||||
|
||||
} //namespace YY
|
||||
|
||||
#include "ThreadRunner.h"
|
||||
|
||||
//导入实际的实现
|
||||
#define YY_Thunks_Implemented
|
||||
#define __DEFINE_THUNK(_MODULE, _SIZE, _RETURN_, _CONVENTION_, _FUNCTION, ...) \
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user