How to check if OleVariant contains an interface
One of the frustrating things when working with Excel through the automation interface is weak typing.
The return value can contain anything for different types.
How can I check if a variant returned by an caller
interface is ExcelRange
?
function TAddInModule.InBank: boolean;
var
ExcelAppAsVariant: OleVariant;
test: string;
Caller: OleVariant;
begin //Exception handling omitted for brevity.
Result:= false;
ExcelAppAsVariant:= ExcelApp.Application;
Caller:= ExcelApp.Application.Caller[EmptyParam, 0];
if IDispatch(Caller) is ExcelRange then begin //E2015 Operator not applicable
Result:= lowercase(Caller.Parent.Name) = 'bank'
end;
end;
(Oddly enough, the operator as
works and (IDispatch(Caller) as ExcelRange).Parent;
compiles just fine).
The following code works, but looks too verbose:
if VarIsType(Caller, varDispatch) then begin
IUnknown(Caller).QueryInterface(ExcelRange, ICaller)
if Assigned(ICaller) then ICaller......
There is also no built-in function VarIsInterface(Variant, Interface)
.
How can I check that the OleVariant contains a given interface?
See also: How to distinguish OleVariant from IDispatch?
EDIT
Thanks everyone, I used the following to do the testing because Excel mixes Interfaces and OleStrings as possible return values.
if VarIsType(Caller, varDispatch) and Supports(Caller, ExcelRange) then begin
I would use Supports
for this:
if Supports(Caller, ExcelRange) then
....
This resolves the same code as @Stijn, but the call Supports
is more concise.
The code is really, unfortunately, verbose, but close to what I usually use:
if IUnknown(Caller).QueryInterface(ExcelRange, ICaller)=S_OK then
The module System.Variants
has functions VarSupports()
to test / extract the interface from (Ole)Variant
:
function VarSupports(const V: Variant; const IID: TGUID; out Intf): Boolean; overload;
function VarSupports(const V: Variant; const IID: TGUID): Boolean; overload;
For example:
Caller := ExcelApp.Application.Caller[EmptyParam, 0];
if VarSupports(Caller, ExcelRange) then
Result := LowerCase(Caller.Parent.Name) = 'bank';
if VarSupports(Caller, ExcelRange, ICaller) then
ICaller.DoSomething;