gpt4 book ai didi

c++ - 如何将 HTML 字符串加载到嵌入式 WebBrowser 控件?

转载 作者:搜寻专家 更新时间:2023-10-31 02:10:31 25 4
gpt4 key购买 nike

我知道网上有很多关于这个的文章,我试了很多。虽然我可以让我的浏览器加载互联网上的网页,但我无法设法让它从内存中加载 HTML。

大多数时候,下面的两种方法没有任何可见的效果;其他时候,他们会抛出错误。虽然其他人说“pPSIpHtmlDoc2 都没有指向有效对象”,但我不知道这是不是真的。我已经用注释标记了导致错误的行。

如果您想重现问题,我的问题末尾是完整的工作代码。

方法一

void WebBrowser::setHTML(const wchar_t *htmlSource) {
HRESULT hr;

IDispatch *pDispatch = 0;
IHTMLDocument2 *pHtmlDoc2 = 0;
IPersistStreamInit *pPSI = 0;
IStream *pStream = 0;
HGLOBAL hHTMLContent;

Navigate(L"about:blank");
hr = webBrowser2->get_Document(&pDispatch);
if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2);
//BSTR p = 0;
//if (SUCCEEDED(hr)) hr = pHtmlDoc2->get_readyState(&p);

if (SUCCEEDED(hr) && pHtmlDoc2) hr = pHtmlDoc2->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI);


// allocate global memory to copy the HTML content to
hHTMLContent = ::GlobalAlloc(GMEM_MOVEABLE, (::wcslen(htmlSource) + 1) * sizeof(TCHAR));
if (hHTMLContent)
{
wchar_t * p_content(static_cast<wchar_t *>(GlobalLock(hHTMLContent)));
::wcscpy(p_content, htmlSource); // Debbug: p_content contains HTML string
GlobalUnlock(hHTMLContent);

// create a stream object based on the HTML content
if (SUCCEEDED(hr) && pPSI) hr = ::CreateStreamOnHGlobal(hHTMLContent, TRUE, &pStream);
{
hr = pPSI->InitNew(); //////////// <- Sometime throw error.
if (SUCCEEDED(hr)) hr = pPSI->Load(pStream);
}
}
if (pStream) pStream->Release();
if (pPSI) pPSI->Release();
if (pHtmlDoc2) pHtmlDoc2->Release();
if (pDispatch) pDispatch->Release();

}

错误:

Exception thrown at 0x51539FB1 (mshtml.dll) in Test.exe: 0xC0000005: Access violation reading location 0x00000030

方法二

这个修改自this article在 CodeProject 上。在那个源代码中,它工作得很好,但是当我尝试适应我的代码时它不起作用:

void WebBrowser::setHTML2(const wchar_t *htmlSource) {
HRESULT hr;

IDispatch *pDispatch = 0;
IHTMLDocument2 *pHtmlDoc2 = 0;

this->Navigate(L"about:blank");
hr = this->webBrowser2->get_Document(&pDispatch);
if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2);
if (SUCCEEDED(hr) && pHtmlDoc2)
{
BSTR bstr = SysAllocString(htmlSource);
SAFEARRAY *psaStrings = SafeArrayCreateVector(VT_VARIANT, 0, 1);
if (psaStrings)
{
VARIANT *param;
hr = SafeArrayAccessData(psaStrings, (LPVOID*)&param);
if (SUCCEEDED(hr) && param)
{
param->vt = VT_BSTR;
param->bstrVal = bstr;
//if (SUCCEEDED(hr)) hr = SafeArrayUnaccessData(psaStrings);
if (SUCCEEDED(hr))
{
hr = pHtmlDoc2->write(psaStrings); //////////// <- Sometime throw error.
}
}

SafeArrayDestroy(psaStrings);
}
}
if (pHtmlDoc2) pHtmlDoc2->Release();
if (pDispatch) pDispatch->Release();
}

错误:

Exception thrown at 0x51577F2E (mshtml.dll) in Test.exe: 0xC0000005: Access violation reading location 0x000002C4

