接收MS Word';来自Delphi应用程序的s自动化事件
我一直在尝试使用这个问题答案中显示的技巧 实现微软Word自动化事件的DIY版本 下面是我的应用程序的更完整摘录,您可以从中看到 这些方法中变量的声明:接收MS Word';来自Delphi应用程序的s自动化事件,delphi,ms-word,delphi-7,delphi-10-seattle,Delphi,Ms Word,Delphi 7,Delphi 10 Seattle,我一直在尝试使用这个问题答案中显示的技巧 实现微软Word自动化事件的DIY版本 下面是我的应用程序的更完整摘录,您可以从中看到 这些方法中变量的声明: procedure TForm1.StartWord; var IU : IUnknown; begin IU := CreateComObject(Class_WordApplication); App := IU as WordApplication; App.Visible := True; IEvt := TEve
procedure TForm1.StartWord;
var
IU : IUnknown;
begin
IU := CreateComObject(Class_WordApplication);
App := IU as WordApplication;
App.Visible := True;
IEvt := TEventObject.Create(DocumentOpen);
end;
procedure TForm1.OpenDocument;
var
CPC : IConnectionPointContainer;
CP : IConnectionPoint;
Res : Integer;
MSWord : OleVariant;
begin
Cookie := -1;
CPC := App as IConnectionPointContainer;
Res := CPC.FindConnectionPoint(DIID_ApplicationEvents2, CP);
Res := CP.Advise(IEvt, Cookie);
MSWord := App;
WordDoc:= MSWord.Documents.Open('C:\Docs\Test.Docx');
end;
StartWord
例程工作正常。问题出在OpenDocument
中。这个
Res:=CP.advice(IEvt,Cookie)返回的Res
值代码>是80040200美元
这在Windows.Pas和谷歌搜索“ole错误80040200”的HResult状态代码中不存在
返回一些涉及从Delphi设置Ado事件的点击,但没有返回任何内容
显然相关
无论如何,其结果是EventObject的Invoke方法永远不会被调用
调用,因此我不会收到WordApplication事件的通知
所以,我的问题是80040200美元的错误意味着什么和/或如何避免它
Fwiw,我还尝试使用以下代码连接到ApplicationEvents2接口
procedure TForm1.OpenDocument2;
var
MSWord : OleVariant;
II : IInterface;
begin
II := APP as IInterface;
InterfaceConnect(II, IEvt.EventIID, IEvt as IUnknown, Cookie);
MSWord := App;
WordDoc:= MSWord.Documents.Open('C:\Docs\Test.Docx');
end;
它可以毫无怨言地执行,但EventObject的Invoke方法永远不会被调用
打电话来
如果我把一个应用程序放到一个新的应用程序的空白窗体上,事件
像
OnDocumentOpen
一样工作正常。我提到这一点是因为它似乎证实了这一点
Delphi和MS Word(2007)在我的机器上设置正确
代码:
我可以发布一个MCVE,但大部分都是前面答案中的代码。我可以告诉你,这让我挠头了一段时间。不管怎样,最终硬币掉了
答案必须在于TEventObject的实现方式之间的差异
和OleServer.Pas中的TServerEventDispatch
关键是TServerEventDispatch实现了一个定制的QueryInterface
function TServerEventDispatch.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if GetInterface(IID, Obj) then
begin
Result := S_OK;
Exit;
end;
if IsEqualIID(IID, FServer.FServerData^.EventIID) then
begin
GetInterface(IDispatch, Obj);
Result := S_OK;
Exit;
end;
Result := E_NOINTERFACE;
end;
而TEventObject没有。一旦我发现了这一点,就可以直接进行扩展
我也不想这样做,瞧!“CP.advice”返回的错误消失了
为了完整起见,我已经包含了完整的源代码
下面更新的TEventObject。它是
if IsEquallIID then ...
这两者之间有什么区别
Res := CP.Advise(IEvt, Cookie);
返回$800040200错误,成功返回零。“如果是Isequallid那么…”
注释掉,IEvt上的RefCount在返回“CP.advice…”后为48(!),此时
TeventoObject.QueryInterface已被调用不少于21次
我没有意识到
以前(因为TEventObject以前没有自己的版本可供观察)
当执行“CP.advice…”时,COM系统调用“TEventObject.QueryInterface”
一系列不同的IID,直到其中一个恢复正常。当我有空闲时间时,也许我会尝试查找其他IID是什么:事实上,IDispatch的IID在被查询的IID列表中有很长的一段路要走,这似乎是一个奇怪的次优IID,因为我认为这将是IConnectionPoint.Advice试图获取的IID
更新后的TeventoObject代码如下。它包括一个相当粗略的定制
特定于处理Word的DocumentOpen事件的Invoke()
type
TInvokeEvent = procedure(Sender : TObject; const Doc : _Document) of object;
TEventObject = class(TInterfacedObject, IUnknown, IDispatch)
private
FOnEvent: TInvokeEvent;
FEventIID: TGuid;
protected
function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
function GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
public
constructor Create(const AnEvent : TInvokeEvent);
property OnEvent: TInvokeEvent read FOnEvent write FOnEvent;
property EventIID : TGuid read FEventIID;
end;
constructor TEventObject.Create(const AnEvent: TInvokeEvent);
begin
inherited Create;
FEventIID := DIID_ApplicationEvents2;
FOnEvent := AnEvent;
end;
function TEventObject.GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
begin
Result := E_NOTIMPL;
end;
function TEventObject.GetTypeInfo(Index, LocaleID: Integer;
out TypeInfo): HResult;
begin
Pointer(TypeInfo) := nil;
Result := E_NOTIMPL;
end;
function TEventObject.GetTypeInfoCount(out Count: Integer): HResult;
begin
Count := 0;
Result := E_NOTIMPL;
end;
function TEventObject.Invoke(DispID: Integer; const IID: TGUID;
LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
ArgErr: Pointer): HResult;
var
vPDispParams: PDispParams;
tagV : TagVariant;
V : OleVariant;
Doc : _Document;
begin
vPDispParams := PDispParams(@Params);
if (vPDispParams <> Nil) and (vPDispParams^.rgvarg <> Nil) then begin
tagV := vPDispParams^.rgvarg^[0];
V := OleVariant(tagV);
Doc := IDispatch(V) as _Document;
// the DispID for DocumentOpen of Word's ApplicationEvents2 interface is 4
if (DispID = 4) and Assigned(FOnEvent) then
FOnEvent(Self, Doc);
end;
Result := S_OK;
end;
function TEventObject.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if GetInterface(IID, Obj) then
begin
Result := S_OK;
Exit;
end;
if IsEqualIID(IID, EventIID) then
begin
GetInterface(IDispatch, Obj);
Result := S_OK;
Exit;
end;
Result := E_NOINTERFACE;
end;
类型
TInvokeEvent=对象的过程(发送方:TObject;const Doc:_Document);
TEventObject=类(TInterfacedObject、IUnknown、IDispatch)
私有的
FOnEvent:TInvokeEvent;
feventid:TGuid;
受保护的
函数GetTypeInfoCount(out Count:Integer):HResult;stdcall;
函数GetTypeInfo(Index,LocaleID:Integer;out-TypeInfo):HResult;stdcall;
函数GetIDsOfNames(常量IID:TGUID;名称:指针;
NameCount,LocaleID:Integer;DispIDs:Pointer):HResult;stdcall;
函数调用(DispID:Integer;const IID:TGUID;LocaleID:Integer;
Flags:Word;var参数;VarResult、ExcepInfo、ArgErr:Pointer):HResult;stdcall;
函数查询接口(const IID:TGUID;out Obj):HResult;stdcall;
公众的
构造函数创建(const AnEvent:TInvokeEvent);
属性OnEvent:TInvokeEvent read FOnEvent write FOnEvent;
属性EventIID:TGuid read feventid;
结束;
构造函数TEventObject.Create(constantanevent:TInvokeEvent);
开始
继承创造;
feventid:=DIID_ApplicationEvents2;
FOnEvent:=一个事件;
结束;
函数TEventObject.GetIDsOfNames(常量IID:TGUID;名称:指针;
NameCount,LocaleID:Integer;DispIDs:Pointer):HResult;
开始
结果:=E_NOTIMPL;
结束;
函数TEventObject.GetTypeInfo(索引,LocaleID:Integer;
输出类型信息):HResult;
开始
指针(TypeInfo):=nil;
结果:=E_NOTIMPL;
结束;
函数TEventObject.GetTypeInfoCount(out Count:Integer):HResult;
开始
计数:=0;
结果:=E_NOTIMPL;
结束;
函数TEventObject.Invoke(DispID:Integer;const IID:TGUID;
LocaleID:Integer;标志:Word;var参数;VarResult,ExcepInfo,
ArgErr:指针):HResult;
变量
vPDispParams:PDispParams;
tagV:TagVariant;
V:油变异体;
文件:_文件;
开始
vPDispParams:=PDispParams(@Params);
如果(vPDispParams Nil)和(vPDispParams^.rgvarg Nil),则开始
tagV:=vPDispParams^.rgvarg^[0];
V:=油变异体(tagV);
文件:=IDispatch(V)作为文件;
//Word的ApplicationEvents2接口DocumentOpen的DispID为4
如果(DispID=4)和赋值(FOnEvent),则
FOnEvent(Self,Doc);
结束;
结果:=S_正常;
结束;
函数TEventObject.QueryInterface(常量IID:TGUID;out Obj):HResult;
开始
如果获取接口(IID,Obj),则
开始
结果:=S_正常;
出口
结束;
如果IsEqualIID(IID,EventIID),则
开始
GetInterface(IDispatch,Obj);
结果:=S_正常;
出口
结束;
结果:=E_NOINTERFACE;
结束;
Crikey,我的回答又回到了我的脑海中。我看看能不能复制你的80040200。后来。。。
type
TInvokeEvent = procedure(Sender : TObject; const Doc : _Document) of object;
TEventObject = class(TInterfacedObject, IUnknown, IDispatch)
private
FOnEvent: TInvokeEvent;
FEventIID: TGuid;
protected
function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
function GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
public
constructor Create(const AnEvent : TInvokeEvent);
property OnEvent: TInvokeEvent read FOnEvent write FOnEvent;
property EventIID : TGuid read FEventIID;
end;
constructor TEventObject.Create(const AnEvent: TInvokeEvent);
begin
inherited Create;
FEventIID := DIID_ApplicationEvents2;
FOnEvent := AnEvent;
end;
function TEventObject.GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
begin
Result := E_NOTIMPL;
end;
function TEventObject.GetTypeInfo(Index, LocaleID: Integer;
out TypeInfo): HResult;
begin
Pointer(TypeInfo) := nil;
Result := E_NOTIMPL;
end;
function TEventObject.GetTypeInfoCount(out Count: Integer): HResult;
begin
Count := 0;
Result := E_NOTIMPL;
end;
function TEventObject.Invoke(DispID: Integer; const IID: TGUID;
LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
ArgErr: Pointer): HResult;
var
vPDispParams: PDispParams;
tagV : TagVariant;
V : OleVariant;
Doc : _Document;
begin
vPDispParams := PDispParams(@Params);
if (vPDispParams <> Nil) and (vPDispParams^.rgvarg <> Nil) then begin
tagV := vPDispParams^.rgvarg^[0];
V := OleVariant(tagV);
Doc := IDispatch(V) as _Document;
// the DispID for DocumentOpen of Word's ApplicationEvents2 interface is 4
if (DispID = 4) and Assigned(FOnEvent) then
FOnEvent(Self, Doc);
end;
Result := S_OK;
end;
function TEventObject.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if GetInterface(IID, Obj) then
begin
Result := S_OK;
Exit;
end;
if IsEqualIID(IID, EventIID) then
begin
GetInterface(IDispatch, Obj);
Result := S_OK;
Exit;
end;
Result := E_NOINTERFACE;
end;