Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cast an array to pointer and back in Delphi?

I have an owner drawn combo box that displays the strings in columns. The drawing routine can be shared across combos if I can somehow pass the column specifications to the OnDrawItem event. A natural way to do so, would be to pass the array of column widths in the ComboBox.Tag property and then cast it back to an array.

When I define the column array as:

const arrWidth :array[1..4] of integer = (100,100,100,70);

and set the Tag property to:

ComboBox.Tag := integer(@arrWidth);

and then in the OnDrawItem event, cast it back to an array:

Widths :array of integer;
Widths := pointer(ComboBox.Tag);

I can see the array elements fine, but the array does not know it's length. It appears to be much longer with all sorts of random values.

I have tried using a dynamic array, but then I don't even get the proper column values.

like image 705
Larry Hengen Avatar asked Dec 14 '11 17:12

Larry Hengen


1 Answers

Casts are dangerous because you go outside the type checking system. That has caught you out here. The issue is that array[1..4] of integer and array of integer are not the same type.

You need to declare your array as a distinct type like this

TWidthArray = array [1..4] of Integer;
PWidthArray = ^TWidthArray;

Then do your constant like this:

const 
  arrWidth: TWidthArray = (100,100,100,70);

When you need to extract the array from the combo box do it like this:

Widths: TWidthArray;
...
Widths := PWidthArray(ComboBox.Tag)^;

If you need to support using dynamic array lengths then you would need to change your common type to reflect that. However, beware that casting to an Integer to put in Tag will bypass the reference counting of the dynamic array. So you need to really understand what you are doing if you go down that route.

One final point. If ever you wish to compile this code for 64 bit it will fail because of this line:

ComboBox.Tag := integer(@arrWidth);

since integer is a 32 bit data type. Instead you should use NativeInt which is is an integer the same width as a pointer.

ComboBox.Tag := NativeInt(@arrWidth);
like image 125
David Heffernan Avatar answered Oct 07 '22 14:10

David Heffernan