可能的第三种方法,Loading HTML content from a Stream来自 Microsoft,建议我从 DWebBrowserEvents2::DocumentComplete 事件的流中加载,我已经尝试过但未能弄清楚如何实现。

完整源代码

下面是完整的代码。我创建一个新的 Win32 项目并创建/修改以下文件:

浏览器.h

#include <comdef.h>
#include <Exdisp.h>
#include <ExDispid.h>
#include <MsHTML.h>
#include <Mshtmhst.h>
#include <string>
#include <tchar.h>
#include <Windows.h>

using namespace std;

class WebBrowser :
public IOleClientSite,
public IOleInPlaceSite,
public IStorage
{

public:

WebBrowser(HWND hWndParent);

bool CreateBrowser();

void SetText(const wchar_t* t);

void setHTML(const wchar_t *htmlSource);
void setHTML2(const wchar_t *htmlSource);

RECT PixelToHiMetric(const RECT& _rc);

virtual void SetRect(const RECT& _rc);

// ----- Control methods -----

void GoBack();

void GoForward();

void Refresh();

void Navigate(wstring szUrl);

// ----- IUnknown -----

virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
void**ppvObject) override;

virtual ULONG STDMETHODCALLTYPE AddRef(void);

virtual ULONG STDMETHODCALLTYPE Release(void);

// ---------- IOleWindow ----------

virtual HRESULT STDMETHODCALLTYPE GetWindow(
__RPC__deref_out_opt HWND *phwnd) override;

virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(
BOOL fEnterMode) override;

// ---------- IOleInPlaceSite ----------

virtual HRESULT STDMETHODCALLTYPE CanInPlaceActivate(void) override;

virtual HRESULT STDMETHODCALLTYPE OnInPlaceActivate(void) override;

virtual HRESULT STDMETHODCALLTYPE OnUIActivate(void) override;

virtual HRESULT STDMETHODCALLTYPE GetWindowContext(
__RPC__deref_out_opt IOleInPlaceFrame **ppFrame,
__RPC__deref_out_opt IOleInPlaceUIWindow **ppDoc,
__RPC__out LPRECT lprcPosRect,
__RPC__out LPRECT lprcClipRect,
__RPC__inout LPOLEINPLACEFRAMEINFO lpFrameInfo) override;

virtual HRESULT STDMETHODCALLTYPE Scroll(
SIZE scrollExtant) override;

virtual HRESULT STDMETHODCALLTYPE OnUIDeactivate(
BOOL fUndoable) override;

virtual HWND GetControlWindow();

virtual HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate(void) override;

virtual HRESULT STDMETHODCALLTYPE DiscardUndoState(void) override;

virtual HRESULT STDMETHODCALLTYPE DeactivateAndUndo(void) override;

virtual HRESULT STDMETHODCALLTYPE OnPosRectChange(
__RPC__in LPCRECT lprcPosRect) override;

// ---------- IOleClientSite ----------

virtual HRESULT STDMETHODCALLTYPE SaveObject(void) override;

virtual HRESULT STDMETHODCALLTYPE GetMoniker(
DWORD dwAssign,
DWORD dwWhichMoniker,
__RPC__deref_out_opt IMoniker **ppmk) override;

virtual HRESULT STDMETHODCALLTYPE GetContainer(
__RPC__deref_out_opt IOleContainer **ppContainer) override;

virtual HRESULT STDMETHODCALLTYPE ShowObject(void) override;
virtual HRESULT STDMETHODCALLTYPE OnShowWindow(
BOOL fShow) override;

virtual HRESULT STDMETHODCALLTYPE RequestNewObjectLayout(void) override;

// ----- IStorage -----

virtual HRESULT STDMETHODCALLTYPE CreateStream(
__RPC__in_string const OLECHAR *pwcsName,
DWORD grfMode,
DWORD reserved1,
DWORD reserved2,
__RPC__deref_out_opt IStream **ppstm) override;

