4

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

然后出现了这个问题:通过 OLE 调用 Word CentimetersToPoints 时出现未指定错误
对此很少跟进: http: //pastebin.ca/2369858

我开始寻找库存的德尔福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;

我在这里完全迷失了。

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

还是它们来自不同的不相关框架,例如 Delphi 新class类型到继承的 TurboPascalobject类型?既不_GlobalDisp也不_ApplicationDisp似乎被使用,Word200.pas所以它们就像附录一样,自动导入但从未实际使用过?

我制作了这个项目,同时使用_Application_ApplicationDisp编译。但是我只是想知道如果他们有相同的 GUID,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;
4

1 回答 1

3

dispinterface实际上只是一种IDispatch用于自动化界面的便捷方式。这就是它们具有相同 GUID 的原因——它们在幕后完全一样。

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

当您在 a 上调​​用方法时,dispinterface您仍然最终会调用InvokeIDispatch但您会跳过对 的调用GetIdsOfNames

当您使用QueryInterface接口时,您将获得IDispatch. 然后,您可以将其转换为相应的dispinterface. 它仍然是相同的接口,但是当您在 上调用方法时,dispinterface您会将该调用保存到GetIdsOfNames.

因此,如果您有一个IDispatchWord 应用程序对象,例如,您可以编写如下代码:

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

于 2013-04-30T08:32:51.550 回答