我有一些用于打开IE的继承代码,我有一些麻烦,这就是我所拥有的:
IEUnit.pas(无表格)具有LoadIE和OpenIE的例程
从单独的线程调用OpenIE,它看起来像这样
procedure OpenIE(URL: OleVariant; FieldValues: string = '');
var ie : IWebBrowser2; // <-- This should become "global" variable for the IEUnit
begin
ie := CreateOleObject('InternetExplorer.Application') as IWebBrowser2;
ie.Navigate2(URL, Flags, TargetFrameName, PostData, Headers);
ShowWindow(ie.HWND, SW_SHOWMAXIMIZED);
ie.Visible := true;
...
end;
我想在单元中使用“global”即变量,并像这样编写LoadIE例程:
应从FormCreate(主线程)
调用LoadIE它应该只创建“全局”即对象
ie := CreateOleObject('InternetExplorer.Application') as IWebBrowser2;
所以OpenIE功能不需要创建它,只是为了使用它(目的是加快速度)
所以问题是如何从2个不同的线程访问同一个OLE对象,一个创建对象,另一个使用它。
当我编写不处理线程的代码时,我收到错误
异常类EOleSysError,消息'应用程序称为为不同线程编组的接口'
我该怎么做,照顾线程(我没有线程经验,欢迎阅读和视频链接。)
提前致谢
答案 0 :(得分:5)
MTA model COM服务器只能在其关联的公寓中使用。这是错误的explanation,其中包含以下建议:
传输接口指针的正确方法(直接指向 指针或代理指针)从一个公寓到另一个公寓是通过COM公司 编组机制。来源公寓可以打电话 CoMarshalInterThreadInterfaceInStream()编组接口 指向共享(全局)流的指针。目的地公寓可以 通过调用解组此接口指针 CoGetInterfaceAndReleaseStream()
答案 1 :(得分:2)
如您所知,因为它是your previous question的主题,所以您需要从同一个线程对COM对象进行所有调用。显而易见的选择是主要的GUI线程。因此,在主窗体的IWebBrowser2
事件处理程序中创建OnCreate
。然后在需要显示浏览器时使用TThread.Synchronize
或TThread.Queue
。传递给Synchronize
或Queue
的代码将在主GUI线程上执行。
假设您正在使用支持匿名方法的现代版Delphi,您可以这样写:
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;
答案 2 :(得分:1)
使用CriticalSection来包装对OleObject的所有调用。还可以使用Synchronize从“其他”线程调用主UI线程(这就是你获得异常的原因)。
答案 3 :(得分:1)
非自由线程COM对象只能由/ on /在与/ on / in / with创建的线程相同的线程中使用。在你的情况下,为了加快速度,我会使用类型为IWebBrowser2的普通全局treadvar
值,或者类中覆盖TThread的属性。