virtual HRESULT STDMETHODCALLTYPE OpenStream(
const OLECHAR *pwcsName,
void *reserved1,
DWORD grfMode,
DWORD reserved2,
IStream **ppstm) override;

virtual HRESULT STDMETHODCALLTYPE CreateStorage(
__RPC__in_string const OLECHAR *pwcsName,
DWORD grfMode,
DWORD reserved1,
DWORD reserved2,
__RPC__deref_out_opt IStorage **ppstg) override;

virtual HRESULT STDMETHODCALLTYPE OpenStorage(
__RPC__in_opt_string const OLECHAR *pwcsName,
__RPC__in_opt IStorage *pstgPriority,
DWORD grfMode,
__RPC__deref_opt_in_opt SNB snbExclude,
DWORD reserved,
__RPC__deref_out_opt IStorage **ppstg) override;

virtual HRESULT STDMETHODCALLTYPE CopyTo(
DWORD ciidExclude,
const IID *rgiidExclude,
__RPC__in_opt SNB snbExclude,
IStorage *pstgDest) override;

virtual HRESULT STDMETHODCALLTYPE MoveElementTo(
__RPC__in_string const OLECHAR *pwcsName,
__RPC__in_opt IStorage *pstgDest,
__RPC__in_string const OLECHAR *pwcsNewName,
DWORD grfFlags) override;

virtual HRESULT STDMETHODCALLTYPE Commit(
DWORD grfCommitFlags) override;

virtual HRESULT STDMETHODCALLTYPE Revert(void) override;

virtual HRESULT STDMETHODCALLTYPE EnumElements(
DWORD reserved1,
void *reserved2,
DWORD reserved3,
IEnumSTATSTG **ppenum) override;

virtual HRESULT STDMETHODCALLTYPE DestroyElement(
__RPC__in_string const OLECHAR *pwcsName) override;

virtual HRESULT STDMETHODCALLTYPE RenameElement(
__RPC__in_string const OLECHAR *pwcsOldName,
__RPC__in_string const OLECHAR *pwcsNewName) override;

virtual HRESULT STDMETHODCALLTYPE SetElementTimes(
__RPC__in_opt_string const OLECHAR *pwcsName,
__RPC__in_opt const FILETIME *pctime,
__RPC__in_opt const FILETIME *patime,
__RPC__in_opt const FILETIME *pmtime) override;

virtual HRESULT STDMETHODCALLTYPE SetClass(
__RPC__in REFCLSID clsid) override;
virtual HRESULT STDMETHODCALLTYPE SetStateBits(
DWORD grfStateBits,
DWORD grfMask) override;

virtual HRESULT STDMETHODCALLTYPE Stat(
__RPC__out STATSTG *pstatstg,
DWORD grfStatFlag) override;

protected:

IOleObject* oleObject;
IOleInPlaceObject* oleInPlaceObject;

IWebBrowser2* webBrowser2;

LONG iComRefCount;

RECT rObject;

HWND hWndParent;
HWND hWndControl;

};

浏览器.cpp

#include "stdafx.h"
#include "Browser.h"



namespace tkString
{
wchar_t* Format(const wchar_t* format, ...)
{
va_list args;
va_start(args, format);

wchar_t *w = NULL;
int len = _vsnwprintf(NULL, 0, format, args) + 1;
if (len > 0)
{
w = new wchar_t[len];
w[0] = 0;
_vsnwprintf_s(w, len, len, format, args);
}
va_end(args);

return w;
}
}


void WebBrowser::SetText(const wchar_t* t)
{
const wchar_t* html = L"<html><head><meta http-equiv='x-ua-compatible' content='IE=edge'></head><body><code>%ls</code></body></html>";

if (t)
{
wchar_t *w = tkString::Format(html, t);
setHTML(w);
//setHTML2(w);
delete[] w;
}
else this->Navigate(L"https://google.com.vn");
}

