diff --git a/include/wx/msw/chkconf.h b/include/wx/msw/chkconf.h index f9a3ac8aba..f3e847deb8 100644 --- a/include/wx/msw/chkconf.h +++ b/include/wx/msw/chkconf.h @@ -236,7 +236,7 @@ #endif /* !wxUSE_ACTIVITYINDICATOR && !_MSC_VER */ /* 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 #define wxUSE_WEBREQUEST_WINHTTP 0 #endif diff --git a/src/msw/webrequest_winhttp.cpp b/src/msw/webrequest_winhttp.cpp index 0f3c35a8b3..5f0098bdd6 100644 --- a/src/msw/webrequest_winhttp.cpp +++ b/src/msw/webrequest_winhttp.cpp @@ -15,6 +15,7 @@ #if wxUSE_WEBREQUEST && wxUSE_WEBREQUEST_WINHTTP #include "wx/mstream.h" +#include "wx/dynlib.h" #include "wx/msw/private.h" #include "wx/msw/private/webrequest_winhttp.h" @@ -22,13 +23,114 @@ #include "wx/log.h" #include "wx/utils.h" #include "wx/translation.h" + #include "wx/module.h" #endif -// For MSVC we can link in the required library explicitly, for the other -// compilers (e.g. MinGW) this needs to be done at makefiles level. -#ifdef __VISUALC__ -#pragma comment(lib, "winhttp") -#endif +// Helper class used to dynamically load the required symbols from winhttp.dll +class wxWinHTTP +{ +public: + 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 #ifndef WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY @@ -64,12 +166,12 @@ static wxString wxWinHTTPQueryHeaderString(HINTERNET hRequest, DWORD dwInfoLevel { wxString result; DWORD bufferLen = 0; - ::WinHttpQueryHeaders(hRequest, dwInfoLevel, pwszName, NULL, &bufferLen, + wxWinHTTP::WinHttpQueryHeaders(hRequest, dwInfoLevel, pwszName, NULL, &bufferLen, WINHTTP_NO_HEADER_INDEX); if ( ::GetLastError() == ERROR_INSUFFICIENT_BUFFER ) { wxWCharBuffer resBuf(bufferLen); - if ( ::WinHttpQueryHeaders(hRequest, dwInfoLevel, pwszName, + if ( wxWinHTTP::WinHttpQueryHeaders(hRequest, dwInfoLevel, pwszName, resBuf.data(), &bufferLen, WINHTTP_NO_HEADER_INDEX) ) { @@ -84,11 +186,11 @@ static wxString wxWinHTTPQueryOptionString(HINTERNET hInternet, DWORD dwOption) { wxString result; DWORD bufferLen = 0; - ::WinHttpQueryOption(hInternet, dwOption, NULL, &bufferLen); + wxWinHTTP::WinHttpQueryOption(hInternet, dwOption, NULL, &bufferLen); if ( ::GetLastError() == ERROR_INSUFFICIENT_BUFFER ) { wxWCharBuffer resBuf(bufferLen); - if ( ::WinHttpQueryOption(hInternet, dwOption, resBuf.data(), &bufferLen) ) + if ( wxWinHTTP::WinHttpQueryOption(hInternet, dwOption, resBuf.data(), &bufferLen) ) result.assign(resBuf); } @@ -98,13 +200,13 @@ static wxString wxWinHTTPQueryOptionString(HINTERNET hInternet, DWORD dwOption) static inline void wxWinHTTPSetOption(HINTERNET hInternet, DWORD dwOption, DWORD dwValue) { - ::WinHttpSetOption(hInternet, dwOption, &dwValue, sizeof(dwValue)); + wxWinHTTP::WinHttpSetOption(hInternet, dwOption, &dwValue, sizeof(dwValue)); } static void wxWinHTTPCloseHandle(HINTERNET hInternet) { - if ( !::WinHttpCloseHandle(hInternet) ) + if ( !wxWinHTTP::WinHttpCloseHandle(hInternet) ) { wxLogLastError("WinHttpCloseHandle"); } @@ -225,7 +327,7 @@ void wxWebRequestWinHTTP::WriteData() void* buffer = m_dataWriteBuffer.GetWriteBuf(dataWriteSize); m_dataStream->Read(buffer, dataWriteSize); - if ( !::WinHttpWriteData + if ( !wxWinHTTP::WinHttpWriteData ( m_request, m_dataWriteBuffer.GetData(), @@ -241,7 +343,7 @@ void wxWebRequestWinHTTP::CreateResponse() { wxLogTrace(wxTRACE_WEBREQUEST, "Request %p: creating response", this); - if ( !::WinHttpReceiveResponse(m_request, NULL) ) + if ( !wxWinHTTP::WinHttpReceiveResponse(m_request, NULL) ) { SetFailedWithLastError("Receiving response"); return; @@ -308,14 +410,14 @@ void wxWebRequestWinHTTP::Start() urlComps.dwUrlPathLength = 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"); return; } // Open a connection - m_connect = ::WinHttpConnect + m_connect = wxWinHTTP::WinHttpConnect ( m_sessionImpl.GetHandle(), wxString(urlComps.lpszHostName, urlComps.dwHostNameLength).wc_str(), @@ -334,7 +436,7 @@ void wxWebRequestWinHTTP::Start() // Open a request static const wchar_t* acceptedTypes[] = { L"*/*", NULL }; - m_request = ::WinHttpOpenRequest + m_request = wxWinHTTP::WinHttpOpenRequest ( m_connect, method.wc_str(), objectName.wc_str(), @@ -352,7 +454,7 @@ void wxWebRequestWinHTTP::Start() } // Register callback - if ( ::WinHttpSetStatusCallback + if ( wxWinHTTP::WinHttpSetStatusCallback ( m_request, wxRequestStatusCallback, @@ -397,7 +499,7 @@ void wxWebRequestWinHTTP::SendRequest() SetState(wxWebRequest::State_Active); // Send request - if ( !::WinHttpSendRequest + if ( !wxWinHTTP::WinHttpSendRequest ( m_request, allHeaders.wc_str(), allHeaders.length(), @@ -452,7 +554,7 @@ int wxWebResponseWinHTTP::GetStatus() const { DWORD status = 0; DWORD statusSize = sizeof(status); - if ( !::WinHttpQueryHeaders + if ( !wxWinHTTP::WinHttpQueryHeaders ( m_requestHandle, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, @@ -477,7 +579,7 @@ bool wxWebResponseWinHTTP::ReadData() { wxLogTrace(wxTRACE_WEBREQUEST, "Request %p: reading data", &m_request); - return ::WinHttpReadData + return wxWinHTTP::WinHttpReadData ( m_requestHandle, GetDataBuffer(m_readSize), @@ -510,7 +612,7 @@ bool wxWebAuthChallengeWinHTTP::Init() DWORD supportedSchemes; DWORD firstScheme; - if ( !::WinHttpQueryAuthSchemes + if ( !wxWinHTTP::WinHttpQueryAuthSchemes ( m_request.GetHandle(), &supportedSchemes, @@ -541,7 +643,7 @@ bool wxWebAuthChallengeWinHTTP::Init() void wxWebAuthChallengeWinHTTP::SetCredentials(const wxWebCredentials& cred) { - if ( !::WinHttpSetCredentials + if ( !wxWinHTTP::WinHttpSetCredentials ( m_request.GetHandle(), m_target, @@ -582,7 +684,7 @@ bool wxWebSessionWinHTTP::Open() else accessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; - m_handle = ::WinHttpOpen + m_handle = wxWinHTTP::WinHttpOpen ( GetHeaders().find("User-Agent")->second.wc_str(), accessType,