下面是我尝试设置TForm1
类中实现的IAdviseSink
接口的代码,用于捕获新创建的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;
Edit:
别管这个答案。留作教育用途
为什么使用IAdviseSink(Self)
?
如果你在Form的类声明中声明了接口:
TForm1 = class(TForm, IAdviseSink)
...
end;
,你不应该这么做。
使用强制类型转换(硬类型转换只是告诉编译器关闭)的事实可能表明您没有这样做。这可能会导致调度机制发现你的表单没有实现IAdviseSink,因此没有什么可以调用OnSave方法。
解释为什么以上不是问题:
一开始我不明白Sertac的注释"但是代码不会编译"。他的意思是,如果没有IAdviseSink
作为表单类声明的一部分,
doc_ole_obj.Advise(IAdviseSink(Self), Connection);
将导致[DCC错误]Unit1.pas(41): E2010不兼容的类型:'IAdviseSink'和'TForm1'
IAdviseSink(Self)
显然不是像TForm(SomePointer)
那样简单的硬强制转换,它基本上告诉编译器关闭并将SomePointer视为TForm。然后,接口强制转换会提示编译器检查被强制转换的实例是否实际支持该接口。我不知道。每天学点新东西
不完全是答案,但是…
有什么特别的原因让你想重新发明轮子,自己做整个Advise
的事情吗?为什么不直接使用与Delphi捆绑在一起的Word2000
单元中的TWordDocument
包装器类(在这种情况下,您所要做的就是调用ConnectTo()
并分配您的事件处理程序)?然而,Document
对象没有OnSave
事件(至少在2000版本的TLB中没有,如果你希望你的应用程序与多个版本的Office兼容,这通常是一个很好的共同点)。Application
对象确实有一个BeforeDocumentSave
-事件,但是…