Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

records as parameters 1

Status
Not open for further replies.

sggaunt

Programmer
Jul 4, 2001
8,620
GB
Can any one help with this

I am attempting to convert some 'C' to Delphi
Part of the software's function is to read in data from several differently structured files, into associated structures.
I have set up Pascal records with the same format (no problem here).
But the original code contains a function which accepts the name of a structure as a parameter, it is then able to read into this structure without knowing anything about the format. This seems to be done by pssing a void pointer to the structure.
declared as e.g.
readfunction(size ,void *generalstruct, etc)
called with readfunction(sizeof(strucname) (char *)&structname)

A block read of the file is accomplised by also passing in the structure(record) size.

So far I have not found a way to pass such a generic pointer to a Delphi procedure
Does anyone know how to do this in Delphi?
Steve
 
Have you tried the Addr function ? This returns the address of a given object. I think this is what you are wanting.

So your ReadFunction would start something like
Code:
procedure ReadFunction ( size: integer; GeneralStruct: pointer);
....
end;
It would be called by something like
Code:
ReadFunction ( sizeof(strucname), Addr(strucname) );
Andrew

 
Andrew
Thanks for that. It complies OK and seems resonable but
the code below crashs Windows immediatly with an Invalid Page fault..

Steve.


type
long_adtest_spec = record
record_status: smallint;
file_name: string[21];
common: common_long_adheader;
idle_speed_limit: array [0..1] of smallint;
test_speed_limit: array [0..1] of smallint;
profile: array [0..2, 0..2] of smallint;
x_limit: array [0..1] of smallint;
hyst: smallint;
end;
{common_long_adheader is just another structure with simular fields}

var
LongPspec :long_adtest_spec;
stream: file;


procedure TForm1.Button1Click(Sender: TObject);
begin
with openfile do
if execute then
begin
Evaluate(FileName, Sizeof(LongESpec), addr(LongEspec));
end;

end;


procedure TForm1.Evaluate(FileName: Tfilename; Size: Integer; Rec: Pointer);
begin
try
assignfile(stream, filename);
Reset(stream, 1);
blockRead(stream, rec ,size);
finally
closefile(stream);
end;
end;
 
[tt]
procedure TForm1.Button1Click(Sender: TObject);
begin
with openfile do
if execute then
begin
Evaluate(FileName, Sizeof(LongESpec), @LongEspec);
end;
end;


procedure TForm1.Evaluate(FileName: Tfilename; Size: Integer; Rec: PChar);
begin
try
assignfile(stream, filename);
Reset(stream, 1);
blockRead(stream, rec[0] ,size);
finally
closefile(stream);
end;
end;
[/tt]
 
Cheers ppc386, that is very close indeed,
no crashs now, but I do seem to be loosing proggessivley more characters from the start of each sucessive field,
I will look a bit harder, but if you can think of something obvious.
Sorry about the missing W Andrew this keyboard is rubbish.
Steve
 
I would be surprised if String[21] is correct. This is an example of a Pascal short string where byte zero contains the string length (max length of 255) and byte one is the first byte of the string.

This kind of string would be very unusual in a C (or C++) program. I would have guessed that you should be using something like
Code:
  filename: array [ 0..21 ] of char;
and then using null-terminated string functions and procedures.
Depending on the actual length of the filename field there might also be some packing issues to contend with.

Andrew

 
Some piece of code knows the name of the structure (perhaps from the file name?). You are going to have an "if ..then else if then ... else if then ..." somewhere.

