在 MFC 應用程式中嵌入 WebBrowser 控件時,常需程式化獲取或修改網頁 HTML 原始碼。本文介紹兩種主流方法並附關鍵代碼片段。
此法本質是透過 WM_COMMAND 訊息觸發控件內建的「檢視原始碼」功能,會彈出記事本視窗,屬於 Hack 手段,穩定性差。
#include "mshtmcid.h"
void CHtmlView::OnMethod1() {
CWnd* pWndShell = m_browser.GetWindow(GW_CHILD);
if (pWndShell) {
CWnd* pWnd = pWndShell->GetWindow(GW_CHILD);
if (pWnd != NULL) {
WPARAM wParam = MAKEWPARAM(IDM_VIEWSOURCE, 1);
pWnd->SendMessage(WM_COMMAND, wParam, (LPARAM)this->m_hWnd);
}
}
}
利用 COM 介面 IPersistStreamInit 將文檔寫入 IStream 流,再讀取字串。此法不干擾 UI,適合後台處理。
#include "mshtml.h"
void CMainFrame::OnMethod2() {
IHTMLDocument2* pHTMLDocument = NULL;
IPersistStreamInit* pPSI = NULL;
IStream* pStream = NULL;
HGLOBAL hHTMLText = NULL;
// 1. 獲取文檔介面
if (!(pHTMLDocument = (IHTMLDocument2*)m_pHtmlView->m_browser.GetDocument()))
return;
// 2. 獲取持久化介面
if (FAILED(pHTMLDocument->QueryInterface(IID_IPersistStreamInit, (void**)&pPSI)))
return;
// 3. 創建記憶體流
CreateStreamOnHGlobal(NULL, TRUE, &pStream);
// 4. 將文檔存入流
pPSI->Save(pStream, TRUE);
// 5. 從流讀取資料
STATSTG stat;
pStream->Stat(&stat, STATFLAG_NONAME);
hHTMLText = GlobalAlloc(GMEM_MOVEABLE, stat.cbSize.LowPart);
LPVOID pData = GlobalLock(hHTMLText);
LARGE_INTEGER li = {0};
pStream->Seek(li, STREAM_SEEK_SET, NULL);
pStream->Read(pData, stat.cbSize.LowPart, NULL);
GlobalUnlock(hHTMLText);
// 6. 轉換為 CString 處理
CString strHTML((LPCTSTR)pData);
// ... 對 strHTML 進行解析或修改 ...
// 7. 釋放資源
pStream->Release();
pPSI->Release();
pHTMLDocument->Release();
GlobalFree(hHTMLText);
}
| 維度 | 方法一 | 方法二 |
|---|---|---|
| 實現難度 | 低 | 中 |
| 是否阻塞 UI | 是(彈窗) | 否 |
| 適用場景 | 快速除錯 | 正式產品、後台解析 |
| 穩定性 | 依賴內部命令 ID,易失效 | 標準 COM 介面,穩健 |
建議: 生產環境務必使用方法二,符合 COM 程式設計規範,且能無縫整合後續的 HTML 解析與 DOM 操作邏輯。