I have a list in a CDATA element. How do I get the elements from the CDATA and add this to TStringList?
If I get the CDATA string, it returns:
'string'#10#9#9#9'string'#10#9#9#9'string'#10#9#9#9'string'...
However the characters #10#9#9#9 are not strings; I cannot use use the StringChangeEx method to replace these characters.
Thanks
The string you got is a valid notation for a string containing non printable characters. But you don't need to worry that you lose any char when working with a string list or the StringChangeEx function. Let me convince you with this short script:
[Code]
const
PrintableString = 'string-string-string-string';
NonPrintableString = 'string'#10#9#9#9'string'#10#9#9#9'string'#10#9#9#9'string';
procedure InitializeWizard;
var
S: string;
StringList: TstringList;
begin
StringList := TstringList.Create;
try
StringList.Add(NonPrintableString);
S := StringList[0];
if S = NonPrintableString then
MsgBox('String list didn''t lose non printable chars!', mbInformation, MB_OK);
StringChangeEx(S, #10#9#9#9, '-', True);
if S = PrintableString then
MsgBox('String has been modified as expected!', mbInformation, MB_OK);
finally
StringList.Free;
end;
end;
However, I think your question has been raised just because you want to present these data to the user, and that might be sometimes difficult with non printable chars. One example for all. If you'll have a string which contains a null terminator in the middle and you will want to show such string to the user, e.g. in a message box, you'll get displayed only the part of that string which is before that terminator. But, it's not something you can affect. That's just how the Windows API function call which is behind treats the string:
[Code]
procedure InitializeWizard;
var
S: string;
begin
S := 'Hello'#0' world!';
MsgBox(S, mbInformation, MB_OK);
end;
As you can see, for the above case would be necessary to replace the null terminator char with some printable char, e.g. space.
Related
I need Inno Setup to load a wide string from a function in a custom DLL. I have no problem loading Ansi strings – this, for example, works fine:
int __stdcall GetStringA(char *lpText)
{
StringCchCopyA(lpText, 30, "New Ansi value");
return strlen(lpText);
}
Pascal Script
function GetStringA(lpText: AnsiString): Integer;
external 'GetStringA#files:MyDll.dll';
function LoadStringA(): AnsiString;
var
Str: AnsiString;
Length: Integer;
begin
Str := 'Initial Ansi value';
SetLength(Str, 30);
Length := GetStringA(Str);
SetLength(Str, Length);
Result := Str; // Str == 'New Ansi value'
end;
Doing the same thing with wide strings fails, however:
int __stdcall GetStringW(wchar_t *lpText)
{
StringCchCopyW(lpText, 30, L"New Wide value");
return wcslen(lpText);
}
Pascal Script
function GetStringW(lpText: WideString): Integer;
external 'GetStringW#files:MyDll.dll';
function LoadStringW(): WideString;
var
Str: WideString;
Length: Integer;
begin
Str := 'Initial Wide value';
SetLength(Str, 30);
Length := GetStringW(Str); // ** DOES NOT ALTER 'Str' **
SetLength(Str, Length);
Result := Str; // Str == 'Initial Wide v' (old string, new length)
end;
Sending a WideString to the DLL works fine. Changing the buffer contents in the DLL also works fine…but somehow that does not percolate back to my Pascal Script variable.
I suspect that some sort of marshaling goes on under the hood, so that the DLL actually manipulates a copy of my variable. Any insights or workarounds appreciated!
I'm using Inno Setup 6.2.0.
I made it work by replacing WideString with String:
function GetStringW(lpText: String): Integer;
external 'GetStringW#files:MyDll.dll';
function LoadStringW(): WideString;
var
Str: String;
Length: Integer;
begin
Str := 'Initial Wide value';
SetLength(Str, 30);
Length := GetStringW(Str); // ** ALTERS 'Str' **
SetLength(Str, Length);
Result := Str; // Str == 'New Wide value'
end;
I'd have thought WideString and String were equivalent, but apparently not quite. It is necessary to change both the function prototype and the Str declaration. It is not necessary to change the LoadStringW return type, though you may – and the returned value can in either case be assigned to a variable of type WideString or String without problem.
So: Problem solved. I'm still curious about the underlying behavior, though.
I have a code which has a variable of Single datatype , but i want to display is in a message box. For example
VAR data:Single;
data:=0;
data:=5633.67+1290.965;
Msgbox('The sum of Fractional number is-:'+IntTostr(data),mbinformation,MB_OK);
There are at least two options I can think of right now. The first one is FloatToStr function, which is undocumented, or the official way of using Format function, which gives you much better flexibility in specifying format that you want. Here is an example of FloatToStr function:
var
S: string;
Value: Single;
begin
Value := 1.2345;
S := FloatToStr(Value);
MsgBox('Value is: ' + S, mbInformation, MB_OK);
end;
And here is an example that uses Format function. There is shown how to display a floating value in the General format and how to show the same value with 2 decimal places by using Fixed format. For more information about formats refer to the Delphi help for the Format function:
var
S: string;
Value: Single;
begin
Value := 1.2345;
S := Format('Value is: %g', [Value]);
MsgBox(S, mbInformation, MB_OK);
S := Format('Value is: %.2f', [Value]);
MsgBox(S, mbInformation, MB_OK);
end;
I have a Delphi 5 legacy application and there's a part in which a "string" value is been assigned to an "OleVariant" variable. Something like this:
var
X: OleVariant;
S: string;
Begin
S:= ‘This string should contain 200 characters as per design’;
X:= S;
End;
If the length of “S” is greater than 128, then the value of “X” gets truncated and it only holds a maximum of 128 characters.
Is there a way to overcome this?
I believe there is a way, because if I create my own demo application from scratch (in the same PC, with the same Delphi 5), it allows me to pass longer string values and no truncating is done.
Maybe it is something about the project settings or compiler directives. I have played around with this idea, but I have no workaround yet.
Any help is appreciated. Thanks.
Demo:
procedure TForm1.Button1Click(Sender: TObject);
var
X: OleVariant;
S: string;
begin
//in the Edit I pass a string of 240 chars, let's say;
S:= Edit1.Text;
X:= S;
ShowMessage(IntToStr(Length(X)) + ' : ' + IntToStr(Length(S)));
//this showmessage shows "128 : 240"
end;
Try this OleVariantToString and StringToOleVariant functions at http://www.foxbase.ru/delphi/vzaimnye-preobrazovaniya-olevariant-i-string.htm
They work perfectly for me.
uses Classes, Variants;
function OleVariantToString(const Value: OleVariant): string;
var ss: TStringStream;
Size: integer;
Data: PByteArray;
begin
Result:='';
if Length(Value) = 0 then Exit;
ss:=TStringStream.Create;
try
Size := VarArrayHighBound (Value, 1) - VarArrayLowBound(Value, 1) + 1;
Data := VarArrayLock(Value);
try
ss.Position := 0;
ss.WriteBuffer(Data^, Size);
ss.Position := 0;
Result:=ss.DataString;
finally
VarArrayUnlock(Value);
end;
finally
ss.Free;
end;
end;
function StringToOleVariant(const Value: string): OleVariant;
var Data: PByteArray;
ss: TStringStream;
begin
Result:=null;
if Value='' then Exit;
ss:=TStringStream.Create(Value);
try
Result := VarArrayCreate ([0, ss.Size - 1], varByte);
Data := VarArrayLock(Result);
try
ss.Position := 0;
ss.ReadBuffer(Data^, ss.Size);
finally
VarArrayUnlock(Result);
end;
finally
ss.Free;
end;
end;
One explanation is that OleVariant holds the entire string but that you are looking at the debugger tooltip. In older Delphi versions the debugger tooltip truncates at 128 characters for strings held in a variant. Note that the debugger tooltip for a plain string does not truncate at this length. Try showing the variant in a dialog box and you will see that the entire string is present.
I checked this out on Delphi 6 and there was no truncation with your code (other than the debugger tooltip). Andreas did likewise on Delphi 4 and Rodrigo did so with Delphi 5. I cannot imagine that it could really be the case that strings in a Delphi 5 OleVariant are truncated at 128 characters.
If you really are seeing what you are report then I can think of the following explanations:
Your code is erroneously truncating the string, but you have not yet found the code that does this. Only you can debug that.
You have a local bug private to your Delphi installation. Are you by any chance compiling your own RTL?
I made this work. Summary: instead of filling an “OleVariant” with a “string”; I filled a “Variant” and then typecasted that “Variant” to “OleVariant”. Take a look at the code below so that you can get the idea.
procedure TForm1.Button1Click(Sender: TObject);
var
//X: OleVariant;
X: Variant;
S: string;
begin
//Let's say in the Edit1 I pass a string of 240 chars,
S:= Edit1.Text;
X:= S;
//ShowMessage(IntToStr(Length(X)) + ' : ' + IntToStr(Length(S)));
ShowMessage(IntToStr(Length(OleVariant(X))) + ' : ' + IntToStr(Length(S)));
//This ShowMessage shows "128 : 240"
end;
Honestly, I don’t know for sure why this makes a difference, but it does. It works ok now.
Thanks a lot for your help folks!
I have GetVersion function in [Code] that returns a string like this "1004", "1003", etc.
I created this function to check the registry value for lowest version numbers and uninstall them.
Here is a snippet of the code it is giving error point to StrtoInt conversion line stating
Comma (,) expected
Here is the snippet:
function DoesOldVersionsExist(): Boolean;
var
AppVersion: integer;
mstr: string;
VersionInstalled: cardinal;
begin
AppVersion := StrToInt(GetVersion({#MyAppVersion}), 0);
...
after that line I'm simple comparing the values and return true or false. Much Appreciated.
This is what error message says:
Line 55
Column 40.
Comma (,) expected
Thanks Deanna but unfortunately that is the error message pointing to this :
AppVersion := StrToInt(GetVersion({#MyAppVersion}), 0);
^
Here is the GetVersion function:
function GetVersion(AppVersion: String): String;
var
Version: String;
CharIndex: integer;
c: char;
begin
for CharIndex := 1 to Length(AppVersion) do begin
c := AppVersion[CharIndex];
if (c <> '.') then
Version := Version + c;
end;
Result := Version;
end;
I think that you can't just have Inno Setup constants in code like this, you have to use ExpandConstant():
AppVersion := StrToInt(GetVersion(ExpandConstant('{#MyAppVersion}')), 0);
You have not given us enough information to give a definite answer, but I think that the situation is as follows.
You have defined some constant called MyAppVersion which you let the ISPP (the Inno Setup pre-processor) substitute. Now, you have not told us what type this variable is, and you have not told us what the signature of GetVersion is (in particular, what type of argument does it expect?). However, if these types are strings, you need to write
StrToInt(GetVersion('{#MyAppVersion}'), 0);
in order to obtain, say,
StrToInt(GetVersion('Some string, this is!'), 0);
instead of
StrToInt(GetVersion(Some string, this is!), 0);
which is malformed (indeed, to such an extent that it hurts my eyes to look at it).
I need to do something with a Unicode string of a tree of a TTreeView, so I want to load this string into a memory stream and then load the memory stream into the tree view. How can I do this?
You be tempted to use directly the TStringStream class intead of a TMemoryStream. But this TStringStream class will encode the UnicodeString into an AnsiString before storage, in the Unicode Delphi version...
So here are some functions to create a TMemoryStream instance with pure Unicode content, then retrieve back this text:
function StringToMemoryStream(const Text: string): TMemoryStream;
var Bytes: integer;
begin
if Text='' then
result := nil else
begin
result := TMemoryStream.Create;
Bytes := length(Text)*sizeof(Char);
result.Size := Bytes;
move(pointer(Text)^,result.Memory^,Bytes);
end;
end;
function MemoryStreamToString(MS: TMemoryStream): string;
begin
if MS=nil then
result := '' else
SetString(result,PChar(MS.Memory),MS.Size div sizeof(Char));
end;
Be sure that you Free the TMemoryStream when you won't need it any more.
By using sizeof(Char) and PChar, this code will also work with previous non-Unicode version of Delphi.