以下代码在Delphi(XE)中执行时,CentimetersToPoint
调用上的OLE 800040005“未指定”错误失败,类似的VBS或VBA版本通过
var w : OleVariant;
w := CreateOleObject('Word.Application');
w.Visible := true;
Writeln(w.CentimetersToPoints(2.0));
FWIW类型库给出
/ [id(0x00000173), helpcontext(0x09700173)]
// single CentimetersToPoints([in] single Centimeters);
默认情况下,Delphi只将浮动值传递为Double,因此我尝试直接调用IDispatch.Invoke
并将参数传递为VT_R4
,但没有更好的结果。
编辑:有效的VB版本(保存为.vbs)
set w = CreateObject("Word.Application")
w.Visible = true
msgbox w.CentimetersToPoints(2.0)
有什么可能出错的其他建议吗?
答案 0 :(得分:3)
我最初怀疑问题是该函数需要Single
而Delphi会将您的浮点数转换为其他值。当我在调试器中跟踪它时,我发现传递给Invoke
的变体的VType
为varCurrency
,货币值为2
。我不确定这是怎么回事!
正如我发现的那样,回答这个问题question,将单精度浮点数转换为变量是非常棘手的。我最初怀疑你可以使用我在那里提出的解决方案来解决你的问题。
function VarFromSingle(const Value: Single): Variant;
begin
VarClear(Result);
TVarData(Result).VSingle := Value;
TVarData(Result).VType := varSingle;
end;
....
w := CreateOleObject('Word.Application');
w.Visible := true;
Writeln(w.CentimetersToPoints(VarFromSingle(2.0)));
但是,由于我还不了解的原因,这也失败了。
和你一样,我尝试使用IDispatch.Invoke
调用该函数。这就是我想出的:
program SO16279098;
{$APPTYPE CONSOLE}
uses
SysUtils, Variants, Windows, ComObj, ActiveX;
function VarFromSingle(const Value: Single): Variant;
begin
VarClear(Result);
TVarData(Result).VSingle := Value;
TVarData(Result).VType := varSingle;
end;
var
WordApp: Variant;
param: Variant;
retval: HRESULT;
disp: IDispatch;
Params: TDispParams;
result: Variant;
begin
try
CoInitialize(nil);
WordApp := CreateOleObject('Word.Application');
disp := IDispatch(WordApp);
param := VarFromSingle(2.0);
Params := Default(TDispParams);
Params.cArgs := 1;
Params.rgvarg := @param;
retval := disp.Invoke(
371,//CentimetersToPoints
GUID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_METHOD,
Params,
@Result,
nil,
nil
);
// retval = E_FAIL
Params := Default(TDispParams);
retval := disp.Invoke(
404,//ProductCode
GUID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_METHOD,
Params,
@Result,
nil,
nil
);
// retval = S_OK
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
我不能以这种方式调用CentimetersToPoints
,但可以调用ProductCode
函数。
要添加到您的成功/失败指标集合,当我使用CentimetersToPoints
调用PowerShell
函数时,我获得了成功。当我使用Python的win32com.client
来电话时,我得到E_FAIL
。
显然我们缺少一些特殊的神奇成分。似乎所有MS工具都知道这种魔力。
我的结论是,无法使用Delphi中实现的变体调度来调用CentimetersToPoints
。无论魔法是什么,它都不知道魔法。
显然可以在Invoke
上致电IDispatch
并取得成功。我们可以说,因为其他环境设法这样做。所以,我不知道的是缺少的魔法是什么。
如果你可以使用早期绑定的COM,那么你可以回避这个问题:
Writeln((IDispatch(w) as WordApplication).CentimetersToPoints(2.0));
好的,使用help的Hans Passant,我有一些Delphi代码可以调用此函数:
program SO16279098;
{$APPTYPE CONSOLE}
uses
SysUtils, Variants, Windows, ComObj, ActiveX;
function VarFromSingle(const Value: Single): Variant;
begin
VarClear(Result);
TVarData(Result).VSingle := Value;
TVarData(Result).VType := varSingle;
end;
var
WordApp: Variant;
param: Variant;
retval: HRESULT;
disp: IDispatch;
Params: TDispParams;
result: Variant;
begin
try
CoInitialize(nil);
WordApp := CreateOleObject('Word.Application');
disp := IDispatch(WordApp);
param := VarFromSingle(2.0);
Params := Default(TDispParams);
Params.cArgs := 1;
Params.rgvarg := @param;
retval := disp.Invoke(
371,//CentimetersToPoints
GUID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_METHOD or DISPATCH_PROPERTYGET,
Params,
@Result,
nil,
nil
);
Writeln(Result);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
由于未知原因,您需要包含DISPATCH_PROPERTYGET
以及DISPATCH_METHOD
。
question that I asked可能会使这个问题重复。所以,我投票结束了。