Load winhttp functions dynamically

winhttp cannot be added to the makefiles, because some MinGW distributions
(MinGW 5.3) do not have this library.
This commit is contained in:
Maarten Bent
2021-03-19 22:28:05 +01:00
parent 3cc48e2e56
commit c4343ed2d4
2 changed files with 126 additions and 24 deletions

View File

@@ -236,7 +236,7 @@
#endif /* !wxUSE_ACTIVITYINDICATOR && !_MSC_VER */ #endif /* !wxUSE_ACTIVITYINDICATOR && !_MSC_VER */
/* MinGW-w64 (32 and 64 bit) has winhttp.h available, legacy MinGW does not. */ /* MinGW-w64 (32 and 64 bit) has winhttp.h available, legacy MinGW does not. */
#if (!defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)) #if (!defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)) || !wxUSE_DYNLIB_CLASS
#undef wxUSE_WEBREQUEST_WINHTTP #undef wxUSE_WEBREQUEST_WINHTTP
#define wxUSE_WEBREQUEST_WINHTTP 0 #define wxUSE_WEBREQUEST_WINHTTP 0
#endif #endif

View File

@@ -15,6 +15,7 @@
#if wxUSE_WEBREQUEST && wxUSE_WEBREQUEST_WINHTTP #if wxUSE_WEBREQUEST && wxUSE_WEBREQUEST_WINHTTP
#include "wx/mstream.h" #include "wx/mstream.h"
#include "wx/dynlib.h"
#include "wx/msw/private.h" #include "wx/msw/private.h"
#include "wx/msw/private/webrequest_winhttp.h" #include "wx/msw/private/webrequest_winhttp.h"
@@ -22,13 +23,114 @@
#include "wx/log.h" #include "wx/log.h"
#include "wx/utils.h" #include "wx/utils.h"
#include "wx/translation.h" #include "wx/translation.h"
#include "wx/module.h"
#endif #endif
// For MSVC we can link in the required library explicitly, for the other // Helper class used to dynamically load the required symbols from winhttp.dll
// compilers (e.g. MinGW) this needs to be done at makefiles level. class wxWinHTTP
#ifdef __VISUALC__ {
#pragma comment(lib, "winhttp") public:
#endif static bool LoadLibrary()
{
bool result = m_winhttp.Load("winhttp.dll", wxDL_VERBATIM | wxDL_QUIET);
if ( !result )
return result;
#define wxLOAD_FUNC(name) \
wxDL_INIT_FUNC(, name, m_winhttp); \
result &= (name != NULL);
wxLOAD_FUNC(WinHttpQueryOption)
wxLOAD_FUNC(WinHttpQueryHeaders)
wxLOAD_FUNC(WinHttpSetOption)
wxLOAD_FUNC(WinHttpWriteData)
wxLOAD_FUNC(WinHttpCloseHandle)
wxLOAD_FUNC(WinHttpReceiveResponse)
wxLOAD_FUNC(WinHttpCrackUrl)
wxLOAD_FUNC(WinHttpConnect)
wxLOAD_FUNC(WinHttpOpenRequest)
wxLOAD_FUNC(WinHttpSetStatusCallback)
wxLOAD_FUNC(WinHttpSendRequest)
wxLOAD_FUNC(WinHttpReadData)
wxLOAD_FUNC(WinHttpQueryAuthSchemes)
wxLOAD_FUNC(WinHttpSetCredentials)
wxLOAD_FUNC(WinHttpOpen)
if ( !result )
m_winhttp.Unload();
return result;
}
typedef BOOL(WINAPI* WinHttpQueryOption_t)(HINTERNET, DWORD, LPVOID, LPDWORD);
static WinHttpQueryOption_t WinHttpQueryOption;
typedef BOOL(WINAPI* WinHttpQueryHeaders_t)(HINTERNET, DWORD, LPCWSTR, LPVOID, LPDWORD, LPDWORD);
static WinHttpQueryHeaders_t WinHttpQueryHeaders;
typedef BOOL(WINAPI* WinHttpSetOption_t)(HINTERNET, DWORD, LPVOID, DWORD);
static WinHttpSetOption_t WinHttpSetOption;
typedef BOOL(WINAPI* WinHttpWriteData_t)(HINTERNET, LPCVOID, DWORD, LPDWORD);
static WinHttpWriteData_t WinHttpWriteData;
typedef BOOL(WINAPI* WinHttpCloseHandle_t)(HINTERNET);
static WinHttpCloseHandle_t WinHttpCloseHandle;
typedef BOOL(WINAPI* WinHttpReceiveResponse_t)(HINTERNET, LPVOID);
static WinHttpReceiveResponse_t WinHttpReceiveResponse;
typedef BOOL(WINAPI* WinHttpCrackUrl_t)(LPCWSTR, DWORD, DWORD, LPURL_COMPONENTS);
static WinHttpCrackUrl_t WinHttpCrackUrl;
typedef HINTERNET(WINAPI* WinHttpConnect_t)(HINTERNET, LPCWSTR, INTERNET_PORT, DWORD);
static WinHttpConnect_t WinHttpConnect;
typedef HINTERNET(WINAPI* WinHttpOpenRequest_t)(HINTERNET, LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR*, DWORD);
static WinHttpOpenRequest_t WinHttpOpenRequest;
typedef WINHTTP_STATUS_CALLBACK(WINAPI* WinHttpSetStatusCallback_t)(HINTERNET, WINHTTP_STATUS_CALLBACK, DWORD, DWORD_PTR);
static WinHttpSetStatusCallback_t WinHttpSetStatusCallback;
typedef BOOL(WINAPI* WinHttpSendRequest_t)(HINTERNET, LPCWSTR, DWORD, LPVOID, DWORD, DWORD, DWORD_PTR);
static WinHttpSendRequest_t WinHttpSendRequest;
typedef BOOL(WINAPI* WinHttpReadData_t)(HINTERNET, LPVOID, DWORD, LPDWORD);
static WinHttpReadData_t WinHttpReadData;
typedef BOOL(WINAPI* WinHttpQueryAuthSchemes_t)(HINTERNET, LPDWORD, LPDWORD, LPDWORD);
static WinHttpQueryAuthSchemes_t WinHttpQueryAuthSchemes;
typedef BOOL(WINAPI* WinHttpSetCredentials_t)(HINTERNET, DWORD, DWORD, LPCWSTR, LPCWSTR, LPVOID);
static WinHttpSetCredentials_t WinHttpSetCredentials;
typedef HINTERNET(WINAPI* WinHttpOpen_t)(LPCWSTR, DWORD, LPCWSTR, LPCWSTR, DWORD);
static WinHttpOpen_t WinHttpOpen;
private:
static wxDynamicLibrary m_winhttp;
};
wxDynamicLibrary wxWinHTTP::m_winhttp;
wxWinHTTP::WinHttpQueryOption_t wxWinHTTP::WinHttpQueryOption;
wxWinHTTP::WinHttpQueryHeaders_t wxWinHTTP::WinHttpQueryHeaders;
wxWinHTTP::WinHttpSetOption_t wxWinHTTP::WinHttpSetOption;
wxWinHTTP::WinHttpWriteData_t wxWinHTTP::WinHttpWriteData;
wxWinHTTP::WinHttpCloseHandle_t wxWinHTTP::WinHttpCloseHandle;
wxWinHTTP::WinHttpReceiveResponse_t wxWinHTTP::WinHttpReceiveResponse;
wxWinHTTP::WinHttpCrackUrl_t wxWinHTTP::WinHttpCrackUrl;
wxWinHTTP::WinHttpConnect_t wxWinHTTP::WinHttpConnect;
wxWinHTTP::WinHttpOpenRequest_t wxWinHTTP::WinHttpOpenRequest;
wxWinHTTP::WinHttpSetStatusCallback_t wxWinHTTP::WinHttpSetStatusCallback;
wxWinHTTP::WinHttpSendRequest_t wxWinHTTP::WinHttpSendRequest;
wxWinHTTP::WinHttpReadData_t wxWinHTTP::WinHttpReadData;
wxWinHTTP::WinHttpQueryAuthSchemes_t wxWinHTTP::WinHttpQueryAuthSchemes;
wxWinHTTP::WinHttpSetCredentials_t wxWinHTTP::WinHttpSetCredentials;
wxWinHTTP::WinHttpOpen_t wxWinHTTP::WinHttpOpen;
class wxWinHTTPModule : public wxModule
{
public:
virtual bool OnInit() wxOVERRIDE
{
return wxWinHTTP::LoadLibrary();
}
virtual void OnExit() wxOVERRIDE
{
}
wxDECLARE_DYNAMIC_CLASS(wxWinHTTPModule);
};
wxIMPLEMENT_DYNAMIC_CLASS(wxWinHTTPModule, wxModule);
// Define constants potentially missing in old SDKs // Define constants potentially missing in old SDKs
#ifndef WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY #ifndef WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY
@@ -64,12 +166,12 @@ static wxString wxWinHTTPQueryHeaderString(HINTERNET hRequest, DWORD dwInfoLevel
{ {
wxString result; wxString result;
DWORD bufferLen = 0; DWORD bufferLen = 0;
::WinHttpQueryHeaders(hRequest, dwInfoLevel, pwszName, NULL, &bufferLen, wxWinHTTP::WinHttpQueryHeaders(hRequest, dwInfoLevel, pwszName, NULL, &bufferLen,
WINHTTP_NO_HEADER_INDEX); WINHTTP_NO_HEADER_INDEX);
if ( ::GetLastError() == ERROR_INSUFFICIENT_BUFFER ) if ( ::GetLastError() == ERROR_INSUFFICIENT_BUFFER )
{ {
wxWCharBuffer resBuf(bufferLen); wxWCharBuffer resBuf(bufferLen);
if ( ::WinHttpQueryHeaders(hRequest, dwInfoLevel, pwszName, if ( wxWinHTTP::WinHttpQueryHeaders(hRequest, dwInfoLevel, pwszName,
resBuf.data(), &bufferLen, resBuf.data(), &bufferLen,
WINHTTP_NO_HEADER_INDEX) ) WINHTTP_NO_HEADER_INDEX) )
{ {
@@ -84,11 +186,11 @@ static wxString wxWinHTTPQueryOptionString(HINTERNET hInternet, DWORD dwOption)
{ {
wxString result; wxString result;
DWORD bufferLen = 0; DWORD bufferLen = 0;
::WinHttpQueryOption(hInternet, dwOption, NULL, &bufferLen); wxWinHTTP::WinHttpQueryOption(hInternet, dwOption, NULL, &bufferLen);
if ( ::GetLastError() == ERROR_INSUFFICIENT_BUFFER ) if ( ::GetLastError() == ERROR_INSUFFICIENT_BUFFER )
{ {
wxWCharBuffer resBuf(bufferLen); wxWCharBuffer resBuf(bufferLen);
if ( ::WinHttpQueryOption(hInternet, dwOption, resBuf.data(), &bufferLen) ) if ( wxWinHTTP::WinHttpQueryOption(hInternet, dwOption, resBuf.data(), &bufferLen) )
result.assign(resBuf); result.assign(resBuf);
} }
@@ -98,13 +200,13 @@ static wxString wxWinHTTPQueryOptionString(HINTERNET hInternet, DWORD dwOption)
static inline static inline
void wxWinHTTPSetOption(HINTERNET hInternet, DWORD dwOption, DWORD dwValue) void wxWinHTTPSetOption(HINTERNET hInternet, DWORD dwOption, DWORD dwValue)
{ {
::WinHttpSetOption(hInternet, dwOption, &dwValue, sizeof(dwValue)); wxWinHTTP::WinHttpSetOption(hInternet, dwOption, &dwValue, sizeof(dwValue));
} }
static static
void wxWinHTTPCloseHandle(HINTERNET hInternet) void wxWinHTTPCloseHandle(HINTERNET hInternet)
{ {
if ( !::WinHttpCloseHandle(hInternet) ) if ( !wxWinHTTP::WinHttpCloseHandle(hInternet) )
{ {
wxLogLastError("WinHttpCloseHandle"); wxLogLastError("WinHttpCloseHandle");
} }
@@ -225,7 +327,7 @@ void wxWebRequestWinHTTP::WriteData()
void* buffer = m_dataWriteBuffer.GetWriteBuf(dataWriteSize); void* buffer = m_dataWriteBuffer.GetWriteBuf(dataWriteSize);
m_dataStream->Read(buffer, dataWriteSize); m_dataStream->Read(buffer, dataWriteSize);
if ( !::WinHttpWriteData if ( !wxWinHTTP::WinHttpWriteData
( (
m_request, m_request,
m_dataWriteBuffer.GetData(), m_dataWriteBuffer.GetData(),
@@ -241,7 +343,7 @@ void wxWebRequestWinHTTP::CreateResponse()
{ {
wxLogTrace(wxTRACE_WEBREQUEST, "Request %p: creating response", this); wxLogTrace(wxTRACE_WEBREQUEST, "Request %p: creating response", this);
if ( !::WinHttpReceiveResponse(m_request, NULL) ) if ( !wxWinHTTP::WinHttpReceiveResponse(m_request, NULL) )
{ {
SetFailedWithLastError("Receiving response"); SetFailedWithLastError("Receiving response");
return; return;
@@ -308,14 +410,14 @@ void wxWebRequestWinHTTP::Start()
urlComps.dwUrlPathLength = urlComps.dwUrlPathLength =
urlComps.dwExtraInfoLength = (DWORD)-1; urlComps.dwExtraInfoLength = (DWORD)-1;
if ( !::WinHttpCrackUrl(m_url.wc_str(), m_url.length(), 0, &urlComps) ) if ( !wxWinHTTP::WinHttpCrackUrl(m_url.wc_str(), m_url.length(), 0, &urlComps) )
{ {
SetFailedWithLastError("Parsing URL"); SetFailedWithLastError("Parsing URL");
return; return;
} }
// Open a connection // Open a connection
m_connect = ::WinHttpConnect m_connect = wxWinHTTP::WinHttpConnect
( (
m_sessionImpl.GetHandle(), m_sessionImpl.GetHandle(),
wxString(urlComps.lpszHostName, urlComps.dwHostNameLength).wc_str(), wxString(urlComps.lpszHostName, urlComps.dwHostNameLength).wc_str(),
@@ -334,7 +436,7 @@ void wxWebRequestWinHTTP::Start()
// Open a request // Open a request
static const wchar_t* acceptedTypes[] = { L"*/*", NULL }; static const wchar_t* acceptedTypes[] = { L"*/*", NULL };
m_request = ::WinHttpOpenRequest m_request = wxWinHTTP::WinHttpOpenRequest
( (
m_connect, m_connect,
method.wc_str(), objectName.wc_str(), method.wc_str(), objectName.wc_str(),
@@ -352,7 +454,7 @@ void wxWebRequestWinHTTP::Start()
} }
// Register callback // Register callback
if ( ::WinHttpSetStatusCallback if ( wxWinHTTP::WinHttpSetStatusCallback
( (
m_request, m_request,
wxRequestStatusCallback, wxRequestStatusCallback,
@@ -397,7 +499,7 @@ void wxWebRequestWinHTTP::SendRequest()
SetState(wxWebRequest::State_Active); SetState(wxWebRequest::State_Active);
// Send request // Send request
if ( !::WinHttpSendRequest if ( !wxWinHTTP::WinHttpSendRequest
( (
m_request, m_request,
allHeaders.wc_str(), allHeaders.length(), allHeaders.wc_str(), allHeaders.length(),
@@ -452,7 +554,7 @@ int wxWebResponseWinHTTP::GetStatus() const
{ {
DWORD status = 0; DWORD status = 0;
DWORD statusSize = sizeof(status); DWORD statusSize = sizeof(status);
if ( !::WinHttpQueryHeaders if ( !wxWinHTTP::WinHttpQueryHeaders
( (
m_requestHandle, m_requestHandle,
WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
@@ -477,7 +579,7 @@ bool wxWebResponseWinHTTP::ReadData()
{ {
wxLogTrace(wxTRACE_WEBREQUEST, "Request %p: reading data", &m_request); wxLogTrace(wxTRACE_WEBREQUEST, "Request %p: reading data", &m_request);
return ::WinHttpReadData return wxWinHTTP::WinHttpReadData
( (
m_requestHandle, m_requestHandle,
GetDataBuffer(m_readSize), GetDataBuffer(m_readSize),
@@ -510,7 +612,7 @@ bool wxWebAuthChallengeWinHTTP::Init()
DWORD supportedSchemes; DWORD supportedSchemes;
DWORD firstScheme; DWORD firstScheme;
if ( !::WinHttpQueryAuthSchemes if ( !wxWinHTTP::WinHttpQueryAuthSchemes
( (
m_request.GetHandle(), m_request.GetHandle(),
&supportedSchemes, &supportedSchemes,
@@ -541,7 +643,7 @@ bool wxWebAuthChallengeWinHTTP::Init()
void void
wxWebAuthChallengeWinHTTP::SetCredentials(const wxWebCredentials& cred) wxWebAuthChallengeWinHTTP::SetCredentials(const wxWebCredentials& cred)
{ {
if ( !::WinHttpSetCredentials if ( !wxWinHTTP::WinHttpSetCredentials
( (
m_request.GetHandle(), m_request.GetHandle(),
m_target, m_target,
@@ -582,7 +684,7 @@ bool wxWebSessionWinHTTP::Open()
else else
accessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; accessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
m_handle = ::WinHttpOpen m_handle = wxWinHTTP::WinHttpOpen
( (
GetHeaders().find("User-Agent")->second.wc_str(), GetHeaders().find("User-Agent")->second.wc_str(),
accessType, accessType,