Как передать массив указателю и обратно в Delphi?

У меня есть поле со списком владельца, которое отображает строки в столбцах. Процедура рисования может быть разделена между комбо, если я могу каким-то образом передать спецификации столбца в событие OnDrawItem. Естественным способом сделать это было бы передать массив ширины столбцов в свойстве ComboBox.Tag, а затем вернуть его обратно в массив.

Когда я определяю массив столбцов как:

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

и установите для свойства Tag значение:

ComboBox.Tag := integer(@arrWidth);

а затем в событии OnDrawItem верните его в массив:

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

Я вижу элементы массива в порядке, но массив не знает его длины. Кажется, что он намного длиннее со всеми видами случайных значений.

Я попытался использовать динамический массив, но тогда я даже не получил правильные значения столбца.

Ответ 1

Броски опасны, потому что вы выходите за пределы системы проверки типов. Это вас поймало. Проблема в том, что array[1..4] of integer и array of integer не являются одинаковыми.

Вам нужно объявить массив как отдельный тип, подобный этому

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

Затем сделайте свою константу следующим образом:

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

Когда вам нужно извлечь массив из поля со списком, сделайте следующее:

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

Если вам нужно поддерживать использование динамических массивов, вам нужно будет изменить свой общий тип, чтобы это отразить. Однако будьте осторожны с тем, что приведение Integer к Tag при вводе Tag приведет к обходу подсчета ссылок динамического массива. Поэтому вам нужно действительно понять, что вы делаете, если спуститесь по этому маршруту.

Один последний момент. Если вы захотите скомпилировать этот код для 64-битного, это приведет к сбою из-за этой строки:

ComboBox.Tag := integer(@arrWidth);

так как Integer - это 32-битный тип данных. Вместо этого вы должны использовать NativeInt, который является целым числом той же ширины, что и указатель.

ComboBox.Tag := NativeInt(@arrWidth);