Solved

union type in C header conversion

Posted on 2004-04-13
21
283 Views
Last Modified: 2010-04-05
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
Comment
Question by:Jana618
  • 8
  • 7
  • 6
21 Comments
 
LVL 12

Assisted Solution

by:Lee_Nover
Lee_Nover earned 125 total points
ID: 10812576
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
 
LVL 11

Accepted Solution

by:
robert_marquardt earned 125 total points
ID: 10814129
"packed" may not be correct.
The structure packing is handled by pragmas or compler options in C.

"ShortInt" is wrong. Use "Smallint".
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 10820422
my bad on the ShortInt .. sorry
about 'packed' .. they usualy are packed so I wrote it like that
anyway tnx for correcting me :)
0
 

Author Comment

by:Jana618
ID: 10830290
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
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 10830328
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
 

Author Comment

by:Jana618
ID: 10830809
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
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 10830872
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
 

Author Comment

by:Jana618
ID: 10830987
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
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 10831099
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
 

Author Comment

by:Jana618
ID: 10831169
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
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 12

Expert Comment

by:Lee_Nover
ID: 10831200
humz ... try with packed records :)
0
 
LVL 11

Expert Comment

by:robert_marquardt
ID: 10832796
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
 

Author Comment

by:Jana618
ID: 10838742
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
 
LVL 11

Expert Comment

by:robert_marquardt
ID: 10839215
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
 

Author Comment

by:Jana618
ID: 10839297
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
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 10839345
ha ! so I was right about the structs being packed :-D
0
 
LVL 11

Expert Comment

by:robert_marquardt
ID: 10839520
Please give the C declaration of the function GetPairs.
From the description your Pascal conversion is wrong.
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 10839605
 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
 

Author Comment

by:Jana618
ID: 10839632
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
 
LVL 11

Expert Comment

by:robert_marquardt
ID: 10840857
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
 
LVL 11

Expert Comment

by:robert_marquardt
ID: 10840881
Oops:
   Num := 101;
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now