Delphi 将多个参数传递给 IActiveScript IDispatch.Invoke



使用Delphi 11.1,我想使用 IActiveScript 向我的应用程序添加脚本。我创建了一个小的 VBScript 来测试将多个参数从 Delphi 传递到脚本:

Function TestParams(a, b, c)
TestParams = c
End Function

VB 脚本加载正常,但我在传递多个参数时遇到问题。德尔福密码:

procedure TForm1.Button14Click(Sender: TObject);
var
v: OleVariant;
Disp: IDispatch;
Arg: TArray<TVariantArg>;
Res: OleVariant;
DispParams: TDispParams;
i,n: Integer;
s: string;
begin
v := VarArrayOf(['Wrong...', 'huh', 'OK!']);
s := 'TestParams';

Memo2.Lines.Text := VarToStr(MyScriptingHost1.Run('TestParams', v));
exit;
OleCheck(MyScriptingHost1.FScript.GetScriptDispatch(nil, Disp));
OleCheck(Disp.GetIDsOfNames(GUID_NULL, @s, 1, 1033, @n));

setlength(arg, 3);
for i := 0 to High(Arg) do
begin
n := High(Arg) - i;

Arg[n].vt := VarType(v[i]);
Arg[n].bstrVal := PWideChar(VarToWideStr(v[i]));
end;
//At this point, my Delphi 11.1 assignes the same value to Arg[]0, Arg[1], arg[2] 

//this works
//Arg[0].vt := VT_BSTR;
//Arg[0].bstrVal := 'test3';
//
//Arg[1].vt := VT_BSTR;
//Arg[1].bstrVal := 'test2';
//
//Arg[2].vt := VT_BSTR;
//Arg[2].bstrVal := 'test1';

DispParams.rgvarg := @Arg[0]; //@Arg gives error
DispParams.rgdispidNamedArgs := nil;
DispParams.cArgs := High(Arg) + 1;
DispParams.cNamedArgs := 0;

//passing pointer to DispParams gives errors
OleCheck(Disp.Invoke(n, GUID_NULL, 1033, DISPATCH_METHOD, DispParams, @res, nil, nil));
end;

出于某种原因,多个参数为 32/64 位给出不同的结果,并且使用上面的代码,所有参数通常都获得相同的值。很奇怪。

更奇怪的是,多次运行有时会产生不同的结果。

上面的代码在只有 1 个参数的情况下工作没有问题。

有谁知道这里出了什么问题?

正如我在回答您之前的问题时所解释的那样,在与COM交互时必须使用WideString,而不是string(即,在调用Disp.GetIDsOfNames()时)。

此外,您对VarToWideStr()的使用会产生临时WideString,当您将Arg数组传递给Disp.Invoke()时,这些不再有效,因此请将WideString存储在另一个数组中以将它们保持在范围内,直到Invoke()退出。

试试这个:

procedure TForm1.Button14Click(Sender: TObject);
var
v: OleVariant;
Disp: IDispatch;
Arg: TArray<TVariantArg>;
ArgStrs: TArray<WideString>;
Res: OleVariant;
DispParams: TDispParams;
i, n: Integer;
s: WideString;
begin
v := VarArrayOf(['Wrong...', 'huh', 'OK!']);
s := 'TestParams';
//Memo2.Lines.Text := VarToStr(MyScriptingHost1.Run('TestParams', v));
OleCheck(MyScriptingHost1.FScript.GetScriptDispatch(nil, Disp));
OleCheck(Disp.GetIDsOfNames(GUID_NULL, @s, 1, 1033, @n));
SetLength(Arg, 3);
SetLength(ArgStrs, 3);
for i := 0 to High(Arg) do
begin
ArgStrs[i] := VarToWideStr(v[i]);
n := High(Arg) - i;
Arg[n].vt := VT_BSTR;
Arg[n].bstrVal := PWideChar(ArgStrs[i]);
end;
DispParams.rgvarg := @Arg[0]; //@Arg gives error
DispParams.rgdispidNamedArgs := nil;
DispParams.cArgs := Length(Arg);
DispParams.cNamedArgs := 0;
OleCheck(Disp.Invoke(n, GUID_NULL, 1033, DISPATCH_METHOD, DispParams, @res, nil, nil));
end;