打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
multithreading

I have some inherited code for opening IE and I have some troubles, here is what I have:

IEUnit.pas (no form) has routines for LoadIE and OpenIE

OpenIE is called from separate thread and it looks like this

procedure OpenIE(URL: OleVariant; FieldValues: string = '');var ie : IWebBrowser2; // <-- This should become "global" variable for the IEUnitbegin  ie := CreateOleObject('InternetExplorer.Application') as IWebBrowser2;  ie.Navigate2(URL, Flags, TargetFrameName, PostData, Headers);  ShowWindow(ie.HWND, SW_SHOWMAXIMIZED);  ie.Visible := true;  ...end;

I would like to have "global" ie variable in the unit and to write LoadIE routine like this :

LoadIE should be called from FormCreate (main thread)

It should just create "global" ie object

  ie := CreateOleObject('InternetExplorer.Application') as IWebBrowser2;

so the OpenIE function doesn't need to create it, just to use it (purpose is to speed things up)

So problem is how to access same OLE object from 2 different threads, one creates the object, the other one uses it.


When I write code that doesn't take care of threads I get an error

exception class EOleSysError with message 'The application called an interface that was marshalled for a different thread'

How should I do it, to take care of threads (I'm not experienced with threads, some reading and video links are welcome).

Thanks in advance

asked Oct 11 '12 at 13:31
Milan
578

add comment

4 Answers

up vote 2 down vote accepted

As you know, because it was the subject of your previous question, you need all calls to the COM object to be made from the same thread. The obvious choice is the main GUI thread. So, create the IWebBrowser2 in your main form's OnCreate event handler. And then use TThread.Synchronize or TThread.Queue whenever you need to show the browser. The code that you pass to Synchronize or Queue will be executed on the main GUI thread.

Assuming you are using a modern version of Delphi with support for anonymous methods you'd write it like this:

procedure TMyThread.ShowBrowser(const URL: string);var  Proc: TThreadProcedure;begin  Proc := procedure    begin      MainForm.Browser.Navigate2(URL, ...);      ShowWindow(MainForm.Browser.HWND, SW_SHOWMAXIMIZED);      MainForm.Browser.Visible := true;    end;  Queue(Proc);end;
answered Oct 11 '12 at 14:03
David Heffernan
233k16284498


 
Thank you all, I'll probably try to find a way to do it from the same thread –  Milan Oct 12 '12 at 9:49
add comment

MTA model COM servers can only be used from within their associated apartment. Here's the explanation of the error with the following advice:

The correct way of transferring an interface pointer (either a direct pointer or a proxy pointer) from one apartment to another is via COM's marshaling mechanism. The source apartment can call CoMarshalInterThreadInterfaceInStream() to marshal the interface pointer to a shared (global) stream. The destination apartment can unmarshal this interface pointer by calling CoGetInterfaceAndReleaseStream().

answered Oct 11 '12 at 13:58
TOndrej
25.1k23469


 
Are you recommending that Milan uses CoMarshalInterThreadInterfaceInStream() and CoGetInterfaceAndReleaseStream()? –  David Heffernan Oct 11 '12 at 14:22

 
@DavidHeffernan No, since there's not enough information to recommend anything. I'm only pointing out the documented way to access COM objects from different threads if and when it's needed (which might be the case here as the question suggests). –  TOndrej Oct 11 '12 at 14:27

 
Hmm, I think it's safe enough to recommend only calling the COM object from a single thread. –  David Heffernan Oct 11 '12 at 14:55

 
Sure, but safe enough might not be good enough. (Safe but slow, for example.) –  TOndrej Oct 11 '12 at 15:07

 
Why would it be slow? I can't see any performance problems here. –  David Heffernan Oct 11 '12 at 15:13
show 2 more comments

use CriticalSection to wrap all calls to the OleObject. also use Synchronize to call from the "other" thread to the main UI thread (this is why you get the exception).

answered Oct 11 '12 at 13:41
Zdravko Danev
3,606421


 
Why would you need to use a critical section once you ensure that all access to the COM object is from the same thread? –  David Heffernan Oct 11 '12 at 14:04

 
if all access to the object is from the same thread, you are right, you do not need to use CriticalSection... –  Zdravko Danev Oct 11 '12 at 14:10
add comment

Non-free-threaded COM objects can only be used by/on/in the same thread as the one it's created for/on/in/with. In your case, to speed things up, I would use a plain global treadvar value of type IWebBrowser2, or a property in your class overriding TThread.

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Mozilla ActiveX control
Writing a graphical application for scientific programming using TraitsUI
The Architecture of Open Source Applications ...
Developing zero.suggest.demo with the IBM WebSphere sMash application builder
diffrence between [[[[UIApplication sharedApplication] delegate] window] and [[UIApplication sharedA
JAVA进程中的线程分析
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服