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.
Related
I have a C++ DLL:
int __stdcall Hello(int numFiles, char **inFiles)
and I don't know how to translate this char **.
I tried:
function Hello(numFiles: Integer; InFiles: PPChar): Integer; stdcall; external 'dll2.dll';
and then:
Files: array of PChar;
begin
SetLength(Files, 2);
Files[0] := PChar('siema.jpg');
Files[1] := PChar('siema2.jpg');
c := Hello(2, #Files[0]);
but all I get is "Access violation"
On the face of it, given the information in the question, your code seems basically fine. However, a rookie mistake, made by many beginners with interop, is to believe that a function's signature is enough to define the interface. It is not. For instance, a parameter of type char** could be used for many different things. So, to specify the information you must also specify the semantics of the parameters, not just the syntax.
Given
int __stdcall Hello(int numFiles, char **inFiles)
let us assume the following:
The return value is an error code, with 0 indicating success.
The first parameter is the number of files.
The second parameter is an array of files, of length specified by the first parameter. Each element of the array is a C string, a pointer to a null-terminated array of 8 bit characters.
With those assumptions in place, I would write the code like this:
function Hello(numFiles: Integer; InFiles: PPAnsiChar): Integer; stdcall;
external 'dll2.dll';
The function would be called like this:
var
Files: array of PAnsiChar;
retval: Integer;
....
SetLength(Files, 2);
Files[0] := PAnsiChar('siema.jpg');
Files[1] := PAnsiChar('siema2.jpg');
retval := Hello(Length(Files), PPAnsiChar(Files));
if retval <> 0 then
... handle error
You might prefer to write the final parameter as #Files[0] if you prefer. I prefer the cast because it allows me to pass an empty array even when range checking is enabled.
Note that I used PAnsiChar to match with char*. The PChar type is an alias to either PAnsiChar or PWideChar depending on the Delphi version. It is better to be explicit.
Of course, my assumptions may be wrong. You should confirm them by consulting the library's documentation.
Delphi has:
var : pass by reference; parameter is both input and output.
out : pass by reference; parameter is output only.
const: pass by ..... well it depends; parameter is input only.
in : pass by reference; parameter is input only and will not be changed there is no "in".
I don't mind that there is no spoon, but I miss in; considering the following code, is there a cleaner way of doing this?
type TFastDiv = record
strict private
FBuffer: Int64;
other fields
....
//Must be `var` because `const` would pass a Int64 by value
// |||
// VVV
function DivideFixedI32(var Buffer: Int64; x: integer): integer;
asm
mov r9,rcx
imul dword ptr[rcx] // do stuff with the buffer
..
mov ecx, [r9+4] // do other stuff with the rest of the buffer
{Changing the code to imul ecx;...;shr r9,32;mov ecx,r9d would allow pass by value, but let's assume the code must not be changed.}
class operator TFastDiv.IntDivide(x:integer; const buffer:TFastDiv):integer;
begin
Result:= DivideFixedI32(Int64((#buffer.FBuffer)^), abs(x)); <<-- Ugly
if (x < 0) then Result:= - Result;
end;
DivideFixed will never change the buffer. The whole point of the routine is that buffer is a precalculated value that does not change.
In the class operator I declare buffer as const, because the record must not change.
The question is:
If I insist on declaring the buffer parameter in IntDivide as const is there a cleaner way of coding or am I stuck in the pointer_to/points_to hack?
Newer compiler versions (from XE3 onwards) support the [Ref] decorator:
procedure Foo(const [Ref] Arg1: Integer; [Ref] const Arg2: Byte);
Example adapted from the documentation, which emphasises the [Ref] can go either before or after the const keyword.
The only option (pre Delphi XE3) if you want to ensure pass-by-reference, is to pass something big.
i.e. bigger than sizeof(pointer)
type TFastDiv = record
strict private
FBuffer: Int64; <<-- make sure this is the first member
other fields
....
function DivideFixedI32(const Buffer: TFastDiv; x: integer): integer;
...
class operator TFastDiv.IntDivide(x:integer; const buffer:TFastDiv):integer;
begin
Result:= DivideFixedI32(buffer, abs(x));
This line in the Delphi help file:
Sets, records, and static arrays of 1, 2, or 4 bytes are passed as 8-bit, 16-bit, and 32bit values. Larger sets, records, and static arrays are passed as 32-bit pointers to the value. An exception to this rule is that records are always passed directly on the stack under the cdecl, stdcall, and safecall conventions; the size of a record passed this way is rounded upward to the nearest double-word boundary.
is misleading and should be changed to/read as:
Sets, records, and static arrays up to SizeOf(pointer) are passed as 8-bit, 16-bit, and 32bit values (64 bit values on x64). Sets, records, and static arrays larger than SizeOf(Pointer) are passed as pointers to the value. An exception to this rule is that records are always passed directly on the stack under the cdecl, stdcall, and safecall conventions; the size of a record passed this way is rounded upward to the nearest SizeOf(pointer) boundary.
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.
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.
I'm needing to call a Windows API function introduced in Vista from my Delphi app, but I don't have any Delphi headers which describe the function.
Related functions are already documented in the JEDI Windows API library, but not this function.
My C++ is almost non-existent, and I'm struggling to work out the Delphi definitions that correspond to the function and it's parameter as documented on MSDN.
From http://msdn.microsoft.com/en-us/library/aa814417.aspx
NETIOAPI_API GetIpInterfaceEntry(__inout PMIB_IPINTERFACE_ROW Row);
typedef struct _MIB_IPINTERFACE_ROW {
ADDRESS_FAMILY Family;
NET_LUID InterfaceLuid;
NET_IFINDEX InterfaceIndex;
ULONG MaxReassemblySize;
ULONG64 InterfaceIdentifier;
ULONG MinRouterAdvertisementInterval;
ULONG MaxRouterAdvertisementInterval;
BOOLEAN AdvertisingEnabled;
BOOLEAN ForwardingEnabled;
BOOLEAN WeakHostSend;
BOOLEAN WeakHostReceive;
BOOLEAN UseAutomaticMetric;
BOOLEAN UseNeighborUnreachabilityDetection;
BOOLEAN ManagedAddressConfigurationSupported;
BOOLEAN OtherStatefulConfigurationSupported;
BOOLEAN AdvertiseDefaultRoute;
NL_ROUTER_DISCOVERY_BEHAVIOR RouterDiscoveryBehavior;
ULONG DadTransmits;
ULONG BaseReachableTime;
ULONG RetransmitTime;
ULONG PathMtuDiscoveryTimeout;
NL_LINK_LOCAL_ADDRESS_BEHAVIOR LinkLocalAddressBehavior;
ULONG LinkLocalAddressTimeout;
ULONG ZoneIndices[ScopeLevelCount];
ULONG SitePrefixLength;
ULONG Metric;
ULONG NlMtu;
BOOLEAN Connected;
BOOLEAN SupportsWakeUpPatterns;
BOOLEAN SupportsNeighborDiscovery;
BOOLEAN SupportsRouterDiscovery;
ULONG ReachableTime;
NL_INTERFACE_OFFLOAD_ROD TransmitOffload;
NL_INTERFACE_OFFLOAD_ROD ReceiveOffload;
BOOLEAN DisableDefaultRoutes;
}MIB_IPINTERFACE_ROW, *PMIB_IPINTERFACE_ROW;
Among other bits, the bit I'm struggling with at the minute is the ZoneIndices[ScopeLevelCount] field; I can't work out what size the array is supposed to be.
This is what I've defined so far, although I haven't worked out the enums in the original C++ definition yet. I'll be explicitly loading the Windows DLL on Vista and getting the address of the new function to call.
type
PMIB_IPINTERFACE_ROW = ^MIB_IPINTERFACE_ROW;
{$EXTERNALSYM PMIB_IPINTERFACE_ROW}
_MIB_IPINTERFACE_ROW = record
Family: ADDRESS_FAMILY;
InterfaceLuid: NET_LUID;
InterfaceIndex: NET_IFINDEX;
MaxReassemblySize,
InterfaceIdentifier,
MinRouterAdvertisementInterval,
MaxRouterAdvertisementInterval: Cardinal;
AdvertisingEnabled,
ForwardingEnabled,
WeakHostSend,
WeakHostReceive,
UseAutomaticMetric,
UseNeighborUnreachabilityDetection,
ManagedAddressConfigurationSupported,
OtherStatefulConfigurationSupported,
AdvertiseDefaultRoute: LongBool;
RouterDiscoveryBehavior: NL_ROUTER_DISCOVERY_BEHAVIOR;
DadTransmits,
BaseReachableTime,
RetransmitTime,
PathMtuDiscoveryTimeout: Cardinal;
LinkLocalAddressBehavior: NL_LINK_LOCAL_ADDRESS_BEHAVIOR;
LinkLocalAddressTimeout,
ZoneIndices[ScopeLevelCount],
SitePrefixLength,
Metric,
NlMtu: Cardinal;
Connected,
SupportsWakeUpPatterns,
SupportsNeighborDiscovery,
SupportsRouterDiscovery: LongBool;
ReachableTime: Cardinal;
TransmitOffload: NL_INTERFACE_OFFLOAD_ROD;
ReceiveOffload: NL_INTERFACE_OFFLOAD_ROD;
DisableDefaultRoutes: LongBool;
end;
{$EXTERNALSYM _MIB_IPINTERFACE_ROW}
MIB_IPINTERFACE_ROW = _MIB_IPINTERFACE_ROW;
{$EXTERNALSYM MIB_IPINTERFACE_ROW}
TMibIpInterfaceRow = MIB_IPINTERFACE_ROW;
PMibIpInterfaceRow = PMIB_IPINTERFACE_ROW;
const
iphlpapilib = 'iphlpapi.dll';
var
HIpHlpApi: THandle = 0;
GetIpInterfaceEntry: function(const pArpEntry: MIB_IPINTERFACE_ROW): LongInt; stdcall;
{$EXTERNALSYM GetIpInterfaceEntry}
Does anybody out there have suggestions or tips/tricks for translating a function definition like this?
Many thanks,
Conor
The Win32 BOOLEAN type is one byte, but Delphi's LongBool type is four. Use Delphi's ByteBool instead.
Maybe you can try "C 2 pas"
http://cc.embarcadero.com/Item/26951
Also found these tools:
http://www.drbob42.com/delphi/headconv.htm
http://rvelthuis.de/programs/convertpack.html
http://rvelthuis.de/articles/articles-convert.html#cconvs
Hmm. A strange structore. But if you look into w2def.h, you can see that ScopeLevelCount=16. So your array should have 16 elements,
Make sure you use the packed command when defining your record because Delphi aligns complex data types on 2, 4 or 8 byte boundaries by default.
TExample = record
f1: Integer; // start at offset 0x00
f2: Char; // start at offset 0x04
f3: Integer; // start at offset 0x06 or 0x08 depending on alignment
end;
TExample = packed record // this is what c++ would do
f1: Integer; // start at offset 0x00
f2: Char; // start at offset 0x04
f3: Integer; // start at offset 0x05
end;
The ZoneIndices array should be defined like this:
ZoneIndices : array [0..ScopeLevelCount - 1] of Cardinal;
ScopeLevelCount is a constant that is 16
I often used Dr. Bob's Header Converter for this task, but mostly I took the long and tedious way of manually performing the conversion, because it helped me to understand the API better. (Because I was going to use it and I have to familiarize myself with it anyway)
Also see this article: http://www.delphi-jedi.org/api-howto.html
In general it's best not to put to much hopes on a header conversion tool, because C++ is a very powerful and complex language. Most conversion tools I tested only supported a subset of C++ and its preprocessor, thus making it necessary to manually make fixes to the generated source.
you can investigate some already translated APIs/structures that related to this subject and convert it yourself. for example this one
I don't see any field of type ULONG64 in the translation, but I do in the original.
Further, FPC also has an header converter which works fine for structs. Typically windows api structures are packed.
In doubt, use some free msvc product to write the sizeof(structure) and do the same under pascal. If that matches, and you still have doubts, calculate field offsets with a bit of pointer magic and compare them.