Поделиться через


Создание функций обратного вызова состояния

В этом руководстве описывается, как создать функцию обратного вызова состояния, используемую для отслеживания состояния запроса в Интернете.

Функции обратного вызова статуса получают уведомления о состоянии для любых интернет-запросов, исходящих из любых функций WinINet, которым было передано ненулевое значение контекста.

Для создания функции обратного вызова состояния необходимо выполнить следующие действия.

  1. Определить значение контекста.
  2. Создайте функцию обратного вызова состояния.

Определение значения контекста

Значение контекста может быть любым длинным целым числом без знака. В идеале значение контекста должно определить, какой запрос только что был завершен, и расположение любых связанных ресурсов при необходимости.

Одним из наиболее полезных способов использования значения контекста является передача адреса структуры и приведение его к DWORD_PTR. Структура может использоваться для хранения информации о запросе, чтобы она могла быть передана в функцию обратного вызова статуса.

Следующая структура является примером возможного значения контекста. Элементы структуры выбираются с учетом функции InternetOpenUrl.

typedef struct{
    HWND       hWindow;      // Window handle
    int        nStatusList;  // List box control to hold callbacks
    HINTERNET  hResource;    // HINTERNET handle created by InternetOpenUrl
    char       szMemo[512];  // String to store status memo
} REQUEST_CONTEXT;

В этом примере функция обратного вызова состояния будет иметь доступ к дескриптору окна, что позволит отображать пользовательский интерфейс. Дескриптор HINTERNET, созданный при помощи InternetOpenUrl, можно передать в другую функцию, которая может скачать ресурс, и массив символов, которые можно использовать для передачи информации о запросе.

Члены структуры можно изменить в соответствии с потребностями конкретного приложения, поэтому не чувствуют себя ограниченными в этом примере.

Создание функции обратного вызова состояния