You can use overloaded function if you want to avoid having differently-named methods for each format, and you can even use polymorphism to avoid having more than one &quot;if..&quot; (that's really what polymorphism is used for most often <s>), but either in the function or in its caller, some piece of code has to decide what the format it.

Do I misunderstand?
 
Andrew
Yes the original 'C' structure has arrays of Char as you suggest, I got the string[n] syntax from a magazine tutorial on file streaming in Delphi, where the data sizes must be fixed. but it allows you the power of Delphi 'strings'. Isn't byte[0] always inaccessible in delphi strings?.
As I am attemping to read 'C' created files you are probobly right about the arrays of char and I will try changing the records defintions to same.

As I explained in my opening question, the original 'C' code does not need to know the structure of the records, It accepts a pointer to the memory location of the data and reads it all in successivly, as in 'C', Pascal records are arranged sequentialy in memory, I needed a way to duplicate the 'C' codes access to the data.
Yes I could have used 'overloaded' functions to do this but there are about 9 different record types in the application, that would have been a lot of extra code, and ment changing the structure of the application much more than I have.

Steve.

 
Byte zero of a Pascal string is accessible. You can easily demonstrate this to yourself:
Code:
procedure TForm1.TestByteZero;
var
  test: string[21];
  length: integer;
begin
  test := 'test it';
  length := Integer ( test[0] );
  ShowMessage ( IntToStr ( length ) );
end;

I was trying to explain why you were losing characters in your strings. Byte zero of your C array would be considered part of the string in C but would be considered to be the string length in Pascal.

Does it work now (using array [ 0..xx ] of char) ?

Andrew
 
Andrew

The simple answer is yes, there were/are some other probs,
the record had a nested component, this seemed to loose a charater from the first field Perhaps Delphi uses a pointer to the nested part as the first char.

The 'common: common_longad_header' part of the record in the code I posted.

I got round this by including the nested part in the main structure?.

A problem remains that the subsiquent integer fields are not reading correctly. maybe this is the same sort of problem as with the nested record?

Steve.



 
Can you post the entire record structure? It might help to have the original C code as well from which you did the conversion.

But first, are you aware of the Pascal 'packed' reserved word? This affects how fields are aligned on boundaries and might explain the problem.

Andrew

 
Sure 'C' structures (2 used for test there are lots of them)
are:-

typedef struct
{char drive_model[21];
char part_number[21];
char fan_type[21];
char fan_geometry[21];
int input_speed;
int number_blades;
int RPM_at;
}common_long_adheader;

typedef struct
{
int record_status; /* 0=OK, 1=deleted */
char file_name[21];
common_long_adheader common;
int idle_speed_limit[2];
int test_speed_limit[2];
int profile[3][3];
int x_limit[2];
int hyst;
}long_adtest_spec;

variable defided as
extern long_adtest_spec long_pspec;

my Pascal versions look like

// long test specification */

type
LongTestSpec = record
record_status: smallint; // 0=OK, 1=deleted
file_name: array[0..20] of char;
common: common_long_header;
temp_profile: TProfile;
upper_limit : array [0..5, 0..1] of smallint;
lower_limit : array [0..5, 0..1] of smallint;
hysteresis : array [0..2, 0..1] of smallint;
end;

}
type
long_adtest_spec = record
record_status: smallint; // 0=OK, 1=deleted */
file_name: array[0..20] of char;
drive_model: array[0..20] of char;
part_number: array[0..20] of char;
fan_type: array[0..20] of char;
fan_geometry: array[0..20] of char;
Input_speed: smallint;
number_blades: smallint;
RPM_at: smallint;

// common: common_long_adheader;
idle_speed_limit: array [0..1] of smallint;
test_speed_limit: array [0..1] of smallint;
profile: array [0..2, 0..2] of smallint;
x_limit: array [0..1] of smallint;
hyst: smallint;
end;

Note fields included from embedded record

This is a typical call to the reader form the 'C' code
case LONG_ESPEC:
if (get_index((net == ON) ? LONG_EDATA_NET : LONG_EDATA_LOCAL
,sizeof(long_espec)
,(char *) &long_espec
,long_espec.file_name)==ERR_RET)
return(ERR_RET);
break;


This inside the function get_index declared as
int get_index(char *filename,int record_size,void *spec,char *title)

rewind(stream1);
for (x = 0; x < records; x++)
{
fseek(stream1,(long)((x * record_size) + sizeof(int)), SEEK_SET);
fgets(file_name, 21, stream1);
if (strcmp(file_name,index[selection]) == 0)
{
fseek(stream1,(long)(x * record_size), SEEK_SET); /* start of record */
fread(spec, sizeof(char), record_size,stream1); /* read in spec */
fclose(stream1);
net_unlock();
return(x);
}
}

fclose(stream1);
net_unlock();
etc..


Steve

 
Andrew

after some jigging around with a calculator, see that it is the same affect I am loosing the first byte of the integer information the rest gets pulled forward.
so i am expecting for input_speed, number_blades and RPM_at
1000, 30,100 and I get 7683, 25600 in hex this is :-
03E8 , 1E, 64 getting 1E03 6400.

The Byte order is reversed (not a problem) but the inital E8 is missing.
Steve

 
I am pretty sure it is an alignment problem. The Pascal compiler is inserting a filler character to align input_speed (as it is a small integer) on a 16 bit boundary because file_name is an odd number of bytes long. The E8 is falling into this filler character.

I suggest you try marking all the pascal records as 'packed'. For example:
Code:
  LongTestSpec = packed record
    ...
  end;


Andrew
 
Cheers Andrew This one is wrapped up now.
Packed records did the trick, Nesting, byteorder, all is now OK.

Steve.

 
A general note--when records are written to disk they should *ALWAYS* be declared packed so they don't get broken by some later version of the compiler. The only case that broke here was the subrecord because in the other cases the compiler saw there was no point in aligning them. However, that's not always the case. Had those numbers been bigger the main record would have misaligned also.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top