void WebBrowser::setHTML(const wchar_t *htmlSource) {
HRESULT hr;

IDispatch *pDispatch = 0;
IHTMLDocument2 *pHtmlDoc2 = 0;
IPersistStreamInit *pPSI = 0;
IStream *pStream = 0;
HGLOBAL hHTMLContent;

Navigate(L"about:blank");
hr = webBrowser2->get_Document(&pDispatch);
if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2);
//BSTR p = 0;
//if (SUCCEEDED(hr)) hr = pHtmlDoc2->get_readyState(&p);

if (SUCCEEDED(hr) && pHtmlDoc2) hr = pHtmlDoc2->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI);


// allocate global memory to copy the HTML content to
hHTMLContent = ::GlobalAlloc(GMEM_MOVEABLE, (::wcslen(htmlSource) + 1) * sizeof(TCHAR));
if (hHTMLContent)
{
wchar_t * p_content(static_cast<wchar_t *>(GlobalLock(hHTMLContent)));
::wcscpy(p_content, htmlSource);
GlobalUnlock(hHTMLContent);

// create a stream object based on the HTML content
if (SUCCEEDED(hr) && pPSI) hr = ::CreateStreamOnHGlobal(hHTMLContent, TRUE, &pStream);

if (SUCCEEDED(hr) && pStream) hr = pPSI->InitNew();
if (SUCCEEDED(hr)) hr = pPSI->Load(pStream);
}
if (pStream) pStream->Release();
if (pPSI) pPSI->Release();
if (pHtmlDoc2) pHtmlDoc2->Release();
if (pDispatch) pDispatch->Release();

}

void WebBrowser::setHTML2(const wchar_t *htmlSource) {
HRESULT hr;

IDispatch *pDispatch = 0;
IHTMLDocument2 *pHtmlDoc2 = 0;

this->Navigate(L"about:blank");
hr = this->webBrowser2->get_Document(&pDispatch);
if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2);
if (SUCCEEDED(hr) && pHtmlDoc2)
{
BSTR bstr = SysAllocString(htmlSource);
SAFEARRAY *psaStrings = SafeArrayCreateVector(VT_VARIANT, 0, 1);
if (psaStrings)
{
VARIANT *param;
hr = SafeArrayAccessData(psaStrings, (LPVOID*)&param);
if (SUCCEEDED(hr) && param)
{
param->vt = VT_BSTR;
param->bstrVal = bstr;
//if (SUCCEEDED(hr)) hr = SafeArrayUnaccessData(psaStrings);
if (SUCCEEDED(hr)) hr = pHtmlDoc2->write(psaStrings);
}

SafeArrayDestroy(psaStrings);
}
}
if (pHtmlDoc2) pHtmlDoc2->Release();
if (pDispatch) pDispatch->Release();
}


WebBrowser::WebBrowser(HWND _hWndParent)
{
iComRefCount = 0;
::SetRect(&rObject, 0, 0, 600, 400);
hWndParent = _hWndParent;

if (CreateBrowser() == FALSE)
{
return;
}
webBrowser2->put_Visible(TRUE);
ShowWindow(GetControlWindow(), SW_SHOW);

this->Navigate(_T("about:blank"));
}

bool WebBrowser::CreateBrowser()
{
HRESULT hr;
hr = ::OleCreate(CLSID_WebBrowser,
IID_IOleObject, OLERENDER_DRAW, 0, this, this,
(void**)&oleObject);

if (FAILED(hr))
{
MessageBox(NULL, _T("Cannot create oleObject CLSID_WebBrowser"),
_T("Error"),
MB_ICONERROR);
return FALSE;
}

hr = oleObject->SetClientSite(this);
hr = OleSetContainedObject(oleObject, TRUE);

RECT posRect;
::SetRect(&rObject, 0, 0, 600, 400);
hr = oleObject->DoVerb(OLEIVERB_INPLACEACTIVATE,
NULL, this, -1, hWndParent, &posRect);
if (FAILED(hr))
{
MessageBox(NULL, _T("oleObject->DoVerb() failed"),
_T("Error"),
MB_ICONERROR);
return FALSE;
}

hr = oleObject->QueryInterface(&webBrowser2);
if (FAILED(hr))
{
MessageBox(NULL, _T("oleObject->QueryInterface(&webBrowser2) failed"),
_T("Error"),
MB_ICONERROR);
return FALSE;
}

return TRUE;
}