Функция обратного вызова состояния должна соответствовать формату InternetStatusCallback. Для этого выполните указанные ниже действия.

  1. Напишите объявление функции для функции обратного вызова состояния.

    В следующем примере показан пример объявления.

    void CALLBACK CallMaster( HINTERNET,
                              DWORD_PTR,
                              DWORD,
                              LPVOID,
                              DWORD );
    
  2. Определите, что будет делать функция обратного вызова статуса. Для приложений, выполняющих асинхронные вызовы, функция обратного вызова состояния должна обрабатывать значение INTERNET_STATUS_REQUEST_COMPLETE, указывающее, что асинхронный запрос завершен. Функцию обратного вызова состояния также можно использовать для отслеживания хода выполнения запроса в Интернете.

    Как правило, рекомендуется использовать инструкцию switch с dwInternetStatus в качестве значения переключателя и значений состояния для инструкций case. В зависимости от типов функций, вызываемых приложением, можно игнорировать некоторые значения состояния. Определение различных значений состояния можно найти в списке, указанном в параметре dwInternetStatusInternetStatusCallback.

    Следующая инструкция switch — это пример обработки обратных вызовов состояния.

    switch (dwInternetStatus)
    {
        case INTERNET_STATUS_REQUEST_COMPLETE:
            // Add code
            break;
        default:
            // Add code
            break;
    }
    
  3. Создайте код для обработки значений состояния.

    Код для обработки каждого из значений состояния сильно зависит от предполагаемого использования функции обратного вызова состояния. Для приложений, которые просто отслеживают ход выполнения запроса, написание строки в поле списка может быть все, что вам нужно. Для асинхронных операций код должен обрабатывать некоторые данные, возвращаемые в обратном вызове.

    Следующая функция обратного вызова состояния использует функцию switch для определения значения состояния и создает строку, содержащую имя значения состояния и предыдущую функцию, которая хранится в элементе szMemo структуры REQUEST_CONTEXT.

    void __stdcall CallMaster(
        HINTERNET hInternet,
        DWORD_PTR dwContext,
        DWORD dwInternetStatus,
        LPVOID lpvStatusInformation,
        DWORD dwStatusInformationLength
    )
    {
        UNREFERENCED_PARAMETER(hInternet);
        UNREFERENCED_PARAMETER(lpvStatusInformation);
        UNREFERENCED_PARAMETER(dwStatusInformationLength);
    
        REQUEST_CONTEXT *cpContext;
        cpContext = (REQUEST_CONTEXT*)dwContext;
        char szStatusText[80];
    
        switch (dwInternetStatus)
        {
            case INTERNET_STATUS_CLOSING_CONNECTION:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s CLOSING_CONNECTION",
                                  cpContext->szMemo);
                break;
            case INTERNET_STATUS_CONNECTED_TO_SERVER:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s CONNECTED_TO_SERVER",
                                  cpContext->szMemo );
                break;
            case INTERNET_STATUS_CONNECTING_TO_SERVER:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s CONNECTING_TO_SERVER",
                                  cpContext->szMemo );
                break;
            case INTERNET_STATUS_CONNECTION_CLOSED:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s CONNECTION_CLOSED",
                                  cpContext->szMemo );
                break;
            case INTERNET_STATUS_HANDLE_CLOSING:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s HANDLE_CLOSING",
                                  cpContext->szMemo );
                break;
            case INTERNET_STATUS_HANDLE_CREATED:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s HANDLE_CREATED",
                                  cpContext->szMemo);
                break;
            case INTERNET_STATUS_INTERMEDIATE_RESPONSE:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s INTERMEDIATE_RESPONSE",
                                  cpContext->szMemo );
                break;
            case INTERNET_STATUS_NAME_RESOLVED:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s NAME_RESOLVED",
                                  cpContext->szMemo);
                break;
            case INTERNET_STATUS_RECEIVING_RESPONSE:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s RECEIVING_RESPONSE",
                                  cpContext->szMemo);
                break;
            case INTERNET_STATUS_RESPONSE_RECEIVED:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s RESPONSE_RECEIVED",
                                  cpContext->szMemo);
                break;
            case INTERNET_STATUS_REDIRECT:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s REDIRECT",
                                  cpContext->szMemo );
                break;
            case INTERNET_STATUS_REQUEST_COMPLETE:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s REQUEST_COMPLETE",
                                  cpContext->szMemo);
                break;
            case INTERNET_STATUS_REQUEST_SENT:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s REQUEST_SENT",
                                  cpContext->szMemo);
                break;
            case INTERNET_STATUS_RESOLVING_NAME:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s RESOLVING_NAME",
                                  cpContext->szMemo );
                break;
            case INTERNET_STATUS_SENDING_REQUEST:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s SENDING_REQUEST",
                                  cpContext->szMemo );
                break;
            case INTERNET_STATUS_STATE_CHANGE:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s STATE_CHANGE",
                                  cpContext->szMemo );
                break;
            default:
                StringCchPrintfA( szStatusText,
                                  80,
                                  "%s Unknown Status %d Given",
                                  cpContext->szMemo,
                                  dwInternetStatus);
                break;
        }
    
        SendDlgItemMessage( cpContext->hWindow,
                          cpContext->nStatusList,
                          LB_ADDSTRING,
                          0, (LPARAM)szStatusText );
    
    }
    
  4. Используйте функцию InternetSetStatusCallback, чтобы задать функцию обратного вызова состояния для дескриптора HINTERNET, для которого требуется получать обратные вызовы состояния.

    В следующем примере показано, как задать функцию обратного вызова состояния.

    HINTERNET hOpen;                       // Root HINTERNET handle
    INTERNET_STATUS_CALLBACK iscCallback;  // Holds the callback function
    
    // Create the root HINTERNET handle.
    hOpen = InternetOpen( TEXT("Test Application"),
                          INTERNET_OPEN_TYPE_PRECONFIG,
                          NULL, NULL, 0);
    
    // Set the status callback function.
    iscCallback = InternetSetStatusCallback( hOpen, (INTERNET_STATUS_CALLBACK)CallMaster );
    

Заметка

WinINet не поддерживает реализации сервера. Кроме того, его не следует использовать в сервисе. Для реализации серверов или служб используйте Microsoft Windows HTTP Services (WinHTTP).

 

Создание функций обратного вызова состояния

InternetSetStatusCallback

InternetStatusCallback