I'm implementing my custom protocol handler by implementing IInternetProtocol interface and registering COM object in HKEY_CLASSES_ROOT\PROTOCOLS\Handler.
I want to be able to process the request and just leave the browser window as is (i.e. it must stay on the page with the link to my custom protocol).
Such a behavior normally achieved by returning HTTP 204 response.
I have implemented IWinInetHttpInfo interface for this. It processes HTTP_QUERY_REQUEST_METHOD, HTTP_QUERY_CONTENT_TYPE, HTTP_QUERY_VERSION, HTTP_QUERY_RAW_HEADERS_CRLF, HTTP_QUERY_STATUS_CODE requests.
But this does not help. Internet Explorer still switches the original page to a blank one with the URL of my custom protocol.
Any help, please?
Code:
SchemeHandlerImpl::SchemeHandlerImpl()
{
m_headers =
"HTTP/1.1 204 No Content\r\n"
"Content-Length: 0\r\n"
"Connection: close\r\n"
"\r\n";
m_response = "";
}
STDMETHODIMP SchemeHandlerImpl::Abort(HRESULT, DWORD)
{
return S_OK;
}
STDMETHODIMP SchemeHandlerImpl::Continue(PROTOCOLDATA *)
{
return S_OK;
}
STDMETHODIMP SchemeHandlerImpl::Resume()
{
return S_OK;
}
STDMETHODIMP SchemeHandlerImpl::Start(
LPCWSTR url,
IInternetProtocolSink *sink,
IInternetBindInfo *,
DWORD grfPI,
HANDLE_PTR)
{
m_responsePos = 0;
sink->ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, L"text/html");
sink->ReportData(BSCF_FIRSTDATANOTIFICATION, 0, (ULONG)m_response.size());
sink->ReportData(BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
(ULONG)m_response.size(), (ULONG)m_response.size());
sink->ReportResult(S_OK, 0, nullptr);
return S_OK;
}
STDMETHODIMP SchemeHandlerImpl::Suspend()
{
return S_OK;
}
STDMETHODIMP SchemeHandlerImpl::Terminate(DWORD)
{
return S_OK;
}
STDMETHODIMP SchemeHandlerImpl::LockRequest(DWORD)
{
return S_OK;
}
STDMETHODIMP SchemeHandlerImpl::Read(LPVOID pv, ULONG to_read, ULONG *read)
{
if (to_read > (m_response.size() - m_responsePos))
to_read = m_response.size() - m_responsePos;
if (to_read)
{
std::memcpy(pv, &m_response.front() + m_responsePos, to_read);
m_responsePos += to_read;
}
*read = to_read;
return to_read ? S_OK : S_FALSE;
}
STDMETHODIMP SchemeHandlerImpl::Seek(LARGE_INTEGER, DWORD, ULARGE_INTEGER*)
{
return E_NOTIMPL;
}
STDMETHODIMP SchemeHandlerImpl::UnlockRequest()
{
return S_OK;
}
STDMETHODIMP SchemeHandlerImpl::QueryInfo(
DWORD dwOption,
LPVOID pBuffer,
DWORD *pcbBuf,
DWORD *pdwFlags,
DWORD *pdwReserved)
{
if (LOWORD(dwOption) == HTTP_QUERY_REQUEST_METHOD)
{
wchar_t result[] = L"GET";
std::memcpy(pBuffer, result, sizeof(result)-2);
*pcbBuf = sizeof(result)-2;
return S_OK;
}
if (LOWORD(dwOption) == HTTP_QUERY_CONTENT_TYPE)
{
wchar_t result[] = L"text/html";
std::memcpy(pBuffer, result, sizeof(result)-2);
*pcbBuf = sizeof(result)-2;
return S_OK;
}
if (LOWORD(dwOption) == HTTP_QUERY_VERSION)
{
wchar_t result[] = L"HTTP/1.1";
std::memcpy(pBuffer, result, sizeof(result)-2);
*pcbBuf = sizeof(result)-2;
return S_OK;
}
if (LOWORD(dwOption) == HTTP_QUERY_RAW_HEADERS_CRLF)
{
if (dwOption & HTTP_QUERY_FLAG_REQUEST_HEADERS)
return E_NOTIMPL;
std::wstring wheaders(m_headers.cbegin(), m_headers.cend());
auto size = wheaders.size() * 2;
if (*pcbBuf < size)
return E_INVALIDARG;
std::memcpy(pBuffer, &wheaders.front(), size);
*pcbBuf = size;
return S_OK;
}
if (LOWORD(dwOption) == HTTP_QUERY_STATUS_CODE)
{
if (dwOption & HTTP_QUERY_FLAG_NUMBER)
{
UINT code = 204;
std::memcpy(pBuffer, &code, 4);
*pcbBuf = 4;
return S_OK;
}
else
{
wchar_t code[] = L"204";
std::memcpy(pBuffer, code, sizeof(code)-2);
*pcbBuf = sizeof(code)-2;
return S_OK;
}
}
return E_FAIL;
}
STDMETHODIMP SchemeHandlerImpl::QueryOption(
DWORD dwOption,
LPVOID pBuffer,
DWORD *pcbBuf)
{
return INET_E_DEFAULT_ACTION;
}