I have a record type defined. There are several fields, and I want to assign to them from a custom class: (D2010, win7) <code> type tmyrec record field1: pchar; ... end; type tmyclass = class ffield1: string; public property field1: string read ffield1 write ffield1; procedure assignto(var aMyRec: tmyrec); procedure freeMem(var aMyRec: tmyrec); end; ... procedure tmyclass.assignto(var aMyRec: tmyrec); begin if not assigned(aMyRec.field1) then getmem(aMyRec.field1,4); aMyRec.field1 := pchar(self.field1); end; < access violation here. procedure tmyclass.freeMem(var aMyRec: tmyrec); begin system.freemem(aMyRec.field1); end; .... Calling program does this: procedure myproc(oMyClass: TMyClass); var myRec: tMyRec; begin oMyClass.assignto(myRec); < access violation here. end; </code> The problem is, I get a access violation when the assignto method exits. oMyClass has been created and populated. Also, the first time I ran the program (in the IDE), the statement assigned(aMyRec.field1) evaluated to false. In subsequent runs, it evaluates to True. I infer that somehow myRec is never going out of scope.
![]() |
0 |
![]() |
jeremy grand wrote: > I have a record type defined. There are several fields, and I want to > assign to them from a custom class: (D2010, win7) > > > > procedure tmyclass.assignto(var aMyRec: tmyrec); > begin > if not assigned(aMyRec.field1) then getmem(aMyRec.field1,4); > aMyRec.field1 := pchar(self.field1); > end; < access violation here. > I don't see a reason to allocate memory by yourself why not leave Delphi to do that? You are not allocating enough space except if your string is always a single character. You should write: {code}GetMem(aMyRec.field1, (1+length(self.field1)) * SizeOf(Char)); {code} I tried with Delphi 2007 even when I allocated less memory there was no AV error.
![]() |
0 |
![]() |
In your code: {code} procedure myproc(oMyClass: TMyClass); var myRec: tMyRec; {code} The myRec is not initialized. So the myRec.field1 PChar is not necessary nil. So it's not allocated in AssignTo So there is an access violation. Just initialize the myRec content: {code} procedure myproc(oMyClass: TMyClass); var myRec: tMyRec; begin fillchar(myRec,sizeof(myRec),0); oMyClass.assignto(myRec); end; {code}
![]() |
0 |
![]() |
Lajos Juhasz wrote: > I don't see a reason to allocate memory by yourself why not leave > Delphi to do that? You are not allocating enough space except if your > string is always a single character. You should write: > {code}GetMem(aMyRec.field1, (1+length(self.field1)) * SizeOf(Char)); > {code} Lajos, thanks. I tried both approaches just now. Turns out that one of the pchar fields I was declaring was being assigned a string of length 255. There apparently is a limit on how long a pchar can be, but I don't see it in the literature. And I did do what Arnaud suggests -- initialize the record var. Doing that, the assigned(myrec.field1) function returns false. But I'm still confused about memory allocation. Are you saying that delphi will allocate the memory, and then free it again when the record goes out of scope? My overall goal is to use the record to pass parameters into a dll, and that's what got me started on explicit allocation of memory. One pchar field in the record is supposed to hold result text and will be populated by the dll. Surely that one needs to be allocated prior to calling the dll. Jeremy
![]() |
0 |
![]() |
jeremy grand wrote: > Lajos, thanks. I tried both approaches just now. Turns out that one > of the pchar fields I was declaring was being assigned a string of > length 255. There apparently is a limit on how long a pchar can be, > but I don't see it in the literature. Well, I was wrong. There is another issue corrupting my record in the dll. Haven't found it yet, but shortening my result string just kept the corruption from causing a fault. Pure coincidence.
![]() |
0 |
![]() |
"jeremy grand" <jeremy@ninprodata.com> schreef in bericht news:289401@forums.embarcadero.com... >I have a record type defined. There are several fields, and I want to > assign to them from a custom class: (D2010, win7) > > > <code> > type tmyrec record > field1: pchar; > .. > end; > > type tmyclass = class > ffield1: string; > public > property field1: string read ffield1 write ffield1; > procedure assignto(var aMyRec: tmyrec); > procedure freeMem(var aMyRec: tmyrec); > end; > > .. > > procedure tmyclass.assignto(var aMyRec: tmyrec); > begin > if not assigned(aMyRec.field1) then getmem(aMyRec.field1,4); > aMyRec.field1 := pchar(self.field1); > end; < access violation here. > > procedure tmyclass.freeMem(var aMyRec: tmyrec); > begin > system.freemem(aMyRec.field1); > end; > A Pchar is just a buffer (of char). When you want to copy data from your TmyClass.field1 (a string) to aMyRec.field1 (a Pchar), you need to create enough space in the buffer to hold the string. Your getmem call allocates only 4 bytes to the buffer. Shouldn't that be length(ffield1)+1 instead? The +1 being for a terminating zero byte. Tom
![]() |
0 |
![]() |
Tom deNeef wrote: > When you want to copy data from your TmyClass.field1 (a string) to > aMyRec.field1 (a Pchar), you need to create enough space in the > buffer to hold the string. Your getmem call allocates only 4 bytes to > the buffer. Shouldn't that be length(ffield1)+1 instead? The +1 being > for a terminating zero byte. Tom Yes, I'm doing that now. But also, I stumbled onto strPCopy in my searching, and that fixes the AV problem. I was assigning PChar(mystring), and that, if I understand correctly, doesn't copy the string, it just assigns a pointer. So progress is being made. I'm now confronted with what EurekaLog calls a Memory Overrun leak. But that is way ahead of where I was. This has something to do with copying a string that is too long for the allocated memory I think. So, we're taking ground from the enemy but paying for it in lots of frustration. Jeremy.
![]() |
0 |
![]() |
Tom deNeef wrote: > A Pchar is just a buffer (of char). When you want to copy data from > your TmyClass.field1 (a string) to aMyRec.field1 (a Pchar), you need > to create enough space in the buffer to hold the string. Your getmem > call allocates only 4 bytes to the buffer. Shouldn't that be > length(ffield1)+1 instead? The +1 being for a terminating zero byte. > Tom Tom It should be (length(ffield1)+1)*SizeOf(char)) as I wrote in my previous post. Delphi 2009 SizeOf(char)=2 as it's unicode. I was a bit fast on testing and followed your wrong design. Of course you have to copy the string as Delphi would just redirect the pointer and have the errors you got. My next guess would be: {code} procedure tmyclass.assignto(var aMyRec: tmyrec); var llen: integer; begin llen:=length(self.field1) if Assigned(aMyrec.field1) then freeMem(aMyRec.field1); GetMem(aMyRec.Field1,(llen+1)*SizeOf(char)); StrLCopy(aMyRec.Field1, PChar(lTempStr), llen); end; {code} This code will free the previous value (we don't need a memory leak). Allocate the memory for the new string. and finally to copy the string. > One pchar field in the record is supposed to hold result text and > will be populated by the dll. If the dll needs to change the PChar you should also send the size of the PCHAR or allocate buffer large enough. Can you show the entire record and some code in the DLL how you populate the PCHAR?
![]() |
0 |
![]() |
Lajos Juhasz wrote: > It should be (length(ffield1)+1)*SizeOf(char)) That disposes of the last error message -- I was thinking the 0 position (the length position) would be 1 byte long [length*size+1], but apparently it wants to be sizeOf(char) wide [(length+1)*size]. Friends, thank you for your help on this. I believe I can now move on to producing actual functionality (g). Jeremy
![]() |
0 |
![]() |
jeremy grand wrote: > Lajos Juhasz wrote: > > > It should be (length(ffield1)+1)*SizeOf(char)) > > That disposes of the last error message -- I was thinking the 0 > position (the length position) would be 1 byte long [length*size+1], > but apparently it wants to be sizeOf(char) wide [(length+1)*size]. > > Friends, thank you for your help on this. I believe I can now move on > to producing actual functionality (g). > > Jeremy I'm glad we solved this problem. Pchar is a null terminated string. In this case it's terminated with a Unicode #0 that is with #0#0. Lajos PS. I would like to thank to Rudy for writing his article on strings and pchar.
![]() |
0 |
![]() |