diff --git a/ThunksList.md b/ThunksList.md
index 43e169b..98e2e7f 100644
--- a/ThunksList.md
+++ b/ThunksList.md
@@ -290,6 +290,8 @@
| GetFirmwareType | 不存在时,调用NtQuerySystemInformation。
| IsNativeVhdBoot | 不存在时,调用NtQuerySystemInformation。
| RtlCaptureStackBackTrace | 调用ntdll.RtlCaptureStackBackTrace。
+| SetFileCompletionNotificationModes | 不存在时,什么也不做。
+| GetQueuedCompletionStatusEx | 不存在时,调用 GetQueuedCompletionStatus,注意:丢失可警报状态支持。
## mfplat.dll
| 函数 | Fallback
@@ -305,6 +307,11 @@
| NetGetAadJoinInformation | 不存在时,始终认为没有加入 Azure AD 帐户 账号。
| NetFreeAadJoinInformation | 不存在时,什么也不做。
+## ntdll.dll
+| 函数 | Fallback
+| ---- | -----------
+| NtCancelIoFileEx | 不存在时,调用 NtCancelIoFile。注意:将取消此文件的所有IO请求。
+
## ole32.dll
| 函数 | Fallback
| ---- | -----------
diff --git a/src/Shared/km.h b/src/Shared/km.h
index 0479a43..e1f96bc 100644
--- a/src/Shared/km.h
+++ b/src/Shared/km.h
@@ -5104,6 +5104,15 @@ LdrAddRefDll(
IN PVOID BaseAddress
);
+EXTERN_C NTSTATUS NTAPI NtCancelIoFileEx(HANDLE handle, IO_STATUS_BLOCK* io, IO_STATUS_BLOCK* io_status);
+
+EXTERN_C
+NTSTATUS
+NTAPI
+NtCancelIoFile(
+ IN HANDLE FileHandle,
+ OUT PIO_STATUS_BLOCK IoStatusBlock);
+
#if defined __cplusplus && !defined _Disallow_YY_KM_Namespace
} //namespace YY
#endif
diff --git a/src/Thunks/YY_Thunks.cpp b/src/Thunks/YY_Thunks.cpp
index f0614c9..485d86b 100644
--- a/src/Thunks/YY_Thunks.cpp
+++ b/src/Thunks/YY_Thunks.cpp
@@ -1,5 +1,6 @@
// 忽略非标准的 0 数组警告。
#pragma warning(disable:4200)
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define _YY_APPLY_TO_LATE_BOUND_MODULES(_APPLY) \
_APPLY(ntdll, "ntdll" , USING_UNSAFE_LOAD ) \
@@ -57,6 +58,7 @@
_APPLY(LdrLoadDll, ntdll ) \
_APPLY(RtlDllShutdownInProgress, ntdll ) \
_APPLY(RtlCutoverTimeToSystemTime, ntdll ) \
+ _APPLY(NtCancelIoFile, ntdll ) \
_APPLY(AddDllDirectory, kernel32 ) \
_APPLY(SystemFunction036, advapi32 )
diff --git a/src/Thunks/api-ms-win-core-io.hpp b/src/Thunks/api-ms-win-core-io.hpp
index 0479596..8745b9d 100644
--- a/src/Thunks/api-ms-win-core-io.hpp
+++ b/src/Thunks/api-ms-win-core-io.hpp
@@ -52,6 +52,49 @@ namespace YY
return FALSE;
}
#endif
+
+#if (YY_Thunks_Support_Version < NTDDI_WIN6)
+
+ // 最低受支持的客户端 Windows Vista [桌面应用 | UWP 应用]
+ // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用]
+ __DEFINE_THUNK(
+ kernel32,
+ 24,
+ BOOL,
+ WINAPI,
+ GetQueuedCompletionStatusEx,
+ _In_ HANDLE CompletionPort,
+ _Out_writes_to_(ulCount,*ulNumEntriesRemoved) LPOVERLAPPED_ENTRY lpCompletionPortEntries,
+ _In_ ULONG ulCount,
+ _Out_ PULONG ulNumEntriesRemoved,
+ _In_ DWORD dwMilliseconds,
+ _In_ BOOL fAlertable
+ )
+ {
+ if (const auto _pfnGetQueuedCompletionStatusEx = try_get_GetQueuedCompletionStatusEx())
+ {
+ return _pfnGetQueuedCompletionStatusEx(CompletionPort, lpCompletionPortEntries, ulCount, ulNumEntriesRemoved, dwMilliseconds, fAlertable);
+ }
+
+ if (ulCount == 0 || lpCompletionPortEntries == nullptr || ulNumEntriesRemoved == nullptr)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ *ulNumEntriesRemoved = 0;
+
+ auto& _Entry = lpCompletionPortEntries[0];
+
+ // TODO: 已知问题:可警报状态丢失!(fAlertable)
+ auto _bRet = GetQueuedCompletionStatus(CompletionPort, &_Entry.dwNumberOfBytesTransferred, &_Entry.lpCompletionKey, &_Entry.lpOverlapped, dwMilliseconds);
+ if (_bRet)
+ {
+ *ulNumEntriesRemoved = 1;
+ }
+ return _bRet;
+ }
+#endif
}//namespace Thunks
} //namespace YY
\ No newline at end of file
diff --git a/src/Thunks/api-ms-win-core-kernel32-legacy.hpp b/src/Thunks/api-ms-win-core-kernel32-legacy.hpp
index 0a21278..2ac9f0f 100644
--- a/src/Thunks/api-ms-win-core-kernel32-legacy.hpp
+++ b/src/Thunks/api-ms-win-core-kernel32-legacy.hpp
@@ -394,6 +394,31 @@ namespace YY
}
#endif
+#if (YY_Thunks_Support_Version < NTDDI_WIN6)
+
+ // 支持的最低客户端 Windows Vista [桌面应用程序 |UWP 应用]
+ // 支持的最低服务器 Windows Server 2008 [桌面应用程序 |UWP 应用]
+ __DEFINE_THUNK(
+ kernel32,
+ 8,
+ BOOL,
+ WINAPI,
+ SetFileCompletionNotificationModes,
+ _In_ HANDLE FileHandle,
+ _In_ UCHAR Flags
+ )
+ {
+ if (const auto _pfnSetFileCompletionNotificationModes = try_get_SetFileCompletionNotificationModes())
+ {
+ return _pfnSetFileCompletionNotificationModes(FileHandle, Flags);
+ }
+
+ // 初步看起来没有什么的,只是会降低完成端口的效率。
+ // 至少需要 Vista才支持 FileIoCompletionNotificationInformation
+ // 只能假定先返回成功。
+ return TRUE;
+ }
+#endif
}//namespace Thunks
} //namespace YY
\ No newline at end of file
diff --git a/src/Thunks/ntdll.hpp b/src/Thunks/ntdll.hpp
new file mode 100644
index 0000000..20a1df3
--- /dev/null
+++ b/src/Thunks/ntdll.hpp
@@ -0,0 +1,36 @@
+namespace YY
+{
+ namespace Thunks
+ {
+#if (YY_Thunks_Support_Version < NTDDI_WIN6)
+
+ // ֵ֧Ŀͻ Windows Vista [Ӧ|UWP Ӧ]
+ // ֵ֧ķ Windows Server 2008[Ӧ | UWP Ӧ]
+ __DEFINE_THUNK(
+ ntdll,
+ 12,
+ NTSTATUS,
+ NTAPI,
+ NtCancelIoFileEx,
+ HANDLE handle,
+ IO_STATUS_BLOCK* io,
+ IO_STATUS_BLOCK* io_status
+ )
+ {
+ if (const auto _pfnNtCancelIoFileEx = try_get_NtCancelIoFileEx())
+ {
+ return _pfnNtCancelIoFileEx(handle, io, io_status);
+ }
+
+ // 㣬еĵ
+ if (const auto _pfnNtCancelIoFile = try_get_NtCancelIoFile())
+ {
+ return _pfnNtCancelIoFile(handle, io_status);
+ }
+
+ // ˵Ӧߵ
+ return STATUS_NOT_SUPPORTED;
+ }
+#endif
+ }
+}
diff --git a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj
index 9c9cd42..d1cf6ed 100644
--- a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj
+++ b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj
@@ -203,6 +203,7 @@
+
diff --git a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters
index 251c101..ab0b7ce 100644
--- a/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters
+++ b/src/YY-Thunks.UnitTest/YY-Thunks.UnitTest.vcxproj.filters
@@ -227,6 +227,9 @@
Thunks
+
+ Thunks
+
diff --git a/src/YY-Thunks.UnitTest/api-ms-win-core-fibers.UnitTest.cpp b/src/YY-Thunks.UnitTest/api-ms-win-core-fibers.UnitTest.cpp
index 4685658..7be4464 100644
--- a/src/YY-Thunks.UnitTest/api-ms-win-core-fibers.UnitTest.cpp
+++ b/src/YY-Thunks.UnitTest/api-ms-win-core-fibers.UnitTest.cpp
@@ -65,7 +65,7 @@ namespace api_ms_win_core_fibers
for (auto hHandle : hHandles)
{
- Assert::AreEqual(WaitForSingleObject(hHandle, 1000), WAIT_OBJECT_0);
+ Assert::AreEqual(WaitForSingleObject(hHandle, 1000), (DWORD)WAIT_OBJECT_0);
CloseHandle(hHandle);
}
@@ -158,7 +158,7 @@ namespace api_ms_win_core_fibers
for (auto hHandle : hHandles)
{
- Assert::AreEqual(WaitForSingleObject(hHandle, 1000), WAIT_OBJECT_0);
+ Assert::AreEqual(WaitForSingleObject(hHandle, 1000), (DWORD)WAIT_OBJECT_0);
CloseHandle(hHandle);
}
diff --git a/src/YY-Thunks.UnitTest/api-ms-win-core-synch.UnitTest.cpp b/src/YY-Thunks.UnitTest/api-ms-win-core-synch.UnitTest.cpp
index 6109796..5f71061 100644
--- a/src/YY-Thunks.UnitTest/api-ms-win-core-synch.UnitTest.cpp
+++ b/src/YY-Thunks.UnitTest/api-ms-win-core-synch.UnitTest.cpp
@@ -98,7 +98,7 @@ namespace api_ms_win_core_synch
for (auto hThreadHandle : hThreadHandles)
{
- Assert::AreEqual(WaitForSingleObject(hThreadHandle, 500), WAIT_OBJECT_0);
+ Assert::AreEqual(WaitForSingleObject(hThreadHandle, 500), (DWORD)WAIT_OBJECT_0);
}
Assert::AreEqual(100l, (long)Data.RunCount);
@@ -157,7 +157,7 @@ namespace api_ms_win_core_synch
for (auto hThreadHandle : hThreadHandles)
{
- Assert::AreEqual(WaitForSingleObject(hThreadHandle, 500), WAIT_OBJECT_0);
+ Assert::AreEqual(WaitForSingleObject(hThreadHandle, 500), (DWORD)WAIT_OBJECT_0);
}
Assert::AreEqual(100l, (long)Data.RunCount);
@@ -205,7 +205,7 @@ namespace api_ms_win_core_synch
auto _nRet = WaitForSingleObject(_hThreadHandle, 5 * 1000);
::ReleaseSRWLockExclusive(&_SRWLock);
- Assert::AreEqual(WAIT_OBJECT_0, _nRet);
+ Assert::AreEqual((DWORD)WAIT_OBJECT_0, _nRet);
DWORD _uCode = -1;
GetExitCodeThread(_hThreadHandle, &_uCode);
@@ -237,7 +237,7 @@ namespace api_ms_win_core_synch
auto _nRet = WaitForSingleObject(_hThreadHandle, 5 * 1000);
- Assert::AreEqual(WAIT_OBJECT_0, _nRet);
+ Assert::AreEqual((DWORD)WAIT_OBJECT_0, _nRet);
DWORD _uCode = -1;
GetExitCodeThread(_hThreadHandle, &_uCode);
diff --git a/src/YY-Thunks.UnitTest/api-ms-win-core-threadpool.UnitTest.cpp b/src/YY-Thunks.UnitTest/api-ms-win-core-threadpool.UnitTest.cpp
index 75ea608..0ebbc96 100644
--- a/src/YY-Thunks.UnitTest/api-ms-win-core-threadpool.UnitTest.cpp
+++ b/src/YY-Thunks.UnitTest/api-ms-win-core-threadpool.UnitTest.cpp
@@ -146,7 +146,7 @@ namespace api_ms_win_core_threadpool
Assert::IsNotNull(h);
- Assert::AreEqual(WaitForSingleObject(h, 2 * 1000), WAIT_OBJECT_0, L"2秒内必须完成,这是预期。");
+ Assert::AreEqual(WaitForSingleObject(h, 2 * 1000), (DWORD)WAIT_OBJECT_0, L"2秒内必须完成,这是预期。");
CloseHandle(h);
@@ -165,7 +165,7 @@ namespace api_ms_win_core_threadpool
Assert::IsNotNull(h);
- Assert::AreEqual(WaitForSingleObject(h, 6 * 1000), WAIT_OBJECT_0, L"6秒内必须完成,这是预期。");
+ Assert::AreEqual(WaitForSingleObject(h, 6 * 1000), (DWORD)WAIT_OBJECT_0, L"6秒内必须完成,这是预期。");
CloseHandle(h);
@@ -446,7 +446,7 @@ namespace api_ms_win_core_threadpool
::SetThreadpoolTimer(pTimer, &ftDueTime, 1'500, 0);
- Assert::AreEqual(WaitForSingleObject(Data.hEvent, 1 * 1000), WAIT_OBJECT_0, L"1秒内必须完成,这是预期。");
+ Assert::AreEqual(WaitForSingleObject(Data.hEvent, 1 * 1000), (DWORD)WAIT_OBJECT_0, L"1秒内必须完成,这是预期。");
auto h = (HANDLE)_beginthreadex(nullptr, 0, [](void* Work) -> unsigned
{
@@ -457,7 +457,7 @@ namespace api_ms_win_core_threadpool
Assert::IsNotNull(h);
- Assert::AreEqual(WaitForSingleObject(h, 30 * 1000), WAIT_OBJECT_0, L"6秒内必须完成,这是预期。");
+ Assert::AreEqual(WaitForSingleObject(h, 30 * 1000), (DWORD)WAIT_OBJECT_0, L"6秒内必须完成,这是预期。");
CloseHandle(h);
Assert::AreEqual(Data.RunCount, 1l);
@@ -522,7 +522,7 @@ namespace api_ms_win_core_threadpool
::SubmitThreadpoolWork(Work);
- Assert::AreEqual(WaitForSingleObject(Data.hHandle, 5 * 1000), WAIT_OBJECT_0, L"5秒内句柄必须有信号");
+ Assert::AreEqual(WaitForSingleObject(Data.hHandle, 5 * 1000), (DWORD)WAIT_OBJECT_0, L"5秒内句柄必须有信号");
Assert::AreEqual(Data.RunCount, 1l);
CloseThreadpoolWork(Work);
@@ -550,7 +550,7 @@ namespace api_ms_win_core_threadpool
FILETIME ftDueTime = {};
::SetThreadpoolTimer(pTimer, &ftDueTime, 0, 0);
- Assert::AreEqual(WaitForSingleObject(Data.hHandle, 5 * 1000), WAIT_OBJECT_0, L"5秒内句柄必须有信号");
+ Assert::AreEqual(WaitForSingleObject(Data.hHandle, 5 * 1000), (DWORD)WAIT_OBJECT_0, L"5秒内句柄必须有信号");
Assert::AreEqual(Data.RunCount, 1l);
::CloseThreadpoolTimer(pTimer);
@@ -612,7 +612,7 @@ namespace api_ms_win_core_threadpool
::SubmitThreadpoolWork(Work);
- Assert::AreEqual(WaitForSingleObject(Data.hHandle, 5 * 1000), WAIT_OBJECT_0, L"5秒内句柄必须有信号");
+ Assert::AreEqual(WaitForSingleObject(Data.hHandle, 5 * 1000), (DWORD)WAIT_OBJECT_0, L"5秒内句柄必须有信号");
Assert::AreEqual(Data.RunCount, 1l);
CloseThreadpoolWork(Work);
@@ -644,7 +644,7 @@ namespace api_ms_win_core_threadpool
FILETIME ftDueTime = {};
::SetThreadpoolTimer(pTimer, &ftDueTime, 0, 0);
- Assert::AreEqual(WaitForSingleObject(Data.hHandle, 5 * 1000), WAIT_OBJECT_0, L"5秒内句柄必须有信号");
+ Assert::AreEqual(WaitForSingleObject(Data.hHandle, 5 * 1000), (DWORD)WAIT_OBJECT_0, L"5秒内句柄必须有信号");
Assert::AreEqual(Data.RunCount, 1l);
::CloseThreadpoolTimer(pTimer);
@@ -698,7 +698,7 @@ namespace api_ms_win_core_threadpool
Assert::IsNotNull(Context);
auto& Data = *(UserData*)Context;
auto dwWaitResult = WaitForSingleObject(Data.hHandle, 1000);
- Assert::AreEqual(dwWaitResult, WAIT_OBJECT_0);
+ Assert::AreEqual(dwWaitResult, (DWORD)WAIT_OBJECT_0);
::ReleaseMutexWhenCallbackReturns(Instance, Data.hHandle);
InterlockedIncrement(&Data.RunCount);
@@ -709,7 +709,7 @@ namespace api_ms_win_core_threadpool
::SubmitThreadpoolWork(Work);
Sleep(100);
- Assert::AreEqual(WaitForSingleObject(Data.hHandle, 5 * 1000), WAIT_OBJECT_0, L"5秒内句柄必须有信号");
+ Assert::AreEqual(WaitForSingleObject(Data.hHandle, 5 * 1000), (DWORD)WAIT_OBJECT_0, L"5秒内句柄必须有信号");
Assert::AreEqual(Data.RunCount, 1l);
CloseThreadpoolWork(Work);
@@ -728,7 +728,7 @@ namespace api_ms_win_core_threadpool
Assert::IsNotNull(Context);
auto& Data = *(UserData*)Context;
auto dwWaitResult = WaitForSingleObject(Data.hHandle, 1000);
- Assert::AreEqual(dwWaitResult, WAIT_OBJECT_0);
+ Assert::AreEqual(dwWaitResult, (DWORD)WAIT_OBJECT_0);
::ReleaseMutexWhenCallbackReturns(Instance, Data.hHandle);
InterlockedIncrement(&Data.RunCount);
}, &Data, nullptr);
@@ -739,7 +739,7 @@ namespace api_ms_win_core_threadpool
::SetThreadpoolTimer(pTimer, &ftDueTime, 0, 0);
Sleep(100);
- Assert::AreEqual(WaitForSingleObject(Data.hHandle, 5 * 1000), WAIT_OBJECT_0, L"5秒内句柄必须有信号");
+ Assert::AreEqual(WaitForSingleObject(Data.hHandle, 5 * 1000), (DWORD)WAIT_OBJECT_0, L"5秒内句柄必须有信号");
Assert::AreEqual(Data.RunCount, 1l);
::CloseThreadpoolTimer(pTimer);
@@ -1040,7 +1040,7 @@ namespace api_ms_win_core_threadpool
_In_ TP_WAIT_RESULT WaitResult
)
{
- Assert::AreEqual(WaitResult, WAIT_OBJECT_0);
+ Assert::AreEqual(WaitResult, (DWORD)WAIT_OBJECT_0);
Assert::IsNotNull(Context);
@@ -1353,7 +1353,7 @@ namespace api_ms_win_core_threadpool
Assert::IsNotNull(h);
- Assert::AreEqual(WaitForSingleObject(h, 10 * 1000), WAIT_OBJECT_0, L"10秒内必须完成,这是预期。");
+ Assert::AreEqual(WaitForSingleObject(h, 10 * 1000), (DWORD)WAIT_OBJECT_0, L"10秒内必须完成,这是预期。");
diff --git a/src/YY-Thunks.UnitTest/pch.h b/src/YY-Thunks.UnitTest/pch.h
index c015654..69426a0 100644
--- a/src/YY-Thunks.UnitTest/pch.h
+++ b/src/YY-Thunks.UnitTest/pch.h
@@ -7,10 +7,18 @@
#ifndef PCH_H
#define PCH_H
+#include
+
// 添加要在此处预编译的标头
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#define UMDF_USING_NTSTATUS
+#define _Disallow_YY_KM_Namespace
+#include
+
#include
+
#include
+
#include "CppUnitTest.h"
#include