Jump to content
lookin030577

Getting of dynamic array from Variant

Recommended Posts

Hi everybody!

 

  I am transferring my old Delphi 6 code into IDE Delphi 10.4 Community Edition. I encounter a compilation error while using these lines:

 

type TDoubleArray = array of double;

var Value: Variant; //this variable is assigned to a dynamic array somewhere in the code

...

procedure DoSomething;

var rv: TDoubleArray;

begin

  rv:=@TVarData(Value).VArray.Data; // here I get the compilation error "Incompatible types Dynamic array and Pointer" but in Delphi 6 this line is compiled without warnings

  rv:=TDoubleArray(@TVarData(Value).VArray.Data); //here I have no warnings about the compilation

end; 


 

My question is why the first line is not allowed for the compiler?

 

Many thanks in advance! 

Share this post


Link to post
50 minutes ago, lookin030577 said:

  I am transferring my old Delphi 6 code into IDE Delphi 10.4 Community Edition. I encounter a compilation error while using these lines

By default, an array inside a Variant is stored as (a pointer to) a COM SAFEARRAY:

 

https://docs.microsoft.com/en-us/archive/msdn-magazine/2017/march/introducing-the-safearray-data-structure

 

https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-safearray

 

Which is completely different than a Delphi-style dynamic array.  The two are not compatible with each other.  The only way to store a Delphi-style dynamic array AS-A dynamic array in a Variant is to use a custom Variant type:

 

https://docwiki.embarcadero.com/RADStudio/en/Defining_Custom_Variants

 

That being said, Delphi 10.2 and later are more strict about NOT letting you assign a raw Pointer to a dynamic array, as you are trying to do:

So, you would have to type-cast the raw Pointer in order to get the old Delphi 6 behavior, eg:

type
  TDoubleArray = array of double;

var
  Value: Variant; //this variable is assigned to a dynamic array somewhere in the code

...

procedure DoSomething;
var
  rv: TDoubleArray;
begin
  rv := TDoubleArray(TVarData(Value).VArray.Data); // note, no @ used here. Why would you want to assign a PPointer to a dynamic array???
  ...
end; 

But, it never made sense to me why anyone would ever want to do this, since this makes the dynamic array point at something that is not a valid dynamic array, and can't be accessed as a dynamic array.  The structure of a SAFEARRAY and a dynamic array are completely different.

 

In any case, to safely access the raw data of a SAFEARRAY, you MUST use the SafeArrayAccessData() function, which Delphi's RTL has wrapped in the VarArrayLock() function, eg:

var
  Value: Variant; //this variable is assigned to a dynamic array somewhere in the code

...

procedure DoSomething;
var
  rv: PDouble;
begin
  rv := PDouble(VarArrayLock(Value));
  try
    // use rv as needed...
  finally
    VarArrayUnlock(Value);
  end;
end;

 

  • Like 1

Share this post


Link to post

Remi, thank you a lot, I will work closely with your suggestions. However, the first line in my code (that is the line used in Delphi 6) was not only successfully compiled there but also returned a valid array (surely, I used the VarType(Value) flags to check if it is an array and what type of the array) if executed. I hardly understand the whole strusture of TVarData and I agree that it looks strange to use pointer reference (@) to a pointer in this line:

 

@TVarData(Value).VArray.Data

 where VArray.Data is a pointer according to the documentation. But this worked quite well in Delphi 6 so my great wonder now why it does not work in the later version of IDE.

 

Share this post


Link to post
2 hours ago, lookin030577 said:

However, the first line in my code (that is the line used in Delphi 6) was not only successfully compiled there but also returned a valid array (surely, I used the VarType(Value) flags to check if it is an array and what type of the array) if executed. I hardly understand the whole strusture of TVarData and I agree that it looks strange to use pointer reference (@) to a pointer

I honestly can't see how it could ever work to assign a pointer-to-pointer-to-data to a dynamic-array.  What is the original code trying to accomplish, exactly?  If it just wants to access the elements of the Variant array, there is no need to assign the raw data pointer to a dynamic array at all.

Quote

But this worked quite well in Delphi 6

I seriously doubt that.  I would have to see how the original code is populating the Variant, and how it is accessing the dynamic array that is assigned from the Variant's raw data.

Quote

so my great wonder now why it does not work in the later version of IDE.

Because it is not supposed to work (and you should not have relied on it to begin with, even if it did compile. Just because something compiles doesn't make it right).  Embarcadero intentionally changed the compiler in a later version to no longer allow assigning a raw untyped Pointer to a dynamic array.

Edited by Remy Lebeau

Share this post


Link to post

I apologize for my inattentive analysis of my Delphi 6 code - the line with this text:

 

rv:=@TVarData(Value).VArray.Data

is never executed in my code - instead I use another way to implement the conversion between Variant and 1D/2D array of a given type. 

 

So it seems you are totally right with the supposing that this line is out-of-sense and should not work properly. My apologizes again and many thanks for help! 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×