views:

338

answers:

2

I am trying to call a procedure in a Delphi DLL from C#. The procedure expects the caller to preallocate and input an array of array of TSomeRecord, of which it will then manipulate the TSomeRecord elements as a means of returning results. So, I need to hand-craft Delphi dynamic arrays of arrays of X.
Now, I have found here that a dynamic array of X consists of a pointer to the first element of the dynamic array, and that that first element has a reference count and the length (number of elements) of the array prepended (both 32-bit integers), and that the elements are stored inline and contiguously, so that the whole thing looks like this in memory:

rrrrllll000...000111...12...
        ^

with rrrr the reference count, llll the length, 0123 the elements, and ^ where the pointer points to. This bears out; I have tested it and it works.
For multidimensional dynamic arrays I have assumed that I can substitute array of Y for the X in array of X, in other words that the outer dimension is simply a dynamic array of (pointers to) dynamic arrays, like so:

rrrrllll000011112222...
        ^

where the elements 0000, 1111 etc are now 32 bit pointers to independently allocated dynamic arrays. Doing it this way, however, earns me an access violation for my troubles. This is apparently not how Delphi expects me to do it. Can anyone explain to me how I am supposed to do this?

+5  A: 

A dynamic array is a pointer to a packed block of elements.

So array of array of TSomeRecord is a pointer to an array of pointers, each of which points to a block memory with length(array[firstlevel]) elements, or nil if there are none.

In other words, what you assume is roughly correct, with the addition that arrays with zero elements are nil. Note that you are not supposed to change reference count and length yourself unless you REALLY know what you are doing.

Determining what causes your crash will be hard without example code. Keep in mind that, as for ALL automated Delphi types (except widestring), all dynamic memory must be allocated by the delphi memory manager.

Attempts to that using the memory manager of whatever language you are interfacing to is not possible.

Marco van de Voort
Thanks for your answer. I realize this might be easier to diagnose with (example) code, but I have none; only the procedure's signature. The DLL is a 3rd-party black box.
Michiel Rijkers
Then the only advise I can give you is to stick to the principle that whoever allocates also must deallocate, or wrap the DLL in Delphi a delphi .exe (comserver) or dll first that removes the automated types from the interface
Marco van de Voort
A: 

The Language Guide (once available as very useful printed manuals, now finding this info in the online help is very difficult) states:

"A multidimensional array is stored with the rightmost dimension increasing first."

Thereby AFAIK you have not an array of pointers - simply each dimension data one after another, starting from the rightmost one, I guess it's faster because there's no more indirections.

ldsandon
The LG fragment is about static arrays, while the question is about dynamic arrays.
Marco van de Voort
You're right. I've checked the manual and although the memory layout of dynamic arrays is not detailed, it says dynarray can be "non rectangular", and I guess the only way to achive it is to have anohter dynamic array as elements of the "outer" array. Pretty slow to access the inner ones, though.
ldsandon