WebBrowser 控制項 (MSHTML) 原生僅支援導航至 URL 或檔案路徑,無直接方法顯示記憶體中的 HTML 字串。本文提供繼承 CHtmlView 的解決方案:先載入空白 HTML 資源,再透過 IHTMLDocument2 介面注入 body.innerHTML。
在資源檔 (.rc) 新增 HTML 資源 (IDR_EMPTY_HTML) 內容極簡:
<html><body></body></html>
void CMemoryHtmlView::NavigateMemory()
{
CString strApp = AfxGetAppName();
CString strResID; strResID.Format(_T("%d"), IDR_EMPTY_HTML);
// res://協定載入模組資源
CString strPath = _T("res://") + strApp + _T(".exe/") + strResID;
Navigate2(strPath);
m_bMemoryMode = TRUE;
}
void CMemoryHtmlView::OnDocumentComplete(LPCTSTR lpszURL)
{
if (m_bMemoryMode)
{
LPDISPATCH pDisp = GetHtmlDocument();
ASSERT(pDisp);
HRESULT hr = pDisp->QueryInterface(IID_IHTMLDocument2, (void**)&m_pHtmlDoc2);
if (SUCCEEDED(hr))
ShowMemoryHtml(); // 實際注入
}
CHtmlView::OnDocumentComplete(lpszURL);
}
BOOL CMemoryHtmlView::ShowMemoryHtml()
{
if (!m_pHtmlDoc2 || m_strHtmlContent.IsEmpty()) return FALSE;
IHTMLElement* pBody = NULL;
HRESULT hr = m_pHtmlDoc2->get_body(&pBody);
if (SUCCEEDED(hr) && pBody)
{
_bstr_t bstrHtml(m_strHtmlContent);
hr = pBody->put_innerHTML(bstrHtml);
pBody->Release();
return SUCCEEDED(hr);
}
return FALSE;
}
BOOL CMemoryHtmlView::PutHtmlContent(LPCTSTR lpszHtml)
{
m_strHtmlContent = lpszHtml;
if (m_bMemoryMode && m_pHtmlDoc2)
return ShowMemoryHtml(); // 已載入完成,直接注入
else
NavigateMemory(); // 尚未載入,先導航空白頁
return TRUE;
}
res:// 協定:res://模組名.exe/資源ID 載入內嵌資源。IHTMLDocument2::get_body 取得 <body> 元素介面。IHTMLElement::put_innerHTML 設定內部 HTML,支援完整標籤結構。OnDocumentComplete 回呼中查詢介面,確保文件物件模型 (DOM) 就緒。| 方案 | 優點 | 缺點 |
|---|---|---|
| 本文方案 (IHTMLDocument2) | 無臨時檔、效能好、支援動態更新 | 需 MFC/ATL、依賴 MSHTML、程式碼稍多 |
| 寫入暫存檔 + Navigate | 極簡單、相容性佳 | I/O 開銷、需清理暫存檔、並發衝突 |
| IPersistStreamInit / LoadHtml | 標準持久化介面 | 介面較複雜、文件少 |