RECT WebBrowser::PixelToHiMetric(const RECT& _rc)
{
static bool s_initialized = false;
static int s_pixelsPerInchX, s_pixelsPerInchY;
if (!s_initialized)
{
HDC hdc = ::GetDC(0);
s_pixelsPerInchX = ::GetDeviceCaps(hdc, LOGPIXELSX);
s_pixelsPerInchY = ::GetDeviceCaps(hdc, LOGPIXELSY);
::ReleaseDC(0, hdc);
s_initialized = true;
}

RECT rc;
rc.left = MulDiv(2540, _rc.left, s_pixelsPerInchX);
rc.top = MulDiv(2540, _rc.top, s_pixelsPerInchY);
rc.right = MulDiv(2540, _rc.right, s_pixelsPerInchX);
rc.bottom = MulDiv(2540, _rc.bottom, s_pixelsPerInchY);
return rc;
}

void WebBrowser::SetRect(const RECT& _rc)
{
rObject = _rc;

{
RECT hiMetricRect = PixelToHiMetric(rObject);
SIZEL sz;
sz.cx = hiMetricRect.right - hiMetricRect.left;
sz.cy = hiMetricRect.bottom - hiMetricRect.top;
oleObject->SetExtent(DVASPECT_CONTENT, &sz);
}

if (oleInPlaceObject != 0)
{
oleInPlaceObject->SetObjectRects(&rObject, &rObject);
}
}

// ----- Control methods -----

void WebBrowser::GoBack()
{
this->webBrowser2->GoBack();
}

void WebBrowser::GoForward()
{
this->webBrowser2->GoForward();
}

void WebBrowser::Refresh()
{
this->webBrowser2->Refresh();
}

void WebBrowser::Navigate(wstring szUrl)
{
bstr_t url(szUrl.c_str());
variant_t flags(0x02u); //navNoHistory
this->webBrowser2->Navigate(url, &flags, 0, 0, 0);
}

// ----- IUnknown -----

HRESULT STDMETHODCALLTYPE WebBrowser::QueryInterface(REFIID riid,
void**ppvObject)
{
if (riid == __uuidof(IUnknown))
{
(*ppvObject) = static_cast<IOleClientSite*>(this);
}
else if (riid == __uuidof(IOleInPlaceSite))
{
(*ppvObject) = static_cast<IOleInPlaceSite*>(this);
}
else
{
return E_NOINTERFACE;
}

AddRef();
return S_OK;
}

ULONG STDMETHODCALLTYPE WebBrowser::AddRef(void)
{
iComRefCount++;
return iComRefCount;
}

ULONG STDMETHODCALLTYPE WebBrowser::Release(void)
{
iComRefCount--;
return iComRefCount;
}

// ---------- IOleWindow ----------

HRESULT STDMETHODCALLTYPE WebBrowser::GetWindow(
__RPC__deref_out_opt HWND *phwnd)
{
(*phwnd) = hWndParent;
return S_OK;
}

HRESULT STDMETHODCALLTYPE WebBrowser::ContextSensitiveHelp(
BOOL fEnterMode)
{
return E_NOTIMPL;
}

// ---------- IOleInPlaceSite ----------

HRESULT STDMETHODCALLTYPE WebBrowser::CanInPlaceActivate(void)
{
return S_OK;
}

HRESULT STDMETHODCALLTYPE WebBrowser::OnInPlaceActivate(void)
{
OleLockRunning(oleObject, TRUE, FALSE);
oleObject->QueryInterface(&oleInPlaceObject);
oleInPlaceObject->SetObjectRects(&rObject, &rObject);

return S_OK;

}

