Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

union type in C header conversion

Posted on 2004-04-13
21
Medium Priority
?
302 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 500 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 500 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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 

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

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Question has a verified solution.

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

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…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
this video summaries big data hadoop online training demo (http://onlineitguru.com/big-data-hadoop-online-training-placement.html) , and covers basics in big data hadoop .
Screencast - Getting to Know the Pipeline
Suggested Courses

916 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