Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 305
  • Last Modified:

union type in C header conversion

Hi, I'm trying to convert a c header file, and I'm getting access violations when using a union type.
Can anyone help me out?

  union Pair (
    unsigned short LPr ;
    struct (
     unsigned char ID ;
     unsigned char ID ;
    );
  );                                          
0
Jana618
Asked:
Jana618
  • 8
  • 7
  • 6
2 Solutions
 
Lee_NoverCommented:
type
  Pair = packed record
  case integer of
    0: (LPr: ShortInt);
    1: (ID1, ID2: Byte);
  end;


you can also make that ID1, ID2 a record and use a record instead like:

type
  IDRec = packed record
    ID1: Byte;
    ID2: Byte;
  end;

  Pair = packed record
    case integer of
      0: (LPr: ShortInt);
      1: (IDs: IDRec);
  end;
0
 
robert_marquardtCommented:
"packed" may not be correct.
The structure packing is handled by pragmas or compler options in C.

"ShortInt" is wrong. Use "Smallint".
0
 
Lee_NoverCommented:
my bad on the ShortInt .. sorry
about 'packed' .. they usualy are packed so I wrote it like that
anyway tnx for correcting me :)
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Jana618Author Commented:
type
  IDRec = record
    ID1: Byte;
    ID2: Byte;
  end;
  Pair = record
    case Integer of
      0: (LPr: SmallInt);
      1: (IDs: IDRec);
  end;

This seems to be it, except for a problem I've run into trying to use the type...
I call a function that should fill an array:

type PairArray = array of Pair;
type PPairArray = ^PairArray;

function GetPairs(var pPairs: PPairArray; var pMaxPairs: Integer): Integer;

from C delclaration:
int WINAPI GetPairs(Pair *pPairs, int *pMaxPairs );

where the Integer result indicates success/error of the function. When called the function returns the integer value for success, and pMaxPairs is returning the expected number of pairs for the test (2, which is changed from it's input value  by the function), but when I try to list the byte values of pairs in the array, values are all = 0 (I'm expecting the 2 pair of array values: 9 & 1; and  18 & 1 for the test)

I'm using this just to display the contents if the array:
ListBox1.Items.Add('ID1 = ' + IntToStr(Pairs[I].IDs.ID1) + 'ID2 = ' + IntToStr(Pairs[I].IDs.ID1));

0
 
Lee_NoverCommented:
use "var pPairs: PairArray" - function GetPairs(var pPairs: PairArray; var pMaxPairs: Integer): Integer;
that's the delphi way .. or a c-way like: GetPairs(pPairs: PPairArray; pMaxPairs: PInteger): Integer;

I prefer the first method
0
 
Jana618Author Commented:
If I call:
function GetPairs(var Pairs: PairArray; var MaxPairs: Integer): Integer;
Although the function GetPairs doesn't generate errors, and the value of MaxPairs changes to the expected value in the test, any calls to access values in the array after the function call cause access violations, and an access violation is generated when the function that the GetPairs call is in returns (even if the values in the array are not accessed in the function).

If I call:
function GetPairs(var pPairs: PPairArray; var MaxPairs: Integer): Integer;
then after the GetPairs call I have an array containing all LPr, ID1 and ID2 values = 0 (up to the length of the array = 32, btw).

I call the function using:
  SetLength(Pairs,32);
  MaxPairs := 32;
  New(PairsPtr);
  PairsPtr^ := Pairs;
  Value := GetPairs(PairsPtr, MaxPairs);
  ListBox1.Items.Add('Pairs: ' + IntToStr(MaxPairs));  
  for i := 0 to MaxPairs do
  begin
    ListBox1.Items.Add('ID1 = ' + IntToStr(Pairs[I].IDs.ID1) + 'ID2
                               = ' + IntToStr(Pairs[I].IDs.ID2));
  end;  

  This corresponds to the C example I have:

  Pair Prs[32];
  int Num;
  if(GetPairs(Prs, &(Num = 32)) == success_value)
  {
      printf("Pairs:\n");
      for(i=0; i<Num; i++)
      {
            printf("0x%02x -> 0x%02x\n", Prs[i].ID1, Prs[i].ID2);
       }
  }


0
 
Lee_NoverCommented:
function GetPairs(var pPairs: PairArray; var pMaxPairs: Integer): Integer;

var
  pp: PairArray;
  mp, lres: Integer;
begin
  mp:=32;
  SetLength(pp, mp);
  lres:=GetPairs(pp, mp);




example with pointers:

function GetPairs(pPairs: PPairArray; pMaxPairs: PInteger): Integer;

var
  pp: PPairArray;
  mp, lres: Integer;
begin
  mp:=32;
  GetMem(pp, SizeOf(Pair) * mp);
  lres:=GetPairs(pp, @mp);
  // ofcourse don't forget to call
  FreeMem(pp);




both should work
0
 
Jana618Author Commented:
much tighter code, but it does the same thing....
Passing in the array causes the two access violations, and passing in the pointer to array doesn't cause errors, but the array is filled entirely with 0's.
FreeMem won't compile, btw, constant expression expected.
0
 
Lee_NoverCommented:
ofcourse we missed an important thing: calling convention ! :)
if nothing is specified in the dll then it's cdecl ... seeing WINAPI I assume it's stdcall
just append stdcall; at the end of the function declaration
function GetPairs(var pPairs: PairArray; var pMaxPairs: Integer): Integer; stdcall;
0
 
