簡體   English   中英

Webbrowser控件-使用“寫”顯示文本

[英]Webbrowser Control - displaying text using “write”

我正在使用IWebBrowser2接口從運行時創建的HTML字符串呈現頁面。 我已經編寫了一個方法(我們將其稱為DisplayHtmlString),該方法采用一個HTML字符串並將其呈現,如本示例所示。 該方法還首先使用“ about:blank”調用Navigate2,以確保存在文檔,並且在調用write之后也調用close。

第一次調用DisplayHtmlString時,頁面始終呈現正確,即瀏覽器根據我傳遞的字符串顯示HTML。 問題在於,后續調用有時無法正常工作,而是呈現空白頁。 是什么原因造成的?

我發現,當顯示空白頁時,這是導航到about:blank的結果。 這是通過導航到本地文件確定的,然后顯示該文件(由於后續的寫入/關閉操作,因此應顯示HTML字符串)。 因此,對Navigate2的調用有效,而對write和close的調用有時則無效。

我認為IE內部安全檢查是可能的原因(跨域檢查?),但是我的直覺是這不是這里發生的事情。

在我看來,這似乎是某種同步問題,類似“在下一次調用DisplayHtmlString之前,IE還沒有完成渲染”。 我的代碼最初不檢查瀏覽器的就緒狀態(因為該示例未檢查)。 我添加了一個實驗性的等待循環,並調用了get_readyState,並觀察到狀態從方法返回之前從未超出“加載”狀態-可能是因為渲染是異步的(?)。 我還注意到,當連續調用DisplayHtmlString正常工作時,程序的主消息循環已運行(使Windows有機會處理消息),而在連續調用DisplayHtmlString失敗的情況下則不是這種情況。

所以我很確定我需要在此處提供正確的同步,但是如何呢? 我注意到有一個名為onreadystatechange的方法,但是由於我在黑暗中摸索時嘗試了多種其他方法,因此尚未進行過嘗試。 可能是解決方案,如何正確使用呢? 或者,是否應該只在DisplayHtmlString內部處理消息循環,直到就緒狀態變為“完成”?

更新:向DisplayHtmlString添加了消息循環處理。 在第一個調用(有效)中,就緒狀態變為“交互式”,但不再進一步(這似乎不成問題)。 在后續調用中(失敗時),即使處理了消息循環,就緒狀態仍處於“正在加載”狀態。

您應該處理document對象上的readystatechange事件。 在JavaScript中,它看起來像這樣:

<body>
<body>Hi, this is going to be replaced!</body>
<script>
window.onload = function()
{
    document.open("text/html");
    document.onreadystatechange = function() { 
        if (document.readyState == "complete")
            alert("Done!"); 
    }
    document.write("<b>Hello again!</b>");
    document.close();   
}
</script>
</body>

要使用C ++或C#完成此操作,最簡單的方法可能是為IHTMLDocument2::put_readystatechange提供IDispatch接口的實現。 然后,在readystatechange事件中將IDispatch::Invoke(DISPID_VALUE)

如果您指定使用的語言,我也許可以提供代碼示例幫助。

[編輯]您可以從這里獲取完整的示例(C ++ / ATL / VS2012)。 該代碼通過將自定義消息發布到主窗口來異步執行此操作。 這里引用的時間太長了,下面是相關的部分。

IDispatch實現,用於onreadystatechange事件接收器:

class CEventSink: 
  public CComObjectRoot,
  public IDispatch
{
private:
  HWND m_hwnd;
  UINT m_message;

public:
  CEventSink()
  {
    m_hwnd = NULL;
    m_message = NULL;
  }

  BEGIN_COM_MAP(CEventSink)
    COM_INTERFACE_ENTRY(IDispatch)
  END_COM_MAP()

  // Init
  void Init(HWND hwnd, UINT message)
  {
    m_hwnd = hwnd;
    m_message = message;
  }

  // IDispatch
  STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { 
    return E_NOTIMPL; }

  STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) {
    return E_NOTIMPL; }

  STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) { 
    return E_NOTIMPL; }

  STDMETHODIMP Invoke(
    DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
    DISPPARAMS* pDispParams, VARIANT* pvarResult,
    EXCEPINFO*  pExcepInfo, UINT* puArgErr)
  {
    if ( dispidMember != NULL )
      return DISP_E_MEMBERNOTFOUND;

    // Just post a message to notify the main window
    ::PostMessage(m_hwnd, m_message, 0, 0);
    return S_OK;
  }

};

使用它:

CComObject<CEventSink>* p = NULL;
hr = CComObject<CEventSink>::CreateInstance(&p);
if ( FAILED(hr) ) 
  return 0;
p->Init(m_hWnd, WM_DOCUMENTREADYSTATECHANGE);
m_eventSink = p; // does AddRef

// ...

m_htmlDocument2->put_onreadystatechange(CComVariant(m_eventSink));

有關更多詳細信息,請獲取並查看WebOcHost.cpp 為簡便起見,錯誤檢查是非常基本的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM