c++winapiwininetwinhttp

WinHttpCrackUrl function gets wrong nScheme


After running the above code, the output result is not https, but Other(2).

Why does this happen?

The execution environment is Windows 10 (64-bit). The code is compiled as C++14.

#include <windows.h>
#include <WinInet.h>
#include <winhttp.h>
#include <iostream>
#include <string>

#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "Winhttp.lib")

int main() {
    std::wstring gitHubApiUrl = L"https://api.github.com";

    URL_COMPONENTSW urlComponents = {};
    urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);

    // Buffers for host and path
    wchar_t hostName[256] = {};
    wchar_t urlPath[1024] = {};
    urlComponents.lpszHostName = hostName;
    urlComponents.dwHostNameLength = ARRAYSIZE(hostName);
    urlComponents.lpszUrlPath = urlPath;
    urlComponents.dwUrlPathLength = ARRAYSIZE(urlPath);

    // Call WinHttpCrackUrl
    if (!WinHttpCrackUrl(gitHubApiUrl.c_str(), static_cast<DWORD>(gitHubApiUrl.size()), 0, &urlComponents)) {
        std::wcerr << L"Failed to parse URL. Error: " << GetLastError() << std::endl;
        return 0;
    }

    // Output parsed components
    std::wcout << L"Scheme: ";
    switch (urlComponents.nScheme) {
    case INTERNET_SCHEME_HTTP: std::wcout << L"HTTP"; break;
    case INTERNET_SCHEME_HTTPS: std::wcout << L"HTTPS"; break;
    default: std::wcout << L"Other (" << urlComponents.nScheme << L")"; break;
    }
    std::wcout << std::endl;

    std::wcout << L"Host Name: " << urlComponents.lpszHostName << std::endl;
    std::wcout << L"URL Path: " << urlComponents.lpszUrlPath << std::endl;
    return 0;
}

Solution

  • I found the reason, the reason for this problem is so weird. When #include <WinInet.h> is above #include <winhttp.h>, Other(2) will be output.

    Otherwise, if #include <winhttp.h> is above #include <WinInet.h>, https will be output normally, because the INTERNET_SCHEME enumeration is defined in both header files.

    Code:

    #include <windows.h>
    #include <WinInet.h>
    #include <winhttp.h>
    #include <iostream>
    #include <string>
    
    #pragma comment(lib, "wininet.lib")
    #pragma comment(lib, "Winhttp.lib")
    
    int main() {
        std::wstring gitHubApiUrl = L"https://api.github.com";
    
        URL_COMPONENTSW urlComponents = {};
        urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
    
        // Buffers for host and path
        wchar_t hostName[256] = {};
        wchar_t urlPath[1024] = {};
        urlComponents.lpszHostName = hostName;
        urlComponents.dwHostNameLength = ARRAYSIZE(hostName);
        urlComponents.lpszUrlPath = urlPath;
        urlComponents.dwUrlPathLength = ARRAYSIZE(urlPath);
    
        // Call WinHttpCrackUrl
        if (!WinHttpCrackUrl(gitHubApiUrl.c_str(), static_cast<DWORD>(gitHubApiUrl.size()), 0, &urlComponents)) {
            std::wcerr << L"Failed to parse URL. Error: " << GetLastError() << std::endl;
            return 0;
        }
    
        // Output parsed components
        std::wcout << L"Scheme: ";
        switch (urlComponents.nScheme) {
          case INTERNET_SCHEME_HTTP: std::wcout << L"HTTP"; break;
          case INTERNET_SCHEME_HTTPS: std::wcout << L"HTTPS"; break;
          default: std::wcout << L"Other (" << urlComponents.nScheme << L")"; break;
        }
        std::wcout << std::endl;
    
        std::wcout << L"Host Name: " << urlComponents.lpszHostName << std::endl;
        std::wcout << L"URL Path: " << urlComponents.lpszUrlPath << std::endl;
        return 0;
    }