Jana618Author Commented:
sorry Lee, I do have stdcall on the function declaration. I've also tried with cdecl, and that gives the same result. It may be that the fault is not with the type def or function call. tomorrow I'll try running C and Java test programs.... unless we can think of anything else to try.
Cheers
0
 
Lee_NoverCommented:
humz ... try with packed records :)
0
 
robert_marquardtCommented:
If packed does not work:
Can you write a working C program calling the function?
If so then write one to show the value of sizeof(struct Pair).
With that we can determine the real packing of the structure and set it in Delphi with a compiler option.
0
 
Jana618Author Commented:
Many thanks to you both...  it needed:

type
  TIDRec = packed record
    ID1: Byte;
    ID2: Byte;
  end;
  TPair = packed record
    case Integer of
      0: (Pr: SmallInt);
      1: (IDs: TIDRec);
  end;
type TPrArray = array of TPair;

function GetPairs(pPairs: TPrArray; var pMaxPairs: Integer) : Integer; stdcall;
0
 
robert_marquardtCommented:
function GetPairs(pPairs: TPrArray; var pMaxPairs: Integer) : Integer; stdcall;

This looks suspicious.
An "array of" parameter in Delphi adds an invisible extra parameter for the size of the array.
0
 
Jana618Author Commented:
The description of the method in the C header file states that the integer pMaxPairs holds the max size of the array on input, and the number of pairs retreived on output (rather than size of the array), so it's behaving as expected for the test cases that I've done so far... sorry if that wasn't very clear before.
would you still say it's suspicious in that case?
0
 
Lee_NoverCommented:
ha ! so I was right about the structs being packed :-D
0
 
robert_marquardtCommented:
Please give the C declaration of the function GetPairs.
From the description your Pascal conversion is wrong.
0
 
Lee_NoverCommented:
 union Pair (
    unsigned short LPr ;
    struct (
     unsigned char ID ;
     unsigned char ID ;
    );
  );  

from C delclaration:
int WINAPI GetPairs(Pair *pPairs, int *pMaxPairs );


so delphi version should have "var Pair" param

function GetPairs(var pPairs: TPrArray; var pMaxPairs: Integer) : Integer; stdcall;
0
 
Jana618Author Commented:
C declaration:
/* get an array of pairs
on entry, set *pMaxPairs to the size of the array pPairs you have allocated
return values
0 = success, *pMaxPairs will be the # elements returned
-1= array too small; *pMaxPairs will be updated to the # slots that are needed
*/
int WINAPI GetPairs(Pair *pPairs, int *pMaxPairs);
typedef int (WINAPI * _fndef_GetPairs)(Pair *pPairs, int *pMaxPairs);

I've defined both static and dynamic linking in the import unit, and I'm using the module loader from http://www.delphi-jedi.org/APILIBRARY:329523 (I've had some help doing another header conversion before - thanks Robert!)

I find that if I use a var parameter for pPairs:
function GetPairs(var pPairs: TPrArray; var pMaxPairs: Integer) : Integer; stdcall;
I get an access violation,
but:
function GetPairs(pPairs: TPrArray; var pMaxPairs: Integer) : Integer; stdcall;
Gets the expected results...
0
 
robert_marquardtCommented:
The correct declaration is:

type
  PPair = ^TPair;
  TPair = packed record
    case Integer of
      0: (Pr: SmallInt);
      1: (IDs: TIDRec);
  end;

function GetPairs(Pairs: PPairs; var MaxPairs: Integer): Integer; stdcall;

Usage:

var
  Pairs: array [0..100] of TPairs;
  Num: Integer;
begin
  // tell how many entries are in the array
  Num := 100;
  GetPairs(@Pairs[0], Num);
  // Num probably now containing the number of pairs copied to Pairs array.

0
 
robert_marquardtCommented:
Oops:
   Num := 101;
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

  • 8
  • 7
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now