Reputation: 4624
I want to implement IOleMessageFilter
as described here:
How to: Fix 'Application is Busy' and 'Call was Rejected By Callee' Errors
I have found a Delphi implementation which works fine:
`EOleException: Call was rejected by callee` while iterating through `Office.Interop.Word.Documents`
(See UPDATE #1 in the answer)
The implementation looks like this:
type
TOleMessageFilter = class(TInterfacedObject, IMessageFilter)
public
// IMessageFilter
function HandleInComingCall(dwCallType: Longint; htaskCaller: HTask;
dwTickCount: Longint; lpInterfaceInfo: PInterfaceInfo): Longint;stdcall;
function RetryRejectedCall(htaskCallee: HTask; dwTickCount: Longint;
dwRejectType: Longint): Longint;stdcall;
function MessagePending(htaskCallee: HTask; dwTickCount: Longint;
dwPendingType: Longint): Longint;stdcall;
// TOleMessageFilter
procedure RegisterFilter;
procedure RevokeFilter;
end;
implementation
function TOleMessageFilter.HandleInComingCall(dwCallType: Integer; htaskCaller: HTask; dwTickCount: Integer; lpInterfaceInfo: PInterfaceInfo): Longint;
begin
Result := 0;
end;
function TOleMessageFilter.MessagePending(htaskCallee: HTask; dwTickCount, dwPendingType: Integer): Longint;
begin
Result := 2 //PENDINGMSG_WAITDEFPROCESS
end;
function TOleMessageFilter.RetryRejectedCall(htaskCallee: HTask; dwTickCount, dwRejectType: Integer): Longint;
begin
Result := -1;
if dwRejectType = 2 then
Result := 99;
end;
procedure TOleMessageFilter.RegisterFilter;
var
OldFilter: IMessageFilter;
NewFilter: IMessageFilter;
begin
OldFilter := nil;
NewFilter := TOleMessageFilter.Create as IMessageFilter;
CoRegisterMessageFilter(NewFilter,OldFilter);
end;
procedure TOleMessageFilter.RevokeFilter;
var
OldFilter: IMessageFilter;
NewFilter: IMessageFilter;
begin
OldFilter := nil;
NewFilter := nil;
CoRegisterMessageFilter(NewFilter,OldFilter);
end;
This exact Delphi code is found on many other sites on the web. So far so good. I have only changed the class name to TOleMessageFilter
instead of IOleMessageFilter
.
The usage is however a bit annoying.
var
Filter: TOleMessageFilter;
Filter := TOleMessageFilter.Create;
Filter.RegisterFilter;
...
Filter.RevokeFilter;
Filter.Free;
What I want is, Filter
to be declared as interface e.g. IOleMessageFilter
.
var
Filter: IOleMessageFilter;
Filter := TOleMessageFilter.Create as IOleMessageFilter;
Filter.RegisterFilter;
...
Filter.RevokeFilter;
Filter := nil;
and have the benefit of auto freeing the TInterfacedObject
.
How do I create a new IOleMessageFilter
which "derives" from IMessageFilter
but still has new methods RegisterFilter()
and RevokeFilter()
, is implemented as TOleMessageFilter = class(TInterfacedObject, IOleMessageFilter)
, and still be able to use it also with CoRegisterMessageFilter()
which expects IMessageFilter
(used in the RegisterFilter()
method)?
I have tried to declare:
IOleMessageFilter = interface(IMessageFilter)
procedure RegisterFilter;
procedure RevokeFilter;
end;
TOleMessageFilter = class(TInterfacedObject, IOleMessageFilter)
...
end;
But then calling CoRegisterMessageFilter
throws an error:
Interface not supported.
EDIT:
I have also tried to declare TOleMessageFilter
as:
TOleMessageFilter = class(TInterfacedObject, IMessageFilter, IOleMessageFilter)
Which "seems" to work, but I'm not sure it's correct approach.
Upvotes: 3
Views: 581
Reputation: 11860
Split up both interfaces and let TOleMessageFilter keep a reference to the actual message filter, as a bonus you don't have to call RegisterFilter and RevokeFilter anymore as this will done from constructor/destructor:
program SO46913922;
{$APPTYPE CONSOLE}
{$R *.res}
uses
ActiveX,
Windows,
SysUtils;
type
IOleMessageFilter = interface
['{0ECA5DA7-F6C7-4D21-8FD3-872558F88CBE}']
procedure RegisterFilter;
procedure RevokeFilter;
end;
TMessageFilter = class(TInterfacedObject, IMessageFilter)
public
// IMessageFilter
function HandleInComingCall(dwCallType: Longint; htaskCaller: HTask;
dwTickCount: Longint; lpInterfaceInfo: PInterfaceInfo): Longint;stdcall;
function RetryRejectedCall(htaskCallee: HTask; dwTickCount: Longint;
dwRejectType: Longint): Longint;stdcall;
function MessagePending(htaskCallee: HTask; dwTickCount: Longint;
dwPendingType: Longint): Longint;stdcall;
end;
TOleMessageFilter = class(TInterfacedObject, IOleMessageFilter)
private
Filter : IMessageFilter;
procedure RegisterFilter;
procedure RevokeFilter;
public
constructor Create;
destructor Destroy; override;
end;
function TMessageFilter.HandleInComingCall(dwCallType: Integer; htaskCaller: HTask; dwTickCount: Integer; lpInterfaceInfo: PInterfaceInfo): Longint;
begin
Result := 0;
end;
function TMessageFilter.MessagePending(htaskCallee: HTask; dwTickCount, dwPendingType: Integer): Longint;
begin
Result := 2 //PENDINGMSG_WAITDEFPROCESS
end;
function TMessageFilter.RetryRejectedCall(htaskCallee: HTask; dwTickCount, dwRejectType: Integer): Longint;
begin
Result := -1;
if dwRejectType = 2 then
Result := 99;
end;
procedure TOleMessageFilter.RegisterFilter;
var
OldFilter: IMessageFilter;
begin
OldFilter := nil;
Filter := TMessageFilter.Create;
CoRegisterMessageFilter(Filter,OldFilter);
end;
procedure TOleMessageFilter.RevokeFilter;
var
OldFilter: IMessageFilter;
NewFilter: IMessageFilter;
begin
OldFilter := nil;
NewFilter := nil;
CoRegisterMessageFilter(NewFilter,OldFilter);
Filter := nil;
end;
constructor TOleMessageFilter.Create;
begin
RegisterFilter;
end;
destructor TOleMessageFilter.Destroy;
begin
RevokeFilter;
inherited;
end;
var
Filter : IOleMessageFilter;
begin
try
CoInitialize(nil);
Filter := TOleMessageFilter.Create;
Readln; // do something
Filter := nil;
finally
CoUninitialize();
end;
Readln;
end.
Upvotes: 2