В Vista к IOCP наконец то добавили штуку, которую логично было бы добавить с самого начала: возможность отключать ненужные нотификации успешных завершений с помощью функции SetFileCompletionNotificationModes. Просто выставляешь флаг FILE_SKIP_COMPLETION_PORT_ON_SUCCESS на сокет и все. Теперь если асинхронная функция выполнилась успешно, можно сразу же освобождать используемые ей ресурсы и инициировать новый запрос, все как и в нормальном асинхронном IO без использования портов завершения.
Интересно, что некоторые функции, типа AcceptEx, и так всегда обладали таким поведением.
Поскольку аналога GetFileCompletionNotificationModes в МСДН не наблюдается, пришлось из любопытства написать свой:
namespace kernel
{
typedef LONG NTSTATUS;
//---------------------------------------
typedef struct _IO_STATUS_BLOCK
{
union
{
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
}IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
//---------------------------------------
typedef
NTSYSAPI
DWORD
(NTAPI * RtlNtStatusToDosErrorPtr)(IN NTSTATUS status);
typedef
NTSYSAPI
NTSTATUS
(NTAPI * NtQueryInformationFilePtr)(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN DWORD FileInformationClass);
}
class CUndocumentedNtdll
{
HMODULE m_hNtDll;
kernel::NtQueryInformationFilePtr m_pNtQueryInformationFile;
kernel::RtlNtStatusToDosErrorPtr m_pRtlNtStatusToDosError;
public:
CUndocumentedNtdll()
{
m_hNtDll = GetModuleHandle(L"ntdll.dll");
m_pNtQueryInformationFile =
(kernel::NtQueryInformationFilePtr)
GetProcAddress(m_hNtDll, "NtQueryInformationFile");
m_pRtlNtStatusToDosError =
(kernel::RtlNtStatusToDosErrorPtr)
GetProcAddress(m_hNtDll, "RtlNtStatusToDosError");
}
ULONG GetFileCompletionNotificationModes(HANDLE hFile,
ULONG * pFlags)
{
if(!m_pNtQueryInformationFile || !m_pRtlNtStatusToDosError)
return ERROR_NOT_SUPPORTED;
ULONG flags = 0;
kernel::IO_STATUS_BLOCK statusBlock;
kernel::NTSTATUS status = m_pNtQueryInformationFile(hFile, &statusBlock, pFlags, 4, 0x29);
if (status >= 0)
return NO_ERROR;
return m_pRtlNtStatusToDosError(status);
}
};
No comments:
Post a Comment