3

我不确定这是否是缺乏对 msdn 的了解。我有以下代码:

    #include "stdafx.h"
    #include <iostream>
    #include <string>
    #include <windows.h>
    #include <WinHttp.h>
    #include "myHTTP.h"
int main(){
    WinHTTP newHTTP("test", "test");
        bool myResult;

        newHTTP.httpConnect(L"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36",
        L"https://pages.awscloud.com/awsomedayonlineconference-reg.html",
        1,
        L"GET");

        newHTTP.httpAddHeader(L"Content-Type: application/x-www-form-urlencoded\r\n");
        newHTTP.httpSend();
        myResult = newHTTP.httpReceive();



        newHTTP.closeHandles();
 return 0;
}

我为此有一个类,并且正在执行以下行://打开请求-此时未连接

hRequest = WinHttpOpenRequest(hConnect, protocol.c_str(), NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);

if (!hRequest) {
    printf("error2: %d", GetLastError());
}

所以基本上当我运行我的软件时,它会返回这里,因为调用 winhttpopenrequest 时 !hrequest 是空的。我添加了 getlasterror 来看看为什么会这样,但我得到的唯一输出是:

error2: 6

然后我阅读了 winhttp 的 msdn,我可以在这里看到函数返回的错误:https ://msdn.microsoft.com/en-us/library/windows/desktop/aa384099(v=vs.85).aspx但是这个神秘的错误 6 对我来说毫无意义。

有关查看为什么句柄无效的任何帮助?

完整的课程代码:

#pragma once
// WinHTTP wrapper for web protocol -- windows 8.1+
class WinHTTP {

private:
    std::string siteUsername, sitePassword;
    std::wstring UA, URL;
    bool bResult = false;
    DWORD dwSize = sizeof(DWORD); // used to handle reading data in bytes
    LPSTR pszOutBuffer; // used to Allocate space for the buffer.
    DWORD dwDownloaded = 0; // set to null if using asynchronously and use in callback function only
    HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL;

public:
    WinHTTP(std::string myuser = "", std::string mypass = "") {
        siteUsername = myuser;
        sitePassword = mypass;
    }

    // TODO: update to be able to add proxy details either here or before. do check if proxy has been detected in here and open/connect accordingly 
    void httpConnect(std::wstring userAgent, std::wstring myURL, int isHTTPS, std::wstring protocol) {

        UA = userAgent;
        URL = myURL;

        std::wstring acceptTypes = L"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8";

        int portToUse;
        if (isHTTPS == 1) {
            portToUse = 443;
        }
        else {
            portToUse = 80;
        }

        //initialize http and return session handle -- use c_str to convert wstring to LPCWSTR
        hSession = WinHttpOpen(UA.c_str(),
            WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);

        //make the connection request
        if (hSession) {
            hConnect = WinHttpConnect(hSession, URL.c_str(), portToUse, 0);
        }
        else {
            std::cout << "winhttpconnect error " << GetLastErrorAsString();
        }

        // open the request - not connected at this point
        hRequest = WinHttpOpenRequest(hConnect, protocol.c_str(), NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);

        if (!hRequest) {
            std::cout << "winhttpopenrequest error " << GetLastErrorAsString();
        }

    }

    std::string GetLastErrorAsString()
    {
        //Get the error message, if any.
        DWORD errorMessageID = ::GetLastError();
        if (errorMessageID == 0)
            return std::string(); //No error message has been recorded

        LPSTR messageBuffer = nullptr;
        size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);

        std::string message(messageBuffer, size);

        //Free the buffer.
        LocalFree(messageBuffer);

        return message;
    }

    void httpAddHeader(std::wstring myheader) {

        if (hRequest) {
            bResult = WinHttpAddRequestHeaders(hRequest, myheader.c_str(), (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD);
        }

    }

    bool httpSend() {
        if (hRequest) {
            bResult = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
        }

        if (!bResult) {
            std::cout << "winhttpsendrequest error " << GetLastErrorAsString();
            return false;
        }
        else {
            return true;
        }
    }

    bool httpReceive() {

        if (bResult) {
            bResult = WinHttpReceiveResponse(hRequest, NULL);
        }

        if (bResult) {

            do
            {
                // Check for available data.
                dwSize = 0; //query data available looks for data in bytes
                if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
                {
                    std::cout << "WinHttpQueryDataAvailable error " << GetLastErrorAsString();
                    break;
                }

                // No more available data.
                if (!dwSize)
                    return false;

                // Allocate space for the buffer. as dwSize now holds the size of the request
                pszOutBuffer = new char[dwSize + 1];  // just a way of freeing up memory 
                if (!pszOutBuffer)
                {
                    printf("Out of memory\n"); // couldnt allocate enough
                    return false;
                }

                ZeroMemory(pszOutBuffer, dwSize + 1); // fills a block of memory with 0s

                                                      // we know the expect size and have the pszoutbffer to write to - read the Data.
                if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer,
                    dwSize, &dwDownloaded))
                {
                        std::cout << "WinHttpReadData error " << GetLastErrorAsString();
                    return false;
                }
                else
                {
                    printf("%s", pszOutBuffer);
                }

                // Free the memory allocated to the buffer.
                delete[] pszOutBuffer;
                return true;

                // This condition should never be reached since WinHttpQueryDataAvailable
                // reported that there are bits to read.
                if (!dwDownloaded)
                    return false;

            } while (dwSize > 0);

        }

        return false;

    }

    void closeHandles() {
        if (hRequest) WinHttpCloseHandle(hRequest);
        if (hConnect) WinHttpCloseHandle(hConnect);
        if (hSession) WinHttpCloseHandle(hSession);
    }

};
4

1 回答 1

3

Why you get error code 6

Error code 6 is the System Error Code ERROR_INVALID_HANDLE.

It tells you that the hConnect you pass into WinHttpOpenRequest is invalid.

You only check hSession after your call to WinHttpOpen, and hRequest after your call to WinHttpOpenRequest. But you never check if hConnect is valid.

You need to check the hConnect returned by WinHttpConnect as well, and if it's invalid check GetLastError() before calling another WINAPI method:

hSession = WinHttpOpen(UA.c_str(), WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);

if (hSession) {
    hConnect = WinHttpConnect(hSession, URL.c_str(), portToUse, 0);

    if (hConnect) {
        hRequest = WinHttpOpenRequest(hConnect, protocol.c_str(), NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);

        if (!hRequest) {
            std::cout << "WinHttpOpenRequest error " << GetLastErrorAsString();
        }
    }
    else {
        std::cout << "WinHttpConnect error " << GetLastErrorAsString();
    }
}
else {
    std::cout << "WinHttpOpen error " << GetLastErrorAsString();
}

Why your call to WinHttpConnect fails

The docs tell us that WinHttpConnect expects a server name, not a URL:

pswzServerName [in]
Pointer to a null-terminated string that contains the host name of an HTTP server. Alternately, the string can contain the IP address of the site in ASCII, for example, 10.0.1.45.

However the string you provide contains a URL, which is not valid. You need to change "https://pages.awscloud.com/awsomedayonlineconference-reg.html" to "pages.awscloud.com", and then provide the path to the page as parameter in WinHttpOpenRequest:

hRequest = WinHttpOpenRequest(hConnect, protocol.c_str(), path.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);

where path is a string containing "/awsomedayonlineconference-reg.html".

You could split your URL into parts for this, or change your httpConnect method to get servername and path as separate parameters.

于 2018-06-05T09:01:41.307 回答