我通过实现IInternetProtocol接口并在 HKEY_CLASSES_ROOT\PROTOCOLS\Handler 中注册 COM 对象来实现我的自定义协议处理程序。
我希望能够处理请求并保持浏览器窗口不变(即它必须保留在带有我的自定义协议链接的页面上)。
这种行为通常通过返回 HTTP 204 响应来实现。
我为此实现了IWinInetHttpInfo接口。它处理 HTTP_QUERY_REQUEST_METHOD、HTTP_QUERY_CONTENT_TYPE、HTTP_QUERY_VERSION、HTTP_QUERY_RAW_HEADERS_CRLF、HTTP_QUERY_STATUS_CODE 请求。
但这无济于事。Internet Explorer 仍然使用我的自定义协议的 URL 将原始页面切换为空白页面。
请问有什么帮助吗?
代码:
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;
}