События Event в WinApi

Подскажите пожалуйста, вот на MSDN есть пример вызова GetAddrInfoExW, приведу только небольшую часть:

https://docs.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfoexw

Там есть пример вызова функции CreateEvent:

QueryContext.CompleteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

Но, в описании функции CreateEvent на том же MSDN`е нет ни какого QueryContext.CompleteEvent, CreateEvent возвращает обычный HANDLE:

HANDLE CreateEventA(
  LPSECURITY_ATTRIBUTES lpEventAttributes,
  BOOL                  bManualReset,
  BOOL                  bInitialState,
  LPCSTR                lpName
);

Я что то не пойму что такое QueryContext.CompleteEvent и откуда он вообще взялся ?


Ответы (1 шт):

Автор решения: nick_n_a

Прокоментирую для вас код

int __cdecl wmain( _In_ int Argc, PWCHAR Argv[]) {
INT                 Error = ERROR_SUCCESS;
WSADATA             wsaData;
BOOL                IsWSAStartupCalled = FALSE;
ADDRINFOEX          Hints;
QUERY_CONTEXT       QueryContext; // Вот отсюда он взялся

// .. пропускаю кусок

QueryContext.CompleteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
// Создали Event событие
if (QueryContext.CompleteEvent == NULL)
{
  // ...  Если не создалось - ошибка
}
// Делаем вызов
Error = GetAddrInfoExW(Argv[1], NULL, NS_DNS, NULL, &Hints,
                       &QueryContext.QueryResults, NULL,
                       &QueryContext.QueryOverlapped,
                       QueryCompleteCallback,
                       &CancelHandle);
// Так как мы передали Event - ответ должен быть PENDING    
if (Error != WSA_IO_PENDING)
{  // Если ответ не PENDING, ответ 0 не будет, а  ошибку обработает код ниже, который в QueryCompleteCallback
    QueryCompleteCallback(Error, 0, &QueryContext.QueryOverlapped); 
    goto exit; // и на выход
}
//  Ждем время  QueryTimeout = 5 секунд пока не произойдёт событие
if (WaitForSingleObject(QueryContext.CompleteEvent,
                        QueryTimeout)  == WAIT_TIMEOUT )
{

    wprintf(L"Пишем что недождались ");

    GetAddrInfoExCancel(&CancelHandle); // Отмена вызова

    WaitForSingleObject(QueryContext.CompleteEvent, INFINITE);// Ждём отмену до бесконечности
}

А тут ещё хитрость, они передали каллбек, QueryCompleteCallback (ниже по коду) будет вызвано в то время, пока будет идти первый WaitForSingleObject.

Это обычный механизм обращения с Overlapped-event. Похожее можно делать и с чтением файла и с другими операциями, которые могут растянуться во времени.

HANDLE позволяет хранить в себе какие угодно kernel обьекты. Файлы, pipe-ы, Thread, их список тут а функции собраны тут (msdn) в функциях есть "лишнии" обьекты которые не имеют хандлов.

Есть специальные функции NtQueryObject и подобных - которые могут узнать тип хандла. Особенность хандла в том, что для любого хандла можно делать CloseHandle, будь то файл, Event, Thread, Process и так далее. Да, в самом низу примера от микрософт - они закрывают хандл. Наверно это для удобства сделано. Так уже сложилось начиная ещё с первых (или вторых) версий винды так принято с хандлами делать.

→ Ссылка