HRESULT STDMETHODCALLTYPE WebBrowser::OnUIActivate(void)
{
return S_OK;
}

HRESULT STDMETHODCALLTYPE WebBrowser::GetWindowContext(
__RPC__deref_out_opt IOleInPlaceFrame **ppFrame,
__RPC__deref_out_opt IOleInPlaceUIWindow **ppDoc,
__RPC__out LPRECT lprcPosRect,
__RPC__out LPRECT lprcClipRect,
__RPC__inout LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
HWND hwnd = hWndParent;

(*ppFrame) = NULL;
(*ppDoc) = NULL;
(*lprcPosRect).left = rObject.left;
(*lprcPosRect).top = rObject.top;
(*lprcPosRect).right = rObject.right;
(*lprcPosRect).bottom = rObject.bottom;
*lprcClipRect = *lprcPosRect;

lpFrameInfo->fMDIApp = false;
lpFrameInfo->hwndFrame = hwnd;
lpFrameInfo->haccel = NULL;
lpFrameInfo->cAccelEntries = 0;

return S_OK;
}

HRESULT STDMETHODCALLTYPE WebBrowser::Scroll(
SIZE scrollExtant)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::OnUIDeactivate(
BOOL fUndoable)
{
return S_OK;
}

HWND WebBrowser::GetControlWindow()
{
if (hWndControl != 0)
return hWndControl;

if (oleInPlaceObject == 0)
return 0;

oleInPlaceObject->GetWindow(&hWndControl);
return hWndControl;
}

HRESULT STDMETHODCALLTYPE WebBrowser::OnInPlaceDeactivate(void)
{
hWndControl = 0;
oleInPlaceObject = 0;

return S_OK;
}

HRESULT STDMETHODCALLTYPE WebBrowser::DiscardUndoState(void)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::DeactivateAndUndo(void)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::OnPosRectChange(
__RPC__in LPCRECT lprcPosRect)
{
return E_NOTIMPL;
}

// ---------- IOleClientSite ----------

HRESULT STDMETHODCALLTYPE WebBrowser::SaveObject(void)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::GetMoniker(
DWORD dwAssign,
DWORD dwWhichMoniker,
__RPC__deref_out_opt IMoniker **ppmk)
{
if ((dwAssign == OLEGETMONIKER_ONLYIFTHERE) &&
(dwWhichMoniker == OLEWHICHMK_CONTAINER))
return E_FAIL;

return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::GetContainer(
__RPC__deref_out_opt IOleContainer **ppContainer)
{
return E_NOINTERFACE;
}

HRESULT STDMETHODCALLTYPE WebBrowser::ShowObject(void)
{
return S_OK;
}

HRESULT STDMETHODCALLTYPE WebBrowser::OnShowWindow(
BOOL fShow)
{
return S_OK;
}

HRESULT STDMETHODCALLTYPE WebBrowser::RequestNewObjectLayout(void)
{
return E_NOTIMPL;
}

// ----- IStorage -----

HRESULT STDMETHODCALLTYPE WebBrowser::CreateStream(
__RPC__in_string const OLECHAR *pwcsName,
DWORD grfMode,
DWORD reserved1,
DWORD reserved2,
__RPC__deref_out_opt IStream **ppstm)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::OpenStream(
const OLECHAR *pwcsName,
void *reserved1,
DWORD grfMode,
DWORD reserved2,
IStream **ppstm)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::CreateStorage(
__RPC__in_string const OLECHAR *pwcsName,
DWORD grfMode,
DWORD reserved1,
DWORD reserved2,
__RPC__deref_out_opt IStorage **ppstg)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::OpenStorage(
__RPC__in_opt_string const OLECHAR *pwcsName,
__RPC__in_opt IStorage *pstgPriority,
DWORD grfMode,
__RPC__deref_opt_in_opt SNB snbExclude,
DWORD reserved,
__RPC__deref_out_opt IStorage **ppstg)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::CopyTo(
DWORD ciidExclude,
const IID *rgiidExclude,
__RPC__in_opt SNB snbExclude,
IStorage *pstgDest)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::MoveElementTo(
__RPC__in_string const OLECHAR *pwcsName,
__RPC__in_opt IStorage *pstgDest,
__RPC__in_string const OLECHAR *pwcsNewName,
DWORD grfFlags)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::Commit(
DWORD grfCommitFlags)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::Revert(void)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::EnumElements(
DWORD reserved1,
void *reserved2,
DWORD reserved3,
IEnumSTATSTG **ppenum)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::DestroyElement(
__RPC__in_string const OLECHAR *pwcsName)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::RenameElement(
__RPC__in_string const OLECHAR *pwcsOldName,
__RPC__in_string const OLECHAR *pwcsNewName)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::SetElementTimes(
__RPC__in_opt_string const OLECHAR *pwcsName,
__RPC__in_opt const FILETIME *pctime,
__RPC__in_opt const FILETIME *patime,
__RPC__in_opt const FILETIME *pmtime)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::SetClass(
__RPC__in REFCLSID clsid)
{
return S_OK;
}

HRESULT STDMETHODCALLTYPE WebBrowser::SetStateBits(
DWORD grfStateBits,
DWORD grfMask)
{
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE WebBrowser::Stat(
__RPC__out STATSTG *pstatstg,
DWORD grfStatFlag)
{
return E_NOTIMPL;
}

Win32Project1.cpp

#include "stdafx.h"
#include "Win32Project1.h"
#include "Browser.h"

HWND mainHWND;
WebBrowser* myBrowser = NULL;

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name

ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
OleInitialize(NULL);

LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_WIN32PROJECT1, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
myBrowser = new WebBrowser(mainHWND);
//myBrowser->Navigate(L"https://google.com.vn");
myBrowser->SetText(L"Hello!");

HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT1));

