Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

union type in C header conversion

Posted on 2004-04-13
21
291 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
Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 

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
 
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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
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…
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

856 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