我有一个用Delphi 7编写的程序,它也是一个自动化服务器。
自动化服务器以下列方式注册:
TAutoObjectFactory.Create(ComServer, TMyServer, Class_App,
ciMultiInstance, tmSingle);我有两个COM外接程序,一个用于Word,一个用于Outlook。他们都在使用自动化服务器从主程序中获取一些信息。当用户单击外接程序中的按钮时,将从外接程序调用以下代码:
MyServerApp: Variant;
begin
MyServerApp := CreateOleObject('MyServer.App');
try
MyServerApp.DoSomething;
finally
MyServerApp := UnAssigned;
end–这里的问题是:大多数情况下代码工作正常。如果主应用程序已经在运行外接程序,则外接程序将连接到自动化服务器并执行它们的操作,如果没有运行,则外接程序将启动主应用程序。
但是由于一些未知的情况,特别是Outlook,有时会发生这样的情况:即使主程序正在运行,外接程序也不会连接到它,而是会再次重新启动主应用程序,并连接到这个新实例的自动化服务器。灾难来了:由于我的应用程序不允许自己在两个实例中运行,第二个应用程序实例将只显示一个错误消息,而我的外接程序将冻结整个Outlook。
这一切为什么要发生?为什么CreateOleObject大部分时间都会像它应该的那样连接,并不时地启动我的应用程序?
发布于 2014-05-15 10:52:50
你真的不应该在一个帖子里问多个问题。
问题1
这事经常发生在我身上。问题是,Office为每个触发外接程序中的代码的事件生成两个调用。我找到的解决办法是只对第一个电话作出反应。
我使用Add-In Express作为COM加载项,这给了我一些可以链接到的事件。
我不确定你是否在使用这个,但下面是我使用的代码:
interface
....
var
MyApp: TAddInModule = nil;
implementation
procedure TAddInModule.adxCOMAddInModuleAddInFinalize(Sender: TObject);
begin
MyApp:= nil;
end;
procedure TAddInModule.adxCOMAddInModuleAddInInitialize(Sender: TObject);
begin
if not(Assigned(MyApp)) then try
MyApp:= Self;
except
{ignore}
end; {if try}
end;在事件处理程序中,您必须测试是否引用了第一个实例,或者是否引用了鬼实例。(两人有时都会接到电话)。
procedure TAddInModule.adxCommandBar1Controls3Click(Sender: TObject);
begin
if (Self <> MyApp) then exit;
//ToggleDisplay
if not(ExcelBezig(xbQuestion)) then try
ToggleDisplay;
except {ignore}
end;
end;这是一个传说(我承认),但是它一劳永逸地解决了这个问题,而且从那以后,这个附加功能一直是稳定的。
不要一遍又一遍地创建链接
您不应该每次需要查询应用程序时都使用CreateOleObject('MyServer.App');。在激活加载项时,只需调用CreateOleObject一次,然后存储该实例,然后重用该链接。类似于:
procedure TAddInModule.adxCOMAddInModuleAddInInitialize(Sender: TObject);
begin
if not(Assigned(MyApp)) then try
MyApp:= Self;
MyServerApp:= CreateOleObject('MyServer.App');
except
{ignore}
end; {if try}
end;
procedure TAddInModule.adxCommandBar1Controls3Click(Sender: TObject);
begin
if (Self <> MyApp) then exit;
try
MyServerApp.DoSomething;
except
{ignore}
end;
end;使用变体访问自动化服务器的很慢!
因为您使用一个变体来存储对自动化服务的引用,Delphi无法在编译时解析您的调用。
它也不能帮助您避免打字和其他错误。
对通过变体访问的服务器的任何调用都是有效的。
所以
MyServer.StupidTyyyypo('hallo').doesnotexist('should be integer');将无错误地编译。
如果导入lib类型并使access变量成为特定类型,例如:
type
TMyServer = IMyServer;通过从Delphi自动化服务器导入类型库获得IMyServer,请参阅:http://www.blong.com/Articles/Automation%20In%20Delphi/Automation.htm
部分:Controlling Automation Servers Using Interfaces及以下。
问题2
为什么CreateOleObject连接到正在运行的应用程序实例而不一直创建单独的实例?
见正式文档:http://docwiki.embarcadero.com/Libraries/XE2/en/System.Win.ComObj.CreateOleObject
它指出:
CreateOleObject创建由ClassName参数指定的类的单个未初始化对象。ClassName指定类ID (CLSID)的字符串表示形式。CreateOleObject用于在已知CLSID和对象位于本地或proc服务器上时创建指定类型的对象。只有不属于聚合的对象才会使用CreateOleObject创建。 注意:在Delphi代码中,调用一次CreateOleObject来创建类的每个新实例。建议使用创建同一个类的多个实例,使用类工厂。
问题3
tmSingle线程模型是否意味着在应用程序的主线程中执行对自动化服务器的所有调用?
你应该用一个单独的问题来问这个问题。
https://stackoverflow.com/questions/23633781
复制相似问题