MSG msg;

while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return (int) msg.wParam;
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT1));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WIN32PROJECT1);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassExW(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable

mainHWND = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

if (!mainHWND)
{
return FALSE;
}

ShowWindow(mainHWND, nCmdShow);
UpdateWindow(mainHWND);

return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
// Removed
return (INT_PTR)FALSE;
}

Visual Studio 创建的其他源文件保持不变。

问题

什么问题导致我的程序无法加载 HTML 字符串,我该如何解决?或者您是否有任何工作示例(没有 MFC 或 ATL)将 HTML 字符串加载到 WebBrowser?

注意:我知道我可以将 HTML 字符串写入硬盘并将文件路径传递给浏览器,但我根本不想涉及硬盘。

注意 2: 为了赢得赏金,请提供一个完整的工作代码示例,尽可能多地使用我的代码。浏览器应成功加载 HTML 字符串。即使它正在加载在线网页,它也应该停止处理这个新命令。

最佳答案

   Navigate(L"about:blank");

发布的源代码没有很好地说明问题。它没有显示错误,但也没有“你好”。只有通过省略 Navigate() 调用,它才接近于因 nullptr 错误而失败。代码还没有完成,它缺少捕获 DocumentComplete 事件所需的管道。只有此事件被触发后,WebBrowser::setHtml() 中的代码才能工作。

让 WebBrowser 类实现 IDispatch 和 IUnknown 接口(interface):

class WebBrowser :
public IDispatch,
public IUnknown,
public IOleClientSite,
public IOleInPlaceSite,
public IStorage
{
private:
HRESULT OnCompleted(DISPPARAMS* args);
wchar_t* htmlSource;
IConnectionPoint* callback;
DWORD eventCookie;
// etc...
};

注意 htmlSource 变量现在如何成为类成员,字符串需要存储到 DocumentComplete 事件触发。

我们需要实现 IDispatch。这很容易做到,我将代码内联:

// ---------- IDispatch ----------
HRESULT GetTypeInfoCount(UINT *pctinfo) { return E_FAIL; }
HRESULT GetTypeInfo(UINT, LCID, ITypeInfo **) { return E_FAIL; }
HRESULT GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { return E_FAIL; }

