Udostępnij za pośrednictwem


Aplikacja Visual C++ używająca ServerXMLHTTP lub XMLHTTP w trybie asynchronicznym musi pompować komunikaty

W tym artykule opisano, że do odbierania i wysyłania komunikatów należy użyć pompy komunikatów.

Oryginalna wersja produktu: Visual C++
Oryginalny numer KB: 303326

Podsumowanie

Począwszy od programu MSXML w wersji 3.0, obiekt żądania XMLHTTP używa Urlmon.dll. Jeśli ustawisz parametr asynchroniczny na VARIANT_TRUE podczas wywoływania open metody, funkcja URLMON używa mechanizmu kolejki komunikatów do powiadamiania aplikacji, gdy dane staną się dostępne, a readyState właściwość obiektu żądania XMLHTTP zostanie zmieniona, jak w poniższym przykładzie:

hr=pXMLHTTPReq->open("POST", "http://www.server1.com/test.asp", VARIANT_TRUE);

W aplikacji Visual C++ należy użyć pompy komunikatów do odbierania i wysyłania komunikatów. Jeśli aplikacja nie obsługuje poprawnie przychodzących komunikatów, aplikacja może przestać odpowiadać (zawieszać się), ponieważ readystate właściwość obiektu żądania XMLHTTP nie zostanie zmieniona.

Uwaga

Ten problem jest specyficzny dla deweloperów języka Visual C++.

Uwaga

Te informacje są specyficzne dla systemu Windows XP. Domyślnie system Windows XP jest dostarczany z MSXML3.0 Service Pack 2 (SP2).

Więcej informacji

W przypadku analizatora MSXML 2.5 dostarczanego z systemem Microsoft Windows 2000 nie jest wymagana żadna taka pompa komunikatów. W systemie Windows XP program MSXML 3.0 z dodatkiem SP2 jest zainstalowany w trybie zastępowania, więc może wystąpić ten problem.

Poniżej przedstawiono przykładową implementację pompy komunikatów z obiektem żądania XMLHTTP. Aby go przetestować, wklej kod do pliku .cpp, a następnie skompiluj i uruchom plik jako projekt aplikacji konsolowej Win32.

#import "msxml3.dll"
using namespace MSXML2; // For Msxml3.dll.

#include "stdio.h"

void dump_com_error(_com_error &e)
{
    printf("Error\n");
    printf("\a\tCode = %08lx\n", e.Error());
    printf("\a\tCode meaning = %s", e.ErrorMessage());
    _bstr_t bstrSource(e.Source());
    _bstr_t bstrDescription(e.Description());
    printf("\a\tSource = %s\n", (LPCSTR) bstrSource);
    printf("\a\tDescription = %s\n", (LPCSTR) bstrDescription);
}

int main()
{
    HRESULT hr = CoInitialize(NULL);

    try{
        IXMLHTTPRequestPtr pXMLHTTPReq = NULL;
        hr=pXMLHTTPReq.CreateInstance(__uuidof(XMLHTTP30));

        //Uncomment the following lines if you are using ServerXMLHTTPRequest.
        //IServerXMLHTTPRequestPtr pXMLHTTPReq = NULL;
        //hr=pXMLHTTPReq.CreateInstance(__uuidof(ServerXMLHTTP30));

        hr=pXMLHTTPReq->open("POST", "http://www.server1.com/test1.asp", VARIANT_TRUE);

        hr = pXMLHTTPReq->setRequestHeader("charset", "UTF-8");
        hr=pXMLHTTPReq->send("<?xml version=\"1.0\" encoding=\"UTF-8\"?><REQUEST>request1</REQUEST>");

        long readyState = READYSTATE_UNINITIALIZED;
        MSG msg;
        while (readyState != READYSTATE_COMPLETE)
        {
            //Without this message pump, readyState does not change.
            if (PeekMessage(&msg, 0, 0 ,0, PM_REMOVE))
            {
                TranslateMessage (&msg);
                DispatchMessage (&msg);
            }

            readyState = pXMLHTTPReq->GetreadyState();

        }
        MessageBox(NULL, "readyState is COMPLETE ", "readystate", MB_OK);

        long status= pXMLHTTPReq->Getstatus();
    }
    catch(_com_error &e)
    {
        dump_com_error(e);
    }
    return 0;
}

Uwaga

Przetwarzanie asynchroniczne w praktyce jest bardziej skomplikowane. Przed próbą użycia trybu asynchronicznego należy przetestować aplikację w trybie synchronicznym.

W przypadku korzystania z SeverXMLHTTPRequest obiektu należy uruchomić narzędzie Proxycfg, aby ustawić informacje o serwerze proxy. Aby uzyskać więcej informacji, zobacz Często zadawane pytania dotyczące serverXMLHTTP.

ServerXMLHTTP nie używa Urlmon.dll. Jeśli jednak używasz ServerXMLHTTP w trybie asynchronicznym, potrzebna jest również ta pompa komunikatów, ponieważ analizator wywołuje zdarzenie, wysyłając komunikaty z powrotem do wątku.

ServerXMLHTTP zawiera również metodę o nazwie waitForResponse , która nie jest dostępna w przypadku protokołu XMLHTTP. waitForResponse czeka, gdy żądanie asynchroniczne jest przetwarzane. Metoda waitForResponse automatycznie pompuje komunikaty okna, więc kod aplikacji klienta nie musi tego robić. Dzięki temu kod aplikacji może zostać uproszczony w następujący sposób:

hr=pXMLHTTPReq.CreateInstance(__uuidof(ServerXMLHTTP30));

hr=pXMLHTTPReq->open("POST", "http://www.server1.com/test1.asp", VARIANT_TRUE);

hr = pXMLHTTPReq->setRequestHeader("charset", "UTF-8");
hr=pXMLHTTPReq->send("<?xml version=\"1.0\" encoding=\"UTF-8\"?><REQUEST>request1</REQUEST>");

VARIANT Timeout;
VariantInit(&Timeout);
Timeout.vt = VT_I4;
Timeout.lVal = 60; // Timeout value of 60 seconds.

VARIANT_BOOL bSucceeded;
//Passing vtMissing as the first parameter sets the timeout value to infinite.
hr = pXMLHTTPReq->waitForResponse(Timeout, &bSucceeded);

long status= pXMLHTTPReq->Getstatus();