Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using ToString for Variant variables

The following code produces an EVariantInvalidOpError exception:

var
  i : Variant;
begin
  i := 10;
  ShowMessage(i.ToString());
end;

Picture displaying the "Invalid variant operation" exception dialog

All the following works good but I don't understand why the ToString function raises exception for Variant type variables:

var
  i : Variant;
begin
  i := 10;
  ShowMessage(VarToStr(i));
end;

var
  i : Integer;
begin
  i := 10;
  ShowMessage(i.ToString());
end;
like image 656
Fabrizio Avatar asked Jan 31 '26 06:01

Fabrizio


1 Answers

Variants let you store values of various types in them, while the type may be unknown at compile-time. You can write an integer value into single variable of Variant type an later overwrite it with string value. Along with the value variant records stores also the type information in it. Among those values some of them are automatically allocated and/or reference counted. The compiler does a lot of stuff behind the scenes when writing or reading the value from Variant variable.

Variants of type varDispatch get even more special treat from the compiler. varDispatch indicates that the value is of type IDispatch (usually, but not necessarily related to Windows COM technology). Instance of IDispatch provides information about its methods and properties via GetTypeInfoCount and GetTypeInfo methods. You can use its GetIDsOfNames method to query the information by name.

Let's answer the question from your comment first:

Why does Delphi allow me to use the ToString function even if there is no helper implementing such function for the Variant type?

This is how Delphi implements concept called late binding. It allows you to call methods of an object which type is unknown at compile-time. The prerequisite for this to work is that the underlying variant type supports late binding. Delphi has built-in support for late binding of varDispatch and varUnknown variants as can be seen in procedure DispInvokeCore in unit System.Variants.

I don't understand why the ToString function raises exception for Variant type variables.

As discussed above, in run-time your program tries to invoke ToString method on variant value which in your case is of type varByte. Since it doesn't support late binding (as well as further ordinal variant types) you get the exception.

To convert variant value to string use VarToStr.

Here's a simple example of using late binding with Microsoft Speech API:

uses
  Winapi.ActiveX,
  System.Win.ComObj;

var
  Voice: Variant;
begin
  CoInitialize(nil);
  try
    Voice := CreateOleObject('SAPI.SpVoice');
    Voice.Speak('Hello, World!');
  finally
    CoUninitialize;
  end;
end.
like image 103
Peter Wolf Avatar answered Feb 02 '26 07:02

Peter Wolf