At first, I suspected that the problem was that the function was expecting Single , and Delphi would convert your float to another. When I tracked it in the debugger, I found that the option passed to Invoke has VType of varCurrency and the currency value is 2 . No matter how it happens, I'm not sure!
As I found out when answering this question , it is surprisingly difficult to get one float option in a variant. At first, I suspected that you could use the solution that 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 is also not the case, for reasons that I still do not understand.
Like you, I tried calling the function using IDispatch.Invoke . Here 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.
I cannot call CentimetersToPoints this way, but I can call the ProductCode function.
To add success / failure indicators to my collection when I call CentimetersToPoints using PowerShell , I have success. When I win32com.client Python using win32com.client , I get E_FAIL .
There is clearly some kind of special magical ingredient that we do not notice. All MS tools seem to know about this magic.
I came to the conclusion that calling CentimetersToPoints cannot be used with the send option implemented in Delphi. He does not know about magic, whatever that magic is.
Obviously, you can call Invoke on IDispatch and succeed. We can say this because other environments do it. So, I still do not know what is missing magic.
If you can use early related COM, you can work around this problem:
Writeln((IDispatch(w) as WordApplication).CentimetersToPoints(2.0));
OK, using, Hans Passant , I have a Delphi code that manages to call a function:
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.
For unknown reasons, you need to enable DISPATCH_PROPERTYGET as well as DISPATCH_METHOD .
The question I asked probably makes this question a duplicate. So, I vote to close.