5

这是我尝试设置IAdviseSink在我的TForm1类中实现的接口以捕获新创建的 MSWord 文档的一些事件的代码。代码运行时我没有任何错误,但是在保存文档或关闭文档时我无法捕获任何事件。如何IAdviseSink正确设置 MSWord 文档?


    var
      Form1 : TForm1;
      doc_ole_obj : IOleObject;
      word : IDispatch;
      Connection: LongInt;

    implementation

     //------------ Setup IAdviseSink
    procedure TForm1.Setup;
    begin
     word := CreateOleObject('Word.Application');
     OleVariant(word).Visible := True;

     IUnknown(OleVariant(word).Documents.Open('file.doc')).QueryInterface(IOleObject,doc_ole_obj);
     doc_ole_obj.Advise(IAdviseSink(Self), Connection);
    end;

     //------------- catch Sink events
    procedure TForm1.OnSave;
    begin
      Caption := 'saved at ' + TimeToStr(Now);
    end;

4

2 回答 2

0

编辑:

不要介意这个答案。将其保留用于教育目的。


为什么选演员IAdviseSink(Self)

如果您在 Form 的类声明中声明了接口:

TForm1 = class(TForm, IAdviseSink)
   ...
end;

,你不应该这样做。

您使用强制转换(以及只是告诉编译器关闭的硬强制转换)的事实可能表明您没有。这很可能会导致调度机制发现您的表单没有实现 IAdviseSink,因此没有可以调用 OnSave 方法的任何内容。


为什么上述不是问题的解释:

起初我不理解 Sertac 的评论“但代码无法编译”。他的意思是,如果IAdviseSink不是表单的类声明的一部分,该行

doc_ole_obj.Advise(IAdviseSink(Self), Connection);

会导致 [DCC 错误] Unit1.pas(41): E2010 Incompatible types: 'IAdviseSink' 和 'TForm1'

IAdviseSink(Self)显然不是像 is 这样的简单硬转换TForm(SomePointer),它基本上告诉编译器关闭并将 SomePointer 视为 TForm。然后,接口转换提示编译器检查正在转换的实例是否实际支持该接口。不知道那个。每天学些新东西。

于 2011-12-24T17:03:57.393 回答
0

不完全是答案,但是...

你有什么特别的原因要重新发明轮子并自己做整个Advise事情吗?为什么不直接使用与 Delphi 捆绑在一起TWordDocument的 -unit 中的包装类Word2000(在这种情况下,您所要做的就是调用ConnectTo()和分配您的事件处理程序)?但是,该Document对象没有OnSave事件(至少在 2000 版本的 TLB 中没有,如果您希望您的应用程序与多个版本的 Office 兼容,这通常是一个很好的共同点)。该Application对象确实有一个BeforeDocumentSave-事件,但......

于 2012-05-08T14:51:36.457 回答