2015-06-03 10 views
3

Одной из неприятных вещей при работе с Excel через интерфейс автоматизации является слабый набор.
Возвращаемое значение может содержать что угодно разных типов.
Как проверить, соответствует ли вариант, возвращаемый caller интерфейсом ExcelRange?Как проверить, содержит ли OleVariant интерфейс

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; 

(достаточно Strangly оператор as работает (IDispatch(Caller) as ExcelRange).Parent; компилируется нормально).

Следующий код работает, но кажется слишком многословным:

if VarIsType(Caller, varDispatch) then begin 
    IUnknown(Caller).QueryInterface(ExcelRange, ICaller) 
    if Assigned(ICaller) then ICaller...... 

Там также нет встроенной функции VarIsInterface(Variant, Interface).
Как проверить, что OleVariant содержит данный интерфейс?

Смотрите также: How to cast OleVariant to IDispatch derived?

EDIT
Спасибо всем, я использовал следующие сделать тестирование, потому что Excel смешивает интерфейсы и OleStrings в качестве возможных возвращаемых значений.

if VarIsType(Caller, varDispatch) and Supports(Caller, ExcelRange) then begin 
+0

Интерфейсы всегда поддерживает 'как' для тиснения. Странно то, что 'is' не работает, а не' '. –

ответ

3

я бы, вероятно, использовать Supports для этого:

if Supports(Caller, ExcelRange) then 
    .... 

Это решает тот же код, что и @Stijn, но вызов Supports является скорее более кратким.

+0

Самая крутая вещь в 'support' заключается в том, что она имеет перегрузку, которая возвращает преобразованный интерфейс. – Johan

+0

Вам здесь не нужно, но во многих случаях эти перегрузки очень полезны. –

+0

Является ли 'Supports' заменой проверки Johan' VarIsType' или просто 'QueryInterface' +' Assigned'? –

2

код действительно, regretably, многословен, но близко к тому, что я обычно использую:

if IUnknown(Caller).QueryInterface(ExcelRange, ICaller)=S_OK then 
2

System.Variants блок имеет VarSupports() функции для тестирования/извлечения интерфейса из (Ole)Variant:

function VarSupports(const V: Variant; const IID: TGUID; out Intf): Boolean; overload; 
function VarSupports(const V: Variant; const IID: TGUID): Boolean; overload; 

Например:

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; 
+0

Какая функциональность это обеспечивает простой поддержки? –

+1

В этой конкретной ситуации мало. Но это помогает гарантировать, что 'Variant' содержит доступный интерфейс, даже из пользовательских типов Variant. И, кроме того, это функция RTL, специфичная для Variant. У вас есть «Variant», вы хотите получить от него интерфейс, так почему бы не использовать функцию, специально разработанную для этой цели * специально для этой цели? Если вы вызываете 'Supports()' напрямую, вы на самом деле не вызываете собственные функции 'Variant', вы неявно конвертируете' Variant' в 'IInterface', а затем запрашиваете его для желаемого интерфейса. Так почему бы не позволить RTL справиться с этим для вас? –

+0

rtl действительно обрабатывает его для вас с поддержкой. Я подозреваю, что эти суммы здесь одинаковы. –