什么是具有相同GUID的两个接口的相关性的交互

时间:2013-04-30 08:10:06

标签: delphi com guid ole idispatch

我曾经认为Delphi中关于Interfaces的类型安全性是通过设置一个唯一的(可选的,但唯一的,如果填充的)GUID来维护的。

然后出现了这个问题:Unspecified error when calling Word CentimetersToPoints via OLE
很少跟进:http://pastebin.ca/2369858

我开始查看库存Delphi TWordApplication组件(即Word200.pas单位)。我看到了:

// *********************************************************************//
// Interface: _Application
// Flags:     (4560) Hidden Dual NonExtensible OleAutomation Dispatchable
// GUID:      {00020970-0000-0000-C000-000000000046}
// *********************************************************************//
  _Application = interface(IDispatch)
    ['{00020970-0000-0000-C000-000000000046}']
...
    function CentimetersToPoints(Centimeters: Single): Single; safecall;



// *********************************************************************//
// DispIntf:  _ApplicationDisp
// Flags:     (4560) Hidden Dual NonExtensible OleAutomation Dispatchable
// GUID:      {00020970-0000-0000-C000-000000000046}
// *********************************************************************//
  _ApplicationDisp = dispinterface
    ['{00020970-0000-0000-C000-000000000046}']
...
    function CentimetersToPoints(Centimeters: Single): Single; dispid 371;

或类似:

// *********************************************************************//
// Interface: _Global
// Flags:     (4560) Hidden Dual NonExtensible OleAutomation Dispatchable
// GUID:      {000209B9-0000-0000-C000-000000000046}
// *********************************************************************//
  _Global = interface(IDispatch)
    ['{000209B9-0000-0000-C000-000000000046}']
...
    function CentimetersToPoints(Centimeters: Single): Single; safecall;

// *********************************************************************//
// DispIntf:  _GlobalDisp
// Flags:     (4560) Hidden Dual NonExtensible OleAutomation Dispatchable
// GUID:      {000209B9-0000-0000-C000-000000000046}
// *********************************************************************//
  _GlobalDisp = dispinterface
    ['{000209B9-0000-0000-C000-000000000046}']
...
    function CentimetersToPoints(Centimeters: Single): Single; dispid 371;

我觉得这里完全迷失了。

我以前认为dispinterfaceinterface的“子类”,如TPersistentTObject是?如果是,那么如何在同一个项目中具有相同GUID的两个接口?

或者他们来自不同的不相关框架,比如继承TurboPascal class类型的Delphi新object类型? _GlobalDisp似乎没有使用_ApplicationDispWord200.pas,所以它们就像附录,自动导入但从未实际使用过吗?

我使用_Application_ApplicationDisp制作了该项目并进行了编译。但后来我只想知道如果他们有相同的指南,Delphi如何打字呢?

procedure TForm4.Button1Click(Sender: TObject);
 procedure show(const s: Single);
 begin
   ShowMessage(FloatToStr(s));
 end;
begin
  show( WordApplication1.CentimetersToPoints(1.0) );
  show( WordApplication1.Application.CentimetersToPoints(2.0) );
  show( WordApplication1.DefaultInterface.CentimetersToPoints(3.0) );
  show( _ApplicationDisp(WordApplication1.Application).CentimetersToPoints(4.0) );
  show( (WordApplication1.DefaultInterface as _ApplicationDisp).CentimetersToPoints(5.0) );
end;

1 个答案:

答案 0 :(得分:3)

dispinterface实际上只是将IDispatch用于自动化界面的便捷方式。这就是他们拥有相同GUID的原因 - 它们在幕后完全相同。

使用IDispatch调用方法时,通常需要调用GetIdsOfNames来获取方法的调度ID。但由于这些是静态的,如果您知道调度ID,则可以通过跳过该步骤来节省时间。这就是dispinterface允许你做的事情。

当您在dispinterface上拨打方法时,您仍然会在Invoke上拨打IDispatch,但是您跳过了GetIdsOfNames的来电。

当您在界面中使用QueryInterface时,您将获得IDispatch。然后,您可以将其强制转换为相应的dispinterface。它仍然是相同的界面,但是当你在dispinterface上调用方法时,你会将该调用保存到GetIdsOfNames

因此,如果您对Word应用程序对象有IDispatch,那么您可以编写如下代码:

var
  WordApp: Variant;
  WordDisp: _ApplicationDisp;
....
WordApp := CreateOleObject('Word.Application');
WordDisp := _ApplicationDisp(IDispatch(WordApp));

_ApplicationDisp()演员只不过是对IntfCopy的召唤。反过来,这只不过是对_AddRef的调用。然后你可以写:

Writeln(WordApp.ProductCode);
Writeln(WordDisp.ProductCode);

两者都产生相同的输出。前者在调用GetIdsOfNames之前首先调用Invoke。后者直接进入Invoke