以下是我尝试设置IAdviseSink
类中实现的TForm1
接口的代码,用于捕获新创建的MSWord文档的某些事件。代码运行时我没有任何错误,但我无法捕获任何事件,同时保存文档或关闭它。
如何正确设置MSWord文档的IAdviseSink
?
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;
答案 0 :(得分: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不兼容的类型:'IAdviseSink'和'TForm1'
IAdviseSink(Self)
显然不是像TForm(SomePointer)
这样的简单硬转换,它基本上告诉编译器关闭并将SomePointer视为TForm。然后,接口强制转换,提示编译器检查正在强制转换的实例是否实际支持该接口。不知道那个。每天学习新东西。
答案 1 :(得分:0)
不完全是答案,但是......
你有没有特别的理由想要重新发明轮子并自己完成整个Advise
的事情?为什么不使用TWordDocument
中的Word2000
包装类 - 与Delphi捆绑在一起的单元(在这种情况下你只需要调用ConnectTo()
并分配你的事件处理程序)?但是,Document
对象没有OnSave
事件(至少在2000版本的TLB中没有,如果您希望您的应用与多个版本兼容,这通常是一个很好的共同点)办公室)。 Application
对象确实有BeforeDocumentSave
- 事件,但是......