I'm working with Windows API and have to recreate a structure inside a Delphi record. I think I have it down, but this one was a little confusing and I need to make sure I did this right.
Here's the original C++ structure:
typedef struct RETRIEVAL_POINTERS_BUFFER {
DWORD ExtentCount;
LARGE_INTEGER StartingVcn;
struct {
LARGE_INTEGER NextVcn;
LARGE_INTEGER Lcn;
} Extents[1];
} RETRIEVAL_POINTERS_BUFFER, *PRETRIEVAL_POINTERS_BUFFER;
Notice that there's an array struct within this struct. This is where I got lost. If I'm not mistaken, the Delphi version should look like this:
TExtent = record
NextVcn: Integer;
Lcn: Integer;
end;
TExtents = array of TExtent;
PRETRIEVAL_POINTERS_BUFFER = ^TRETRIEVAL_POINTERS_BUFFER;
TRETRIEVAL_POINTERS_BUFFER = record
ExtentCount: DWORD;
StartingVcn: Integer;
Extents: TExtents;
end;
When I use this structure in the Windows API, it does appear to work. But, because of this structure array inside of the structure, I'm a little hesitant that I did this correctly. Does this look right?
The Extents field is a variable length array inlined in a struct. The actual struct will have ExtentCount elements. You cannot use a Delphi dynamic array here. In fact you can never use a Delphi dynamic array in interop.
So, declare it as array [0..0] just as the C code does. In order to access it you'll need to disable range checking. An actual instance of this record will have valid data in indices 0..ExtentCount-1.
For your integral types, map DWORD in C to DWORD in Delphi. And LARGE_INTEGER in C to LARGE_INTEGER in Delphi. Neither of those are the same as Delphi Integer. The former is unsigned, and the latter is 64 bits wide.
PRetrievalPointersBuffer = ^TRetrievalPointersBuffer;
TRetrievalPointersBuffer = record
ExtentCount: DWORD;
StartingVcn: LARGE_INTEGER;
Extents: array [0..0] of record
NextVcn: LARGE_INTEGER;
Lcn: LARGE_INTEGER;
end;
end;
The LARGE_INTEGER type is rather awkward to work with. You may prefer to declare those fields as Int64 instead.
This type of struct is invariably heap allocated. The heap allocation code has to work out the size needed to fit ElementCount items in the variable length array. If you are allocating the buffer then you'll need the inner record in a separately defined type so that you can conveniently name it to pass to SizeOf. If the API allocates then you are fine as above.
Defining TExtents as array of TExtent is a mistake. That's declaring it as a dynamic array, a managed reference type. What you need is a bounded array, like array [x..y] of TExtent.
This C declaration is rather strange, though, in that it's declared as an array with only one element. If you want to copy it exactly, you should declare it as array [0..0] of TExtent.
StartingVcn, NextVcn and Lcn are defined as LARGE_INTEGER which is defined as follow in winnt.h:
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
} DUMMYSTRUCTNAME;
struct {
DWORD LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
} LARGE_INTEGER;
Depending on the version of Delphi you are using, the structure you defined might not work. LARGE_INTEGER should be declared as follow:
LARGE_INTEGER = record
case Integer of
0: ( LowPart: DWORD;
HighPart: Longint; );
1: ( QuadPart: LONGLONG);
end;
LONGLONG is actually just an Int64. You can access this structure using LowPart and Highpart or QuadPart.
Hope this helps.
Related
I have a C based DLL that exports a function that has char*** as an argument, this is a pointer to a pointer to a pointer of char (Non-unicode) My question is, after much frustration, what is the equivalent declaration at the Delphi end?
I've tried for example:
// C Method declaration
void method (char*** arg)
TArrayOfPAnsiChar = array of PAnsiChar;
PArrayOfPAnsiChar = ^TArrayOfPAnsiChar;
PPArrayOfPAnsiChar = ^PArrayOfPAnsiChar;
// Delphi declaration
procedure method (var p : PPArrayOfPAnsiChar); cdecl;
p : PPArrayOfAnsiChar;
method (p)
But I'm not getting anything sensible back. Any suggestions? The var in the declaration is of course already a pointer so perhaps that's where I am going wrong. I've tried many variants, written down on paper what the structure is and reverse engineered a Delphi declration but to no avail. This DLL is used in other C based applications so I assume its functioning correctly.
Using XE6
Don't use array of, because that declares a dynamic array, and use AnsiChar rather than Char, since the latter is two bytes in Delphi.
PPAnsiChar = ^PAnsiChar;
PPPAnsiChar = ^PPAnsiChar;
procedure Method(Arg: PPPAnsiChar); cdecl;
or
procedure Method(var Arg: PPAnsiChar); cdecl;
If you want to index into the variable like an array, add {$POINTERMATH ON} before declaring the types
In this case char*** is a pointer to a pointer that points to an array where each element points to a string.
This implies that the callee is returning data to the caller. So you want to use:
procedure method(out Arg: PPAnsiChar); cdecl; external dllname;
where PPAnsiChar is ^PAnsiChar. Note that PPAnsiChar is defined in the System unit.
The C code has three levels of indirection. The outermost is how function passses data from callee to caller. That's represented as a Delphi out parameter. The remaining two levels of indirection are captured in PPAnsiChar. Finally C's char is an 8 bit type on Windows and so maps to AnsiChar.
You will also need to iterate over the array when the function returns. Like this:
var
StrArr: PPAnsiChar;
Str: string;
....
method(StrArr);
while StrArr^ <> nil do
begin
Str := StrArr^;
Inc(StrArr);
end;
I'm assuming that the length of the array is indicated by a terminating null pointer. If instead you are told the length, you use a for loop as should be obvious.
In Windows.pas, there are:
LARGE_INTEGER = record
case Integer of
0: (
LowPart: DWORD;
HighPart: Longint);
1: (
QuadPart: LONGLONG);
end;
TLargeInteger = Int64;
I see several Windows functions and structure members which is originally declared as LARGE_INTEGER has been translated to TLargeInteger such as:
function QueryPerformanceCounter(var lpPerformanceCount: TLargeInteger): BOOL;
stdcall;
and another example is:
WIN32_STREAM_ID = record
dwStreamId : DWORD;
dwStreamAttributes: DWORD;
Size : TLargeInteger;
dwStreamNameSize : DWORD;
cStreamName : array[0..0] of WCHAR;
end;
Can TLargeInteger acts as a replacement of LARGE_INTEGER for every function parameters and structure members found in Windows header files?
You can always safely use these two types interchangeably in API translations. Although, clearly, once you have selected one type for a particular function, you have to stick to that type whenever you call that function.
Using TLargeInteger makes it easier to assign values because there's no need to refer to a record field.
Using LARGE_INTEGER makes it easier to separate into low and high 32 bit parts.
Now that the compiler has good support for 64 bit integers, it probably makes more sense to use TLargeInteger. Because, usually, there is no need to separate the 64 bit integer into its low and high parts. But way back when the compiler couldn't handle 64 bit integer types, there was no other option to work with 64 bit integers.
I'm working on c++ language bindings for our game engine (made with Delphi XE). How would I translate the array of OleVariant and array of const params to work properly in C++ side?
function DLM_CallRoutine(const aFullname: PWideChar;
const aParamList: array of OleVariant): OleVariant; stdcall;
function DLM_CreateObject(const aClassName: PWideChar;
const aParamList: array of const): Integer; stdcall;
Thanks.
Delphi has two completely separate array semantics that both use the same array of code syntax for different purposes.
When array of is used to declare a data type or variable, a Dynamic Array is being used, eg:
type
TIntegerArray: array of Integer;
var
Array1: TIntegerArray;
Array2: array of Integer;
In C++, these correspond to the DynamicArray<T> template class, eg:
typedef DynamicArray<int> TIntegerArray;
TIntegerArray Array1;
DynamicArray<int> Array2;
On the other hand, when array of is used in a function parameter directly (ie, without using a typedef), then an Open Array is being used instead, ie:
procedure DoSomething(Arr: array of Integer);
procedure DoSomethingElse(Arr: array of const);
Values passed to an Open Array parameter are passed by the compiler using two separate parameters - a pointer to the actual array, and the index of the last element in the array. Delphi hides this fact so the coder only sees one parameter, and provides a simple syntax for specifying the parameter values:
DoSomething([12345, 67890]);
DoSomethingElse(['Hello', 12345, True]);
In C++, however, the two parameters used for the array are explicitally declared, and values are typically specified using the OPENARRAY() and ARRAYOFCONST() macros, eg:
// despite their names, the Size parameters are actually indexes.
// This misnaming has already been slated to be fixed in a future
// C++Builder release...
void __fastcall DoSomething(int const *Arr, const int Arr_Size);
void __fastcall DoSomethingElse(TVarRec const *Arr, const int Arr_Size);
DoSomething(OPENARRAY(int, (( 12345, 67890 )) );
DoSomethingElse(ARRAYOFCONST(( "Hello", 12345, true )) );
When creating code with interfaces to other languages it is wise to avoid Delphi specific types and conventions. Where you know your code will be interfacing with Delphi code, you may choose to provide Delphi-friendly interfaces, and "wrappers" to map Delphi-friendly types and mechanisms onto more portable ones for those other languages.
So....
Array of OLEVariant
Since you are passing an array of variants, clearly your C++ code is variant aware/capable, in which case I would pass these values in a variant array themselves (passed as a Variant itself), preserving the dynamic nature of the array, but eliminating any concerns over Delphi RTL specific "magic" types (dynamic arrays).
So you may have a Fn(array of OLEVariant) for your Delphi code, which internally re-packages the array into a Variant Array of Variant before passing the call on to the actual API code (psuedo-code):
Fn(array of OLEVariant)
begin
arr := VarArrayCreate(...);
try
// ... init arr from array of OLEVariant parameter
// call actual API fn:
APIFn(arr);
finally
// Dispose of variant array
end;
end;
Array of Const
The values end up being passed in an array of TVarRec (not directly connected to variants, tho with a similar intention). Again this is a "magic" Delphi type - you will need to research the TVarRec type and map it to some equivalent C++ type.
In this case I would determine exactly what you need to pass in the params list and adopt a mechanism that is more portable between the two languages. Perhaps a simple string containing a name/value pair delimited string of parameter names and values?
In this case, providing a Delphi friendly wrapper around the API call would involve a slightly different approach from that which you are currently using (array of const), given that array of const does not provide for named entries in the array. Or you might choose simply to provide a delimited set of type/values, encoded in a string, in which case you could continue to use array of const for the Delphi side, with a wrapper function that processes the TVarRec array to format a string approriately for the API function.
If I remember correctly, dynamic arrays in Delphi store the size of the array in the first few bytes. You would have to declare your interface function as taking a pointer, plus a size:
function DLM_CallRoutine(const aFullname: PWideChar;
aParamList: POleVariant; numParams :integer): OleVariant; stdcall;
Callers would have to pass the address of the first actual element and the number of elements, #A[0] and Length(A) in Delphi.
Beware: There are memmory management/garbage collection issues wherever OleVariant and other OLE types are involved. You have to make sure that reference counts are incremented and decremented appropiately.
Delphi Dynarrays
This is correctly documented somewhere in the Delphi help, and can probably be learned from looking at the source code of System.pas and SysUtils.pas. What follows is from memory (sorry in advance for being of such little help).
A Delphi dynarray is a record:
type
TDynArray = record
refcount :integer;
size: :integer;
content :array[size*elementSize] of byte;
end;
#A[0] is equivalent is the same as #content. To get to the address that includes the refcount you'd have to do some casting.
Having C call Delphi
You could have the clients written in C manipulate the structures for Delphi dynarrays, But why impose Delphi implementation semantics on them? If C is calling into your code, then by all means use the C way of doing it, which is:
A pointer to an array of structures.
A number-of-records parameter.
The obligation of your API to copy what was passed as parameters so the caller can free what it likes right after the call. The C code owns what it passes in parameters.
The API exposed to C can be easily implemented with calls to the existing API.
I hope that helps.
Var
A : Array [1..4] of Integer;
B : Array [1..4] of Integer;
Begin
A := B;
Won't work as loren-pechtel said here
the problem is A and B for me are in different units. So, is there a way to define a type definition from a existing one in another class?
Define type in interface block of some unit and then include that unit via uses clause in other units where you need that type.
unit A;
interface
type
TMyArray = array [1..4] of Integer;
...
When you need to use TMyArray in another unit:
unit B;
interface
uses A;
...
var x : TMyArray;
Alternatively, define your type in the interface section of unit C and use this unit in both A and B.
Array types in Delphi are a bit odd. It looks like A and B are of exactly the same type, but Delphi doesn't consider that they are the same. "Array [1..4] of Integer" appears twice, so Delphi thinks there are two different types. That's just an oddity of Delphi. Most other languages, I think, wouldn't care. It's not a problem in practice; it's just a bit strange. Maybe there is a good reason for it. Who knows. The solution, as the others have said, is define your own type, which you can put in a unit that can be used by other units. I just mention this issue of array types because it may be confusing you.
Another approach, a bit old school but still works, is to use the ABSOLUTE keyword to force the memory of one to overlay another, and make the other type compatible. For example, in unit a lets say you have the following:
TYPE
TArrayA = Array[1..4] of integer;
then in unit b, you have the following:
TYPE
TArrayB = Array[1..4] of integer;
For compatibility, you can do the following:
VAR
InstanceA : TArrayA;
InstanceB : TArrayB;
InstanceBasA : TArrayA ABSOLUTE InstanceB;
What this does is create a variable "InstanceBasA" of type ArrayA which overlays the same memory space as the variable "InstanceB". This allows you to do the following command:
InstanceA := InstanceBasA;
One more method of moving data from variablea to variableb is to use the MOVE command. For example, to move from ArrayA to ArrayB you can do the following:
var
ArrayA : array[1..4] of Integer;
ArrayB : Array[1..4] of Integer;
begin
FillChar(ArrayB[1],SizeOf(ArrayB),#0);
ArrayA[1] := 1234;
ArrayA[2] := 3456;
ArrayA[3] := 7890;
ArrayA[4] := 9876;
// This is where the move from ArrayA to ArrayB happens.
Move( ArrayA[1], ArrayB[1], SizeOf(ArrayA) );
Assert( ArrayA[4] = ArrayB[4], 'ArrayA[4] <> ArrayB[4]');
end;
This works by the fact that the array is layed out in a linear fashion, so your copying the bytes starting at the first array position, for the length of the array.
You can force the compiler to assume they are of the same type by typecasting them:
type
TIntArray = array[1..4] of integer;
begin
Assert(SizeOf(ArrayA) = SizeOf(TIntArray));
Assert(SizeOf(ArrayB) = SizeOf(TIntArray));
TIntArray(ArrayA) := TIntArray(ArrayB);
But you should make sure that both actually are array[1..4] of otherwise you will overwrite some memory. That's why I added the two assertions.
Just use UnitA in UnitB after inteface and before the implementation ...!!!!
Never, never, NEVER use code like this:
// This is where the move from ArrayA to ArrayB happens.
Move( ArrayA[1], ArrayB[1], SizeOf(ArrayA) );
Where's the flaw? You're using the SOURCE size to get the number of bytes to move, not the DESTINATION size!!! If SizeOf(A) > SizeOf(B) you have a buffer overflow and you're overwriting memory. If you're luck you get an AV, if you're not you have an exploitable vulnerability. It's far better to always use the destination size, although this way you can end up reading memory you shouldn't if Size(B) > Size(A), maybe exposing unwanted data.
Anyway, always check structure boundaries when moving data - some companies banned operations like this (i.e. memcpy() ) from their code.
I'm developing class to represent special kind of matrix:
type
DifRecord = record
Field: String;
Number: Byte;
Value: smallint;
end;
type
TData = array of array of MainModule.DataRecord;
type
TDifference = array of DifRecord;
type
TFogelMatrix = class
private
M: Byte;
N: Byte;
Data: ^TData;
DifVector: ^TDifference;
procedure init();
public
constructor Create(Rows, Cols: Byte);
destructor Destroy;
end;
Now in constructor I need to reserve memory for Data and DifVector class members. I use pointers to array of records, as you see. So, the main question is, how can I correctly reserve memory? I suppose I can not use something like that:
new(Data);
new(DifVector);
cause I`m loosing the main idea - to reserve memory space, as much as I want to, at run-time. Thanks for comments.
Since you're using dynamic arrays, array of, then you should use SetLength to specify the length of the array, which can be done dynamically.
ie. like this:
SetLength(Data, 100);
This will not reserve 100 bytes, but will reserve enough space to hold 100 elements of whatever type the array holds.
Change your declarations for the arrays to simple arrays:
Data: TData;
DifVector: TDifference;
and use it with SetLength, it should do the trick.
Also note that In Delphi variables of a dynamic array type are stored as a pointer (in DotNet-speak you would call this a reference-type).
Unless you cast this variable to a pointer, the compiler won't let you do the allocation yourself. You should use SetLength() like lassevk mentioned already.
With a multi-dimensional array (like TData), you could set both dimensions in one go, by setting all dimension with one call to SetLength(). This results in a cube-like structure (each dimension has equal length). But it's also possible to give each index within a dimension a different length to it's next dimension. With two dimensions, this is sometimes called a 'jagged' array.
To do this, you would write it out like this :
SetLength(Data, SizeOfFirstDimension);
for i = 0 to SizeOfFirstDimension - 1 do
SetLength(Data[i], SizeOfSecondDimensionPerIndex(i));
In this example, I use a function called 'SizeOfSecondDimensionPerIndex' to determine the size of each array in the 2nd dimension, but you could determine this size any way you want.
On a side-note, I would advise you to use the 'R'-prefix for record-type definitions. I know this not in any of the major coding-style guides, but if you look at 'P'-prefixes for pointers, 'I'-prefixes for interfaces, 'F'-prefixes for class-fields, 'a'-prefixes for arguments, 'C'-prefixes for constants, 'S'-prefixes for resourcestring's, you can follow this logic and use an 'R'-prefix for records. I know this has helped me to get a better grasp of my code!
Good luck!