delphi112497
asked on
How can I copy a record ?
Hi!
How can I copy a pointer to a record into another variable of the same record type ?
For example, I have the following code which obviously doesn't work but might give you an idea of what I want to accomplish.
PSOME_RECORD = ^TSOME_RECORD;
TSOME_RECORD = record
a:PChar;
b:PChar;
c: Cardinal;
end;
And then I have the following
function getRecord(offset: integer) : PSOME_RECORD;
begin
//This function works correctly
Result := PSOME_RECORD_Func(offset);
end;
var
FRecords : array of TSOME_RECORD;
begin
SetLength(FRecords, 10);
for i=0 to 9 do
FRecords[I] := GetRecord(i)^; <- this is the part I'm having problems with ...
end;
I know I can easily do this by copying every member explicitly, but since TSOME_RECORD might change at some time, I want a solution that will require the least maintenance possible. I.E. copy the record-pointers directly into a records-array.
If the solution is simpler, FRecords can be switched to
FRecords : array of PSOME_RECORD, but the pointers must not point to the original result of GetRecord();
Thanks.
How can I copy a pointer to a record into another variable of the same record type ?
For example, I have the following code which obviously doesn't work but might give you an idea of what I want to accomplish.
PSOME_RECORD = ^TSOME_RECORD;
TSOME_RECORD = record
a:PChar;
b:PChar;
c: Cardinal;
end;
And then I have the following
function getRecord(offset: integer) : PSOME_RECORD;
begin
//This function works correctly
Result := PSOME_RECORD_Func(offset);
end;
var
FRecords : array of TSOME_RECORD;
begin
SetLength(FRecords, 10);
for i=0 to 9 do
FRecords[I] := GetRecord(i)^; <- this is the part I'm having problems with ...
end;
I know I can easily do this by copying every member explicitly, but since TSOME_RECORD might change at some time, I want a solution that will require the least maintenance possible. I.E. copy the record-pointers directly into a records-array.
If the solution is simpler, FRecords can be switched to
FRecords : array of PSOME_RECORD, but the pointers must not point to the original result of GetRecord();
Thanks.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
swift99,
your code stores pointers ... not the actual values. If I later free all the memory involved in GetRecord(), FRecords will be affected also :(
snehanshu,
your code is basically what I ended up with, and everything works except for the null terminated PChars :( ... is there any way I can copy the PChars also ? Besides Cardinal and PChar, I also have an enum member ... the real record looks something more as:
type
my_enum_values = (type1, type2, type3 ... typen);
TSOME_RECORD = record
a: Cardinal;
b: PChar;
c: my_enum_values;
end;
I don't think there's any problem with 'c', but the PChar just messes things up :(
The reason for all this is TSOME_RECORD and GetRecord come from a DLL and the DLL uses too much memory; I must free it as soon as I'm done with it and FRecords[] is used all through out the application.
Thanks for helping me out with this!
your code stores pointers ... not the actual values. If I later free all the memory involved in GetRecord(), FRecords will be affected also :(
snehanshu,
your code is basically what I ended up with, and everything works except for the null terminated PChars :( ... is there any way I can copy the PChars also ? Besides Cardinal and PChar, I also have an enum member ... the real record looks something more as:
type
my_enum_values = (type1, type2, type3 ... typen);
TSOME_RECORD = record
a: Cardinal;
b: PChar;
c: my_enum_values;
end;
I don't think there's any problem with 'c', but the PChar just messes things up :(
The reason for all this is TSOME_RECORD and GetRecord come from a DLL and the DLL uses too much memory; I must free it as soon as I'm done with it and FRecords[] is used all through out the application.
Thanks for helping me out with this!
ASKER
I am willing to increase the points to 500 if somebody gives me a good solution ...
I.E. copies the records as specified above
frees FRecords from memory (including all of its PChar members) without explicitly making any name reference to them.
I.E. copies the records as specified above
frees FRecords from memory (including all of its PChar members) without explicitly making any name reference to them.
delphi,
Handling pointer record members is a tough one! I am not sure I know any workaround for that :-(
I shall try to find out, meanwhile, hopefully the better experts might help.
...Shu
Handling pointer record members is a tough one! I am not sure I know any workaround for that :-(
I shall try to find out, meanwhile, hopefully the better experts might help.
...Shu
ASKER
snehanshu, after thinking the problem for a little longer I came to the conclusion it will require A LOT of memory handling and will only make things much harder to debug unless perfect code is provided.
I don't beleive this question will ever be answered to my satisfaction, but I do appreciate the effort and code you provided in your posts.
For the time being I will "hard-copy" each element of the record and will keep the question open.
Thanks for your help anyways.
I don't beleive this question will ever be answered to my satisfaction, but I do appreciate the effort and code you provided in your posts.
For the time being I will "hard-copy" each element of the record and will keep the question open.
Thanks for your help anyways.
delphi,
I am not sure what's happening here, but it seems that Delphi makes the pointer thing would perhaps work just as you like :-)
Check this:
PSOME_RECORD = ^TSOME_RECORD;
TSOME_RECORD = record
a:integer;
b:integer;
c:integer;
MyProb: PChar;
end;
...
procedure TForm1.Button2Click(Sender : TObject);
Var
i: Integer;
MyPtr: PSOME_RECORD;
begin
For i := 1 to 5 do
begin
MyPtr := GetRecord(i);
RecAry[i] := TSOME_RECORD(MyPtr^);
RecAry[i].a := RecAry[i].a * 10;
RecAry[i].MyProb := 'Snehanshu';//Array says Snehanshu
//Snehanshu and Hello both still remain
Showmessage(String(RecAry[ i].MyProb) + String(MyPtr^.MyProb));
FreeMem(MyPtr);
Showmessage(String(RecAry[ i].MyProb) { + String(MyPtr^.MyProb)});
// Showmessage(Format('ary: %d, Ptr: %d',[RecAry[i].a, MyPtr^.a]))
end;
end;
function TForm1.GetRecord(i: integer): PSOME_RECORD;
begin
//
Result := AllocMem(Sizeof(TSOME_RECO RD));
Result^.a := i;
result^.b := i*100;
result^.c := i*1000;
result^.MyProb := AllocMem(10);
result^.MyProb := 'Hello';//DLL says Hello
end;
Cheers!
...Shu
I am not sure what's happening here, but it seems that Delphi makes the pointer thing would perhaps work just as you like :-)
Check this:
PSOME_RECORD = ^TSOME_RECORD;
TSOME_RECORD = record
a:integer;
b:integer;
c:integer;
MyProb: PChar;
end;
...
procedure TForm1.Button2Click(Sender
Var
i: Integer;
MyPtr: PSOME_RECORD;
begin
For i := 1 to 5 do
begin
MyPtr := GetRecord(i);
RecAry[i] := TSOME_RECORD(MyPtr^);
RecAry[i].a := RecAry[i].a * 10;
RecAry[i].MyProb := 'Snehanshu';//Array says Snehanshu
//Snehanshu and Hello both still remain
Showmessage(String(RecAry[
FreeMem(MyPtr);
Showmessage(String(RecAry[
// Showmessage(Format('ary: %d, Ptr: %d',[RecAry[i].a, MyPtr^.a]))
end;
end;
function TForm1.GetRecord(i: integer): PSOME_RECORD;
begin
//
Result := AllocMem(Sizeof(TSOME_RECO
Result^.a := i;
result^.b := i*100;
result^.c := i*1000;
result^.MyProb := AllocMem(10);
result^.MyProb := 'Hello';//DLL says Hello
end;
Cheers!
...Shu
Sorry, that wasn't a proper example.
So, the answer is that you cannot get RTTI for records in Delphi so you cannot do what you want.
the only solution would be to write a wrapper class: but your code would have to be recompiled every time your record structure changes.
...Shu
procedure TForm1.Button2Click(Sender : TObject);
Var
i: Integer;
MyPtr: PSOME_RECORD;
begin
For i := 1 to 5 do
begin
MyPtr := GetRecord(i);
RecAry[i] := TSOME_RECORD(MyPtr^);
RecAry[i].a := RecAry[i].a * 10;
Showmessage(String(RecAry[ i].MyProb) + String(MyPtr^.MyProb));//S hows SHUSHU
RecAry[i].MyProb[0] := 'U';
RecAry[i].MyProb[1] := char(0);
Showmessage(String(RecAry[ i].MyProb) + String(MyPtr^.MyProb));//S hows UU
end;
end;
function TForm1.GetRecord(i: integer): PSOME_RECORD;
begin
//
Result := AllocMem(Sizeof(TSOME_RECO RD));
Result^.a := i;
result^.b := i*100;
result^.c := i*1000;
result^.MyProb := AllocMem(10);
result^.MyProb[0] := 'S';
result^.MyProb[1] := 'H';
result^.MyProb[2] := 'U';
result^.MyProb[3] := char(0);
end;
So, the answer is that you cannot get RTTI for records in Delphi so you cannot do what you want.
the only solution would be to write a wrapper class: but your code would have to be recompiled every time your record structure changes.
...Shu
procedure TForm1.Button2Click(Sender
Var
i: Integer;
MyPtr: PSOME_RECORD;
begin
For i := 1 to 5 do
begin
MyPtr := GetRecord(i);
RecAry[i] := TSOME_RECORD(MyPtr^);
RecAry[i].a := RecAry[i].a * 10;
Showmessage(String(RecAry[
RecAry[i].MyProb[0] := 'U';
RecAry[i].MyProb[1] := char(0);
Showmessage(String(RecAry[
end;
end;
function TForm1.GetRecord(i: integer): PSOME_RECORD;
begin
//
Result := AllocMem(Sizeof(TSOME_RECO
Result^.a := i;
result^.b := i*100;
result^.c := i*1000;
result^.MyProb := AllocMem(10);
result^.MyProb[0] := 'S';
result^.MyProb[1] := 'H';
result^.MyProb[2] := 'U';
result^.MyProb[3] := char(0);
end;
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Str1 := Str1 + ' ' + PMRArray1^[i].a;
should be
Str1 := Str1 + ' ' + PMRArray^[i].a;
should be
Str1 := Str1 + ' ' + PMRArray^[i].a;
unit EnumUnit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, TypInfo;
type
PSOME_RECORD = ^TSOME_RECORD;
TSOME_RECORD = record
a:integer;
b:integer;
c:integer;
end;
TForm1 = class(TForm)
Button2: TButton;
procedure Button2Click(Sender: TObject);
function GetRecord(i:integer) : PSOME_RECORD;
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
RecAry: Array [1 .. 10] of TSOME_RECORD;//I had missed this in the earlier post :-)
implementation
{$R *.dfm}
procedure TForm1.Button2Click(Sender
Var
i: Integer;
MyPtr: PSOME_RECORD;
begin
For i := 1 to 10 do
begin
MyPtr := GetRecord(i);
RecAry[i] := TSOME_RECORD(MyPtr^);
RecAry[i].a := RecAry[i].a * 10;
Showmessage(Format('ary: %d, Ptr: %d',[RecAry[i].a, MyPtr^.a]))
end;
end;
function TForm1.GetRecord(i: integer): PSOME_RECORD;
begin
//
Result := AllocMem(Sizeof(TSOME_RECO
Result^.a := i;
result^.b := i*100;
result^.c := i*1000;
end;
end.
Cheers!
...Shu