场景大概是这样的:
建一个工程,添加个窗体,上面放个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。