COM在多线程中的接口共享

场景大概是这样的:

建一个工程,添加个窗体,上面放个TmpWeb:TWebBrowser,然后访问一个站点,再获取页面中的一个button元素,并点击它。

通常情况下这样写没有什么问题:

var
  o:OleVariant;
begin
    o := TmpWeb.oleobject.document.all.item('go',0);
    o.click;
end;

因为所有的东西,都是一个主线程内。

但如果我们在多线程中使用,就有问题了,会报av错误,在这一段:

  o := TmpWeb.oleobject.document.all.item('go',0)

原因就在于COM的对象都生活在套间里,拥有线程相关性。如果我们只访问TmpWeb.Tag或者TmpWeb.Height这类自有属性,那自然不会有问题,但如果A线程要共享一个COM接口,比如说是IHTMLDocument,则不可以直接就把指针copy或者共享给B线程,此时需要向系统注册一个cookie,DWORD格式,然后B线程把这个cookie还原成接口指针。

具体操作如下:

1.创建一个全局变量,如:

var
  MarshalStream:pointer;

 

2.A线程将IHTMLDocument注册成cookie

var
  WebDoc:IHTMLDocument2;
begin
    WebDoc:=TmpWeb.Document as IHTMLDocument2;
    CoMarshalInterThreadInterfaceInStream(IID_IHTMLDocument2, WebDoc, IStream(MarshalStream));
end;

3.B线程将cookie还原成指针

var
  WebDoc:IHTMLDocument2;
  o:OleVariant;
begin
    CoGetInterfaceAndReleaseStream(IStream(MarshalStream),IID_IHTMLDocument2,WebDoc);
    o := WebDoc.all.item('go',0);
    o.click;
end;

通过这样的方式,就可以在不同的线程中,共享COM接口了。

另外,在线程中使用COM时,不要忘了最基础的CoInitialize(nil)和CoUnInitialize。

 

posted @ 2017-05-25 16:04  rockmmm  阅读(887)  评论(0编辑  收藏  举报