CancelSynchronousIo
指定されたスレッドによって発行されたI/O操作をキャンセルします。より具体的には、IoCancelIrp
を介して指定されたスレッドに関連付けられたパケットIRP
を取り消します。使用がNtCancelSynchronousIoFile
文書化されていない場合、我々は、より選択的であり得る(CancelSynchronousIo
を内部IoRequestToCancel = 0
でそれを呼び出す) - これは私がない
が、WaitForSingleObject
をIoRequestToCancel
指定使用のみのI/O要求取り消し(Irp->UserIosb == IoRequestToCancel
というシステムチェックをしてのみ、この要求を取り消します)/Oリクエスト。この呼び出しはキャンセル可能なIRP
を作成しません。だから - これは絶対にしないでください。
しかし、あなたはTRUE
にbAlertable
セットでWaitForSingleObjectEx
を使用している場合 - あなたはブレークQueueUserAPC
を使用してスレッド化にキューAPCによってを待つことができます。 NtWaitForSingleObject
の代わりにWaitForSingleObjectEx
を使用する場合は、文書化されていない電話NtAlertThread
を使用してスレッドに警告することもできます。再びNtWaitForSingleObject
を実行します - - 結果として、我々はコールNtAlertThread
でWaitForSingleObjectEx
を破ることはできませんが、NtWaitForSingleObject
はbreakedされます
。この場合には
NtWaitForSingleObject
は
WaitForSingleObjectEx
内部
STATUS_ALERTED
のためにと、この状態の場合には、特別なチェックを行う
NtWaitForSingleObject
を呼び出していることに注意してください(
STATUS_ALERTED
で壊れます
ので、あなたがSTD入力待ち壊す必要がある場合 - (あなたは待機のためNtWaitForSingleObject
を使用する場合のみ)ではないCancelSynchronousIo
(この無意味な)が、QueueUserAPC
またはNtAlertThread
呼び出す必要があり、追加のスレッドを作成し、入力されたスレッドがアラート可能状態で待機する必要があります。デモコードは次のようになります:
extern "C" NTSYSCALLAPI NTSTATUS NTAPI NtAlertThread(HANDLE ThreadHandle);
VOID NTAPI OnApc(ULONG_PTR Parameter)
{
DbgPrint("OnApc(%p)\n", Parameter);
}
DWORD CALLBACK BreakWaitThread(HANDLE hThread)
{
switch (LONG status = MessageBoxW(0, L"Use Apc(yes) or Alert(No) ?", L"BreakWaitThread",
MB_ICONQUESTION|MB_YESNOCANCEL|MB_DEFBUTTON3))
{
case IDYES:
if (!QueueUserAPC(OnApc, hThread, 0))
{
DbgPrint("QueueUserAPC=%u\n", GetLastError());
}
break;
case IDNO:
if (0 > (status = NtAlertThread(hThread)))
{
DbgPrint("AlertThread=%x\n", status);
}
break;
case IDCANCEL:
DbgPrint("canceled\n");
break;
default:
DbgPrint("MessageBox=%x\n", status);
}
CloseHandle(hThread);
return 0;
}
void ConsoleLoop(HANDLE hStdIn)
{
ULONG NumberOfEvents, NumberOfEventsRead, n;
INPUT_RECORD buf[8], *p;
for (;;)
{
switch (ZwWaitForSingleObject(hStdIn, TRUE, 0))
//switch (WaitForSingleObjectEx(hStdIn, INFINITE, TRUE))
{
case WAIT_OBJECT_0:
while (GetNumberOfConsoleInputEvents(hStdIn, &NumberOfEvents) && NumberOfEvents)
{
do
{
NumberOfEventsRead = min(RTL_NUMBER_OF(buf), NumberOfEvents);
if (ReadConsoleInput(hStdIn, buf, NumberOfEventsRead, &NumberOfEventsRead) && NumberOfEventsRead)
{
n = NumberOfEventsRead;
p = buf;
do
{
if (p->EventType == KEY_EVENT)
{
DbgPrint("%u(%u) %C %x %x %x\n",
p->Event.KeyEvent.bKeyDown,
p->Event.KeyEvent.wRepeatCount,
p->Event.KeyEvent.uChar.UnicodeChar,
p->Event.KeyEvent.wVirtualKeyCode,
p->Event.KeyEvent.wVirtualScanCode,
p->Event.KeyEvent.dwControlKeyState);
if (VK_OEM_PERIOD == p->Event.KeyEvent.wVirtualKeyCode)
{
return ;//if user type '.' return for demo
}
}
} while (p++, --n);
}
else
{
FlushConsoleInputBuffer(hStdIn);
break;
}
} while (NumberOfEvents -= NumberOfEventsRead);
}
continue;
case STATUS_USER_APC:
DbgPrint("\nUSER_APC\n");
return;
case STATUS_ALERTED:
DbgPrint("\nALERTED\n");
return;
case WAIT_FAILED :
DbgPrint("\nWAIT_FAILED=%u\n", GetLastError());
return;
default:
__debugbreak();
return;
}
}
}
void SimpleDemo()
{
if (HANDLE hCurrentThread = OpenThread(THREAD_ALERT|THREAD_SET_CONTEXT , FALSE, GetCurrentThreadId()))
{
ULONG dwThreadId;
HANDLE hThread = CreateThread(0, 0, BreakWaitThread, hCurrentThread, 0, &dwThreadId);
if (hThread)
{
ConsoleLoop(GetStdHandle(STD_INPUT_HANDLE));
PostThreadMessage(dwThreadId, WM_QUIT, 0, 0);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
else
{
CloseHandle(hCurrentThread);
}
}
}
WaitForSingleObjectはI/O要求ではなく、もちろんキャンセルできません。 – RbMm