Webbrowser Control-使用"write"显示文本 [英] Webbrowser Control - displaying text using "write"

查看:127
本文介绍了Webbrowser Control-使用"write"显示文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用IWebBrowser2接口从运行时创建的HTML字符串呈现页面.我已经编写了一个方法(我们将其称为DisplayHtmlString),该方法采用HTML字符串并将其呈现,如

I'm using the IWebBrowser2 interface to render a page from an HTML string created at runtime. I have written a method (let's call it DisplayHtmlString) that takes an HTML string and renders it as shown in this example. The method also calls Navigate2 with "about:blank" first, to ensure a document is present, and it also calls close after calling write.

我第一次调用DisplayHtmlString时,页面始终呈现正确,即浏览器根据我传递的字符串显示HTML.问题在于,后续调用有时无法正常工作,而是呈现空白页.可能是什么原因造成的?

The first time I call DisplayHtmlString, the page is always rendered correctly, i.e. the browser displays HTML according to the string I pass. The problem is that subsequent calls sometimes do not work correctly, but render a blank page instead. What could be causing this?

我发现显示空白页时,这是导航到about:blank的结果.这是通过导航到本地文件来确定的,然后显示该文件(由于后续的写入/关闭操作,因此应显示HTML字符串).因此,对Navigate2的调用有效,而对写入和关闭的调用有时却不起作用.

I have found out that when the blank page is shown, this is the result of navigating to about:blank. This was determined by navigating to a local file instead, which is then shown (whereas the HTML string should be shown instead, due to the subsequent write/close). So the call to Navigate2 works, while the calls to write and close sometimes don't.

我认为IE内部安全检查是一个可能的原因(跨域检查?),但是我的直觉是这不是这里发生的事情.

I considered IE-internal security checks as a possible cause (cross-domain checking?), but my gut feeling is that this isn't what's happening here.

在我看来,这是某种同步问题,类似在下一次调用DisplayHtmlString之前,IE尚未完成渲染"的思路.我的代码最初不检查浏览器的就绪状态(因为该示例未检查).我添加了一个实验性的等待循环,并调用了get_readyState,并观察到状态从方法返回之前从未超出加载"状态-可能是因为渲染是异步的(?).我还注意到,当连续调用DisplayHtmlString正常工作时,程序的主消息循环已运行(使Windows有机会处理消息),在连续调用DisplayHtmlString失败的情况下不是这种情况.

It seems more likely to me that it is some kind of synchronization problem, along the lines of "IE hasn't finished rendering yet before the next call to DisplayHtmlString comes along". My code originally didn't check the browser's ready state (because the example doesn't). I added an experimental waiting loop with a call to get_readyState and observed that the state never got beyond "loading" before returning from the method - probably because rendering is asynchronous(?). I also notice that when successive calls to DisplayHtmlString work correctly, the program's main message loop has run (giving Windows a chance to process messages), which is not the case in the scenario where successive calls to DisplayHtmlString fail.

因此,我很确定我需要在此处提供正确的同步,但是如何呢?我注意到有一个名为onreadystatechange的方法,但是由于我在黑暗中摸索时尝试了多种其他方法,因此尚未进行过尝试.可能是解决方案,如何正确使用呢?或者,是否应该在DisplayHtmlString内部处理消息循环,直到就绪状态变为完成"?

So I'm pretty sure I need to provide correct synchronization here, but how? I notice there's a method named onreadystatechange, but haven't experimented with that yet, due to the multitude of other things I tried while groping in the dark. Could that be the solution, and how does one use it correctly? Or, alternatively, shall I just process the message loop inside DisplayHtmlString until the ready state changes to "complete"?

更新:向DisplayHtmlString添加了消息循环处理.在第一个调用(有效)中,就绪状态变为交互式",但没有进一步变化(这似乎没有问题).在随后的调用中(失败时),即使处理了消息循环,就绪状态仍处于正在加载"状态.

UPDATE: Added message loop processing to DisplayHtmlString. In the first call (which works), the ready state gets to "interactive", but no further (which doesn't seem to be a problem). In the subsequent call (when it fails), the ready state stays at "loading", even though the message loop is processed.

推荐答案

您应该处理document对象上的readystatechange事件.在JavaScript中,它看起来像这样:

You should handle readystatechange event on the document object. In JavaScript, it would look like this:

<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接口的实现.然后IDispatch::Invoke(DISPID_VALUE)将在readystatechange事件后被调用.

To get it done with C++ or C#, probably the easiest way would be to provide an implementation of IDispatch interface to IHTMLDocument2::put_readystatechange. Then IDispatch::Invoke(DISPID_VALUE) will be called back upon readystatechange event.

如果您指定使用的语言,我也许可以提供代码示例帮助.

I might be able to help with a code sample if you specify the language in use.

您可以从此处获取完整的示例(C ++/ATL/VS2012).该代码通过将自定义消息发布到主窗口来异步执行此操作.这里要引用的时间太长了,下面是相关的部分.

You can grab the complete example (C++/ATL/VS2012) from here. The code does it asynchronously by posting a custom message to the main window. It's too long to cite here, below are the relevant parts.

IDispatch实现,用于onreadystatechange事件接收器:

IDispatch implementation, for onreadystatechange Event Sink:

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.为简便起见,错误检查是非常基本的.

For more details, get the sources and look at WebOcHost.cpp. The error checks are very basic, for brevity.

这篇关于Webbrowser Control-使用"write"显示文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