我正在尝试调用COM对象的方法。方法(在OLEView中)如下所示: -
VARIANT_BOOL GetValues(
[out] rsValues** values,
[in, optional] rsCategory* category,
[in, optional] rsProcess* process);
最后两个参数是可选的,我想从调用中“省略”它们(只是传递NULL不起作用)。
我的理解是Delphi / C ++ Builder类型库导入器生成的所有COM包装器都会将每个传递的参数转换为变量。但是为了传递一个'省略'参数,我想我必须像这样构造一个特殊的Variant。
varOpt.vt = VT_ERROR;
varOpt.sCode = DISP_E_PARAMNOTFOUND;
这似乎意味着我无法使用任何自动生成的生成组件包装器。
如何(使用C ++ Builder 或 Delphi - 我应该能够将Delphi转换为C ++)我可以调用该方法,并传递一个“省略”的变体吗?
更新
以下是我按照David Heffernan的回答中的建议尝试调用该方法的方法。
procedure TForm38.Wibble(obj : IrsObject);
var vals : IrsValues;
begin
ps.GetValues(vals, emptyparam, emptyparam);
但是这会给出这个错误:
[DCC Error] E2010 Incompatible types: 'IrsCategory' and 'OleVariant'
[DCC Error] E2010 Incompatible types: 'IrsProcess' and 'OleVariant'
由于我使用非“Disp”对象,我相信我正在使用早期绑定。
我试图避免发布45000行foo_TLB.pas文件,但这里(我希望)是相关部分。
IrsCategory = interface;
IrsCategoryDisp = dispinterface;
IrsProcess = interface;
IrsProcessDisp = dispinterface;
// *********************************************************************//
// Interface: IrsObject
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {861817F7-EA49-49D1-89FC-395BCA57E342}
// *********************************************************************//
IrsObject = interface(IDispatch)
['{861817F7-EA49-49D1-89FC-395BCA57E342}']
...
function GetValues(out values : IrsValue;
const Category: IrsCategory;
const Process: IrsProcess):): WordBool; safecall;
...
end;
// *********************************************************************//
// Interface: IrsObjectDisp
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {861817F7-EA49-49D1-89FC-395BCA57E342}
// *********************************************************************//
IrsObjectDisp = dispinterface ... // basically the same, repeated
答案 0 :(得分:2)
海森堡选项1
您正在使用自动化界面,可能使用后期绑定的COM,参数都是变体。
将EmptyParam
传递给这些参数。
function EmptyParam: OleVariant;
包含OleVariant,表示双接口上未使用的可选参数。
EmptyParam可用于表示其值未分配的可选参数的变量。当编组方法调用的代码需要固定数量的参数时,这很有用,即使其中一些参数是可选的。
当编组包含可选参数的接口调用时,即使不使用这些参数,COM也需要这些参数的值。 EmptyParam返回一个OleVariant,您可以将该值作为该值传递,以指示未使用该参数。
海森堡选项2
您正在使用早期绑定的COM,参数是接口。
将nil
传递给这些参数以省略它们。如果参数是COM接口而不是变体,那么这是您唯一可能的选择。 COM接口变量必须是有效接口或nil
。
答案 1 :(得分:1)
根据MSDN specification for IDL,optional
仅对VARIANT
或VARIANT*
类型的参数有效。
因此IDL中[in, optional] rsCategory* category,
的函数定义格式不正确。
假设您必须使用此签名的其他人的对象,我的建议是将其视为[in]
,即实际创建传递给它的对象(并在之后释放它们)。
您不清楚您是使用早期绑定还是后期绑定。如果接口实际上是双接口,那么通过C ++ Builder你可以做到这两点。 (我不使用Delphi,但可能你也可以在那里做两个)。在C ++ Builder中,当自动生成的后期绑定包装不是optional
时,它似乎会忽略VARIANT
;我想Delphi会是一样的。
后期绑定通过将VARIANT
的列表传递给IDispatch :: Invoke函数来工作,其中每个变量包含一个参数。您可以尝试手动调用此函数的Invoke,绕过包装器。 (查看示例代码的包装器)。
喜欢通过早期绑定传递NULL
;如果您正在使用服务器进程中,这可能会有效,服务器直接接收您发送的内容 - 大概是如果他们认为使用optional
在这里是正确的,那么他们的服务器代码实际上会支持它。
然而,如果你是在进程外,那么你必须依赖于你的参数的编组,并且(我不确定这一点)但我希望标准的编组可能无法应对尝试省略这个参数。