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


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

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

Функции обратного вызова состояния получают обратные вызовы состояния во всех интернет-запросах, исходящих из любой функции 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 в качестве значения switch и значений состояния для операторов case. В зависимости от типов функций, вызываемых приложением, некоторые значения состояния можно игнорировать. Определение различных значений состояния см. в описании параметра dwInternetStatusобъекта InternetStatusCallback.

    Следующая инструкция 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 (WinHTTP).

 

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

InternetSetStatusCallback

InternetStatusCallback