处理InternetCloseHandle失败

时间:2017-07-18 10:13:10

标签: c++ winapi wininet

简介及相关信息:

我正在学习WinInet。我写过(以我的拙见)和#34;典型的"一段代码,最后需要执行清理:

DWORD CSomeClass::MVCE4StackOverflow()
{
    DWORD errorCode = ERROR_SUCCESS;

    URL_COMPONENTS urlComp;

    ::ZeroMemory(&urlComp, sizeof(URL_COMPONENTS));
    urlComp.dwStructSize = sizeof(URL_COMPONENTS);
    urlComp.dwHostNameLength    = -1;
    urlComp.dwSchemeLength      = -1;
    urlComp.dwUrlPathLength     = -1;

    if (!::InternetCrackUrl(m_URL.c_str(), m_URL.length(), 0, &urlComp))
    {
        errorCode = ::GetLastError();
        return errorCode;
    }

    HINTERNET hInternetSession = ::InternetOpen("WinInet",
                                     INTERNET_OPEN_TYPE_DIRECT, 
                                     NULL, NULL, 0);

    if (NULL == hInternetSession)
    {
        errorCode = ::GetLastError();
        return errorCode;
    }

    std::string hostname(urlComp.dwHostNameLength, 0);
    ::memcpy(&hostname[0], urlComp.lpszHostName, urlComp.dwHostNameLength);

    HINTERNET hHttpSession = ::InternetConnect(hInternetSession, 
                             hostname.c_str(), 
                             INTERNET_DEFAULT_HTTP_PORT, 0, 0, 
                             INTERNET_SERVICE_HTTP, 0, NULL);

    if (NULL == hHttpSession)
    {
        errorCode = ::GetLastError();
        return errorCode;
    }

    HINTERNET hHttpRequest = ::HttpOpenRequest(hHttpSession, "POST", 
                             urlComp.lpszUrlPath, 0, 0, 0, 
                             INTERNET_FLAG_RELOAD, 0);

    if (NULL == hHttpRequest)
    {
        errorCode = ::GetLastError();
        return errorCode;
    }

    const char header[] = "Content-Type: application/x-www-form-urlencoded";
    std::string data = "input=1234";

    if (!::HttpSendRequest(hHttpRequest, header, strlen(header), 
        &data[0], data.length()))
    {
        errorCode = ::GetLastError();
        return errorCode;
    }

    DWORD dwBytesRead = 0;
    BOOL result = false;

    char szBuffer[1025] = "";
    char *temp = szBuffer;
    const DWORD dwBytes2Read = sizeof(szBuffer) - 1;

    do{

        result = ::InternetReadFile(hHttpRequest, szBuffer, dwBytes2Read, &dwBytesRead);

        if (FALSE == result)
        {
            errorCode = ::GetLastError();
        }

        temp += dwBytesRead;

    } while (result && dwBytesRead > 0);

    // need error handling for below 3 
    result = ::InternetCloseHandle(hHttpRequest);
    result = ::InternetCloseHandle(hHttpSession);
    result = ::InternetCloseHandle(hInternetSession);

    return errorCode;   
}

问题:

在提供的代码示例中,我需要连续3次调用InternetCloseHandle

我不知道如何构造该部分代码以执行正确的错误处理。

我的想法是做以下事情:

result = ::InternetCloseHandle(hHttpRequest);
if(result)
{
    result = ::InternetCloseHandle(hHttpSession);
    if (result) 
    {
        result = ::InternetCloseHandle(hInternetSession);
        if(!result) return ::GetLastError();
    }
    else return ::GetLastError();
}
else return ::GetLastError();

然而,作为WinInet的新手,我不确定我的解决方案是否正确。

问题:

请告诉我如何在提供的代码示例中处理方案?

我知道我的问题可能令人困惑,但请注意英语不是我的母语。请发表评论,寻求进一步的澄清。

更新#1:

我试图申请RAII:

#include <Windows.h>
#include <iostream>
#include <WinInet.h>

#pragma comment(lib, "Wininet.lib")

class CInternetOpenRAII
{
    HINTERNET hIntSession;

public:

    CInternetOpenRAII(){}

    HINTERNET get() const { return hIntSession; }

    DWORD init()
    {
        hIntSession = ::InternetOpen("WinInet", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);

        return hIntSession ? ERROR_SUCCESS : ::GetLastError();
    }

    ~CInternetOpenRAII()
    { 
        if(hIntSession) 
        {
            if(!::InternetCloseHandle(hIntSession)) 
            {
                std::cerr << "InternetOpen failed with GetLastErrorCode: " << ::GetLastError();
            }
        }
    }
};

class CInternetConnectRAII
{
    HINTERNET hHttpSession;

public:

    CInternetConnectRAII() {}

    HINTERNET get() const { return hHttpSession; }

    DWORD init(const HINTERNET &hIntSession, const char *url)
    {
        hHttpSession = ::InternetConnect(hIntSession, url, INTERNET_DEFAULT_HTTP_PORT, 0, 0, INTERNET_SERVICE_HTTP, 0, NULL);

        return hHttpSession ? ERROR_SUCCESS : ::GetLastError();
    }

    ~CInternetConnectRAII()
    {
        if(hHttpSession) 
        {
            if(!::InternetCloseHandle(hHttpSession)) 
            {
                std::cerr << "InternetConnect failed with GetLastErrorCode: " << ::GetLastError();
            }
        }
    }
};

class CHttpOpenRequestRAII
{
    HINTERNET hHttpRequest;

public:

    CHttpOpenRequestRAII() {}

    HINTERNET get() const { return hHttpRequest; }

    DWORD init(const HINTERNET &hHttpSession, const char *request)
    {
        hHttpRequest = ::HttpOpenRequest(hHttpSession, "POST", request, 0, 0, 0, INTERNET_FLAG_RELOAD, 0);

        return hHttpRequest ? ERROR_SUCCESS : ::GetLastError(); 
    }

    DWORD doRequest(const char *data, size_t dataLength, const char *header, size_t headerLength)
    {
        if (!::HttpSendRequest(hHttpRequest, header, headerLength, (void *)data, dataLength))
            return ::GetLastError();

        CHAR szBuffer[10] = "";
        DWORD dwRead = 0;
        const int dwBytes2Read = sizeof(szBuffer) - 1;

        while (::InternetReadFile(hHttpRequest, szBuffer, dwBytes2Read, &dwRead) && dwRead)
        {
            std::cout << szBuffer;
        }

        return ERROR_SUCCESS;
    }

    ~CHttpOpenRequestRAII()
    {
        if(hHttpRequest) 
        {
            if(!::InternetCloseHandle(hHttpRequest)) 
            {
                std::cerr << "HttpOpenRequest failed with GetLastErrorCode: " << ::GetLastError();
            }
        }
    }
};

int main()
{
    DWORD error = ERROR_SUCCESS;

    CInternetOpenRAII session;

    error = session.init();
    if(error) return error;

    CInternetConnectRAII conn;

    error = conn.init(session.get(), "www.test.com");
    if(error) return error;

    CHttpOpenRequestRAII req;

    error = req.init(conn.get(), "/home/something");
    if(error) return error;

    error = req.doRequest("parameter=1234", strlen("parameter=1234"),
        "Content-Type: application/x-www-form-urlencoded", strlen("Content-Type: application/x-www-form-urlencoded"));
    if(error) return error;

    return 0;
}

现在我不知道如何处理析构函数中的错误。有人可以查看代码并提供一些建议吗?

0 个答案:

没有答案