How to set a constant string (or AnsiString) in TVarRec?

I want to pass Args formatting arguments to the Format function. I found some examples of this, but I canโ€™t find out how to assign a string constant in the TVarRec element. The following code does not execute when compiling with the E2089 Invalid typecast .

 procedure TForm1.Button1Click(Sender: TObject); var Arguments: array of TVarRec; begin SetLength(Arguments, 2); Arguments[0].VInteger := 111; Arguments[1].VAnsiString := PAnsiString('Text'); // I want to set this member ShowMessage(Format('Decimal: %d, String: %s', Arguments)); end; 

Can someone suggest me how to set a constant string (or AnsiString) for a TVarRec member? I am using Delphi 2009.

thanks a lot

+4
source share
2 answers

This seems to work in XE:

 var Args: array[0..1] of TVarRec; S: AnsiString; U: UnicodeString; begin S := 'Hello'; U := 'world'; Args[0].VType := vtAnsiString; Args[0].VAnsiString := Pointer(S); Args[1].VType := vtUnicodeString; Args[1].VUnicodeString := Pointer(U); Writeln(Format('%s, %s!', Args)); end; 
+8
source

Just my two cents. Tondrey's answer is correct, but I just wanted to emphasize some points. And comments are not a good place for this.

Remember that AnsiString reference must be used at all times.

For example, if you write a function that defines an array from TVarRec , you must make sure that you make a temporary copy of AnsiString created inside the function, a variable that remains until TVarRec uses the array. Otherwise, you may have some random access violation (not every time, but only when MM reassigns AnsiString memory).

For example, the following code is invalid :

 type TVarRec2 = array[0..1] of TVarRec; procedure SetVarRec(a,b: integer; var Result: TVarRec2); begin Result[0].VType := vtAnsiString; Result[0].VString := pointer(AnsiString(IntToStr(a))); Result[1].VType := vtUnicodeString; Result[1].VString := pointer(UnicodeString(IntToStr(b))); end; 

Since the temporary variables AnsiString and UnicodeString will be freed at the end of the procedure, and Results[].VString will still point to the freed memory ...

Using a class or record with some temporary private string can do the trick:

 type TMyVar2 = record private tmpA: AnsiString; tmpB: UnicodeString; public VarRec: TVarRec2; procedure SetVarRec(a,b: integer); end; procedure TMyVar2.SetVarRec(a,b: integer); begin VarRec[0].VType := vtAnsiString; tmpA := AnsiString(IntToStr(a)); VarRec[0].VString := pointer(tmpA); VarRec[1].VType := vtUnicodeString; tmpB := UnicodeString(IntToStr(b)); VarRec[1].VString := pointer(tmpB); end; 

Of course, you may have an existing class in your program. In this case, you are better off using the method and some private temporary strings. In order for the method to be multi-threaded (e.g. repeat), you must provide temporary strings as parameters ...

I use this trick to have a valid dynamic TVarData array containing some AnsiString content in the class. In fact, TVarData and TVarRec use such a pointer without a string reference, which can be misleading.

Keep in mind that problems with pointer(S) related statements can be difficult to track.

+3
source

All Articles