HRESULT Invoke(DISPID dispIdMember, REFIID, LCID, WORD,
DISPPARAMS *pDispParams, VARIANT *pVarResult,
EXCEPINFO*, UINT*) {
if (dispIdMember == DISPID_DOCUMENTCOMPLETE) return OnCompleted(pDispParams);
else return S_OK;
}

QueryInterface() 需要调整:

HRESULT STDMETHODCALLTYPE WebBrowser::QueryInterface(REFIID riid, void**ppvObject)
{
if (riid == __uuidof(IUnknown)) *ppvObject = static_cast<IUnknown*>(this);
else if (riid == __uuidof(IDispatch)) *ppvObject = static_cast<IDispatch*>(this);
else if (riid == __uuidof(IOleClientSite)) *ppvObject = static_cast<IOleClientSite*>(this);
else if (riid == __uuidof(IOleInPlaceSite)) *ppvObject = static_cast<IOleInPlaceSite*>(this);
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}

构造函数需要订阅事件接口(interface):

WebBrowser::WebBrowser(HWND _hWndParent)
{
//...
// appended:
htmlSource = nullptr;
IConnectionPointContainer* container = nullptr;
webBrowser2->QueryInterface(IID_IConnectionPointContainer, (void**)&container);
container->FindConnectionPoint(__uuidof(DWebBrowserEvents2), &callback);
IUnknown* punk = nullptr;
this->QueryInterface(IID_IUnknown, (void**)&punk);
callback->Advise(punk, &eventCookie);
punk->Release();
container->Release();
}

setText() 函数变得非常简单,我们根本不用担心 setHtml()。我们只需设置 htmlSource 成员,这样我们就知道在 DocumentComplete 事件触发时要做什么:

void WebBrowser::SetText(const wchar_t* t)
{
const wchar_t* html = L"<html><head><meta http-equiv='x-ua-compatible' content='IE=edge'></head><body><code>%ls</code></body></html>";
if (htmlSource) delete[] htmlSource;
htmlSource = tkString::Format(html, t);
this->Navigate(L"about::blank");
}

最后添加的函数在 DocumentComplete 事件触发时运行。大部分代码已从 setHtml 中移出:

HRESULT WebBrowser::OnCompleted(DISPPARAMS* args) {
HRESULT hr;

IDispatch *pDispatch = 0;
IHTMLDocument2 *pHtmlDoc2 = 0;
IPersistStreamInit *pPSI = 0;
IStream *pStream = 0;
HGLOBAL hHTMLContent;


if (!htmlSource) return S_OK;
hr = webBrowser2->get_Document(&pDispatch);
if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2);
if (SUCCEEDED(hr) && pHtmlDoc2) hr = pHtmlDoc2->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI);


// allocate global memory to copy the HTML content to
hHTMLContent = ::GlobalAlloc(GMEM_MOVEABLE, (::wcslen(htmlSource) + 1) * sizeof(TCHAR));
if (hHTMLContent)
{
wchar_t * p_content(static_cast<wchar_t *>(GlobalLock(hHTMLContent)));
::wcscpy(p_content, htmlSource);
GlobalUnlock(hHTMLContent);

// create a stream object based on the HTML content
if (SUCCEEDED(hr) && pPSI) hr = ::CreateStreamOnHGlobal(hHTMLContent, TRUE, &pStream);

if (SUCCEEDED(hr) && pStream) hr = pPSI->InitNew();
if (SUCCEEDED(hr)) hr = pPSI->Load(pStream);
}
if (pStream) pStream->Release();
if (pPSI) pPSI->Release();
if (pHtmlDoc2) pHtmlDoc2->Release();
if (pDispatch) pDispatch->Release();
delete[] htmlSource;
htmlSource = nullptr;
return S_OK;
}

我会将适当的清理留作//待办事项。现在运行这段代码会产生预期的结果:

enter image description here

关于c++ - 如何将 HTML 字符串加载到嵌入式 WebBrowser 控件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45103166/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com