通过 OLE 调用 Word CentimetersToPoints 时出现未指定的错误 [英] Unspecified error when calling Word CentimetersToPoints via OLE

查看:16
本文介绍了通过 OLE 调用 Word CentimetersToPoints 时出现未指定的错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码在 Delphi (XE) 中执行时在 CentimetersToPoint 调用中失败,并出现 OLE 800040005未指定"错误,类似的 VBS 或 VBA 版本通过

The following code fails with an OLE 800040005 "unspecified" error on the CentimetersToPoint call when executed in Delphi (XE), the similar VBS or VBA version passes

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 传递,但没有更好的结果.

By default, Delphi only passes the floating values as Double, so I tried calling IDispatch.Invoke directly and passing the argument as VT_R4, but without better results.

有效的 VB 版本(保存到 .vbs)

edit: VB version that works (save to .vbs)

set w = CreateObject("Word.Application")
w.Visible = true
msgbox w.CentimetersToPoints(2.0)

关于可能出什么问题的任何其他建议?

Any other suggestions of what could be going wrong?

推荐答案

我最初怀疑问题是函数需要 Single 并且 Delphi 将您的浮点数转换为其他内容.当我在调试器中跟踪它时,我发现传递给 Invoke 的变体具有 VTypevarCurrency 的货币值>2.我不确定这是怎么发生的!

I initially suspected that the issue is that the function expects Single and Delphi converts your float to something else. When I tracked it down in the debugger I find that the variant being passed to Invoke is has VType of varCurrency and a currency value of 2. Quite how that happens I'm not sure!

正如我发现的,回答这个 问题,将单精度浮点数转化为变体是非常棘手的.我最初怀疑您可以使用我在那里提供的解决方案来解决您的问题.

As I discovered, answering this question, it's surprisingly tricky to get a single precision float into a variant. I initially suspected that you can use the solution I presented there to solve your problem.

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)));

但这也失败了,同样的,原因我还不明白.

But this fails also, in the same way, for reasons I don't yet understand.

和您一样,我尝试使用 IDispatch.Invoke 调用该函数.这是我想出的:

Like you, I tried calling the function using IDispatch.Invoke. This is what I came up with:

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 函数.

I cannot call CentimetersToPoints this way, but can call the ProductCode function.

要添加到您的成功/失败指标集合中,当我使用 PowerShell 调用 CentimetersToPoints 函数时,我成功了.当我使用 Python 的 win32com.client 调用时,我得到 E_FAIL.

To add to your collection of success/failure indicators, when I call CentimetersToPoints function using PowerShell I have success. When I call using Python's win32com.client, I get E_FAIL.

显然我们缺少一些特殊的魔法成分.似乎所有 MS 工具都知道这个魔法.

There is clearly some special magic ingredient that we are missing. It seems that all the MS tools know about this magic.

我的结论是不可能使用 Delphi 中实现的变体调度来调用 CentimetersToPoints.它不知道魔法是什么,不管那个魔法是什么.

I conclude that it is not possible to call CentimetersToPoints using variant dispatch as implemented in Delphi. It does not know about the magic, whatever that magic is.

显然可以在 IDispatch 上调用 Invoke 并成功.我们可以这么说,因为其他环境也能做到这一点.所以,我还不知道缺失的魔法是什么.

It is clearly possible to call Invoke on the IDispatch and succeed. We can tell that because other environments manage to do so. So, what I do not know yet is what the missing magic is.

如果您可以使用早期绑定 COM,那么您就可以避开这个问题:

If you could use early bound COM, then you could sidestep this issue:

Writeln((IDispatch(w) as WordApplication).CentimetersToPoints(2.0));

<小时>

好的,使用 Hans Passant 的 >help,我有一些 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_PROPERTYGETDISPATCH_METHOD.

For reasons unknown, you need to include DISPATCH_PROPERTYGET as well as DISPATCH_METHOD.

问题我问可能会使这个问题重复.所以,我投票结束.

The question that I asked probably makes this question a duplicate. So, I'm voting to close.

这篇关于通过 OLE 调用 Word CentimetersToPoints 时出现未指定的错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