Function with PWideChar parameter taking only first char - string

I've just encountered a weird problem. I am trying to load a model to OpenGL and in the part where I load textures I use auxDIBImageLoadA(dibfile:PWideChar) function. Here is my code calling it
procedure CreateTexture(var textureArray: array of UINT; strFileName: string; textureID: integer); // Vytvožení textury
var
pBitmap: PTAUX_RGBImageRec;
begin
if strFileName = '' then exit;
MessageBox(0,PWideChar(strFileName),nil,SW_SHOWNORMAL);
pBitmap := auxDIBImageLoadA(PWideChar(strFileName));
if pBitmap = nil then exit;
...
The MessageBox is just for control. This is what happens: I run the application, a box with "FACE.BMP" appears. Okay. But then I get an error saying "Failed to open DIB file F". When i set the stFileName to xFACE.BMP, I get an "Failed to open DIB file x". So for some reason it appears that the function is taking only the first char.
Am I missing something? I'm using glaux.dll which I downloaded like 5 times from different sources, so it should be bug-free (I hope, every OpenGL site referred to it).

That's odd, functions ending in "A" generally take PAnsiChar pointers, and those ending in "W" take PWideChar pointers. Is there a auxDIBImageLoadW call also? If there is use that one, or try with PAnsiChar, since the PWideChar you pass (two bytes per position) would look like a string one character long if it is evaluated as a 1-byte string.

You need to convert your Unicode string to ANSI. Do it like this
pBitmap := auxDIBImageLoadA (PAnsiChar(AnsiString(strFileName)))
You would be better off calling the Unicode version though
pBitmap := auxDIBImageLoadW (PWideChar(strFileName))

Related

Combine String and Character in Delphi

function leftstr(s:string; n:Integer):string;
var
i:integer;
t:string;
begin
//init var t
t := '';
for i := 0 to n do
begin
//main loop
t := t + s[i];
end;
//return results
Result:=t;
end;
So when I run this function and use ShowMessage to get the value of t in each increment of i, t is always blank. Can someone tell me the problem? This is compiled using Delphi XE6
The problem is that strings use 1-based indexing and you are accessing out of bounds. Your loop should be:
for i := 1 to n do
Probably what happens is that s[0] refers to some part of the string's meta data (length or reference count, I cannot remember which) that happens to contain a zero byte. This is then interpreted as a null terminator when the string is passed to ShowMessage.
If you had enabled the range checking feature in your compiler options, the compiler would have inserted code that would have found the error for you. This range checking feature is an astonishingly neglected and overlooked feature.
Of course, the function is a little pointless, as well as rather inefficient. You can use LeftStr from the StrUtils unit. Or plain old Copy from the System unit.

how can delphi 'string' literals be more than 255?

im working on delphi 7 and i was working on a strings, i came across this
For a string of default length, that is, declared simply as string, max size is always 255. A ShortString is never allowed to grow to more than 255 characters.
on delphi strings
once i had to do something like this in my delphi code (that was for a really big query)
var
sMyStringOF256characters : string;
ilength : integer;
begin
sMyStringOF256characters:='ThisStringisofLength256,ThisStringisofLength256,.....'
//length of sMyStringOF256characters is 256
end;
i get this error
[Error] u_home.pas(38): String literals may have at most 255 elements.
but when i try this
var
iCounter : integer;
myExtremlyLongString : string;
begin
myExtremlyLongString:='';
Label1.Caption:='';
for iCounter:=0 to 2500 do
begin
myExtremlyLongString:=myExtremlyLongString+inttostr(iCounter);
Label1.Caption:=myExtremlyLongString;
end;
Label2.Caption:=inttostr(length(myExtremlyLongString));
end;
and the result is
As you can see the length of myExtremlyLongString is 8894 characters.
why did not delphi give any error saying the length is beyond 255 for myExtremlyLongString?
EDIT
i used
SetLength(sMyStringOF256characters,300);
but it doesnt work.
why did not delphi give any error saying the length is beyond 255 for
myExtremlyLongString?
You have your answer a bit down in the text in section Long String (AnsiString).
In current versions of Delphi, the string type is simply an alias for
AnsiString,
So string is not limited to 255 characters but a string literal is. That means that you can build a string that is longer than 255 characters but you can not have a string value in code that is longer than 255 characters. You need to split them if you want that.
sMyString:='ThisStringisofLength255'+'ThisStringisofLength255';
Split it up into:
sMyStringOF256characters :=
'ThisStringis' +
'ofLength256' +
'And ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'CharactersCharactersCharactersCharactersCharactersCharactersCharactersCharacters';
Back in old DOS/Turbo Pascal days, "strings" were indeed limited to 255 characters. In large part because the 1st byte contained the string length, and a byte can only have a value between 0 and 255.
That is no longer an issue in contemporary versions of Delphi.
"ShortString" is the type for the old DOS/Pascal string type.
"LongString" has been the default string type for a long time (including the Borland Delphi 2006 I currently use for most production work). LongStrings (aka "AnsiStrings") hold 8-bit characters, and are limited only by available memory.
Recent versions of Delphi (Delphi 2009 and higher, including the new Delphi XE2) all now default to multi-byte Unicode "WideString" strings. WideStrings, like AnsiStrings, are also effectively "unlimited" in maximum length.
This article explains in more detail:
http://delphi.about.com/od/beginners/l/aa071800a.htm
The difference is that in your first code example you are putting the string as part of your code - literal string. That has a limitation on how many characters it will allow.
In your second code example you are generating it dynamically and not putting it as one big literal string.
String type in Delphi (unlike shortstring that can only be up to 255) can be as big as your memory.
You could try using the StringBuilder class:
procedure TestStringBuilder;
var
I: Integer;
StringBuilder: TStringBuilder;
begin
StringBuilder := TStringBuilder.Create;
try
for I := 1 to 10 do
begin
StringBuilder.Append('a string ');
StringBuilder.Append(66); //add an integer
StringBuilder.Append(sLineBreak); //add new line
end;
OutputWriteLine('Final string builder length: ' + IntToStr(StringBuilder.Length));
finally
StringBuilder.Free;
end;
end;
If you need realy long string in Delphi, you can load it from other resources like a txt files or just plain text with any extension. Im using it and it works. You can create "like a" array tables using plain text lines numbers. In delphi code, you can do as #arjen van der Spek and others says only.
For me, files with text as var's formated -
sometext:string=
'txt...'+
'txt...'+
'txt...';
are bad for future editing.
pros: you can use any long text.
cons: text code is open, anybody can read it opening file in notepad etc.

How can I convert string encoded with Windows Codepage 1251 to a Unicode string

The cyrllic string my app receives uses(I believe) the table below:
said I believe, because all the chars I tested fit this table.
Question: How do I convert such thing to a string, which is unicode by default in my delphi?
Or better yet: Is there a ready-to-use converter in delphi or should I write one?
If you are using Delphi 2009 or later, this is done automatically:
type
CyrillicString = type AnsiString(1251);
procedure TForm1.FormCreate(Sender: TObject);
var
UnicodeStr: string;
CyrillicStr: CyrillicString;
begin
UnicodeStr := 'This is a test.'; // Unicode string
CyrillicStr := UnicodeStr; // ...converted to 1251
CyrillicStr := 'This is a test.'; // Cryllic string
UnicodeStr := CyrillicStr; // ...converted to Unicode
end;
First of all I recommend you read Marco Cantù's whitepaper on Unicode in Delphi. I am also assuming from your question (and previous questions), that you are using a Unicode version of Delphi, i.e. D2009 or later.
You can first of all define an AnsiString with codepage 1251 to match your input data.
type
CyrillicString = type Ansistring(1251);
This is an important step. It says that any data contained inside a variable of this type is to be interpreted as having been encoded using the 1251 codepage. This allows Delphi to perform correct conversions to other string types, as we will see later.
Next copy your input data into a string of this variable.
function GetCyrillicString(const Input: array of Byte): CyrillicString;
begin
SetLength(Result, Length(Input));
if Length(Result)>0 then
Move(Input[0], Result[1], Length(Input));
end;
Of course, there may be other, more convenient ways to get the data in. Perhaps it comes from a stream. Whatever the case, make sure you do it with something equivalent to a memory copy so that you don't invoke code page conversions and thus lose the 1251 encoding.
Finally you can simply assign a CyrillicString to a plain Unicode string variable and the Delphi runtime performs the necessary conversion automatically.
function ConvertCyrillicToUnicode(const Input: array of Byte): string;
begin
Result := GetCyrillicString(Input);
end;
The runtime is able to perform this conversion because you specified the codepage when defining CyrillicString and because string maps to UnicodeString which is encoded with UTF-16.
Windows API MultiByteToWideChar() and WideCharToMultiByte() can be used to convert to and from any supported code page in Windows. Of course if you use Delphi >= 2009 it is easier to use the native unicode support.

delphi string to "const buffer"

I have a dll which procedure accepts: "const buffer" parameter.
There is also an example of passing value to this parameter:
var
str: array [0..200 - 1] of Char;
LTextSend: string;
begin
LTextSend := 'Text';
StrLCopy(PChar(#str[0]), PChar(LTextSend), High(str));
Dll_procedure(str, Length(LTextSend));
end;
can this parameter be only passed through this declaration: str: array [0..200 - 1] of Char;
Isn't there an easier way to pass string (of different length) to this dll parameter?
Thanks
You can call the procedure like this:
DLL_procedure(str[1], Length(str));
This works because Delphi untyped parameters are sent the same way as var parameters, they're sent by reference. The compiler will send a pointer to str[1], the first char in the string, but that's actually a pointer to the whole string. As usual, make sure the string actually contains an first character (ie: it's not empty).
Your number 1 problem depends entirely on the DLL. The "signature" allows any length of data to be sent, but that doesn't mean the DLL is prepared for anything. Maybe it can only handle 200 bytes at a time.
I don't know why you're making a copy to a temporary buffer.
It does only make sense if the Dll_procedure will modify the buffer. But I doubt it will.
So you could simply write:
Dll_procedure(Pointer(LTextSend)^, Length(LTextSend));
Or a variant making the string unique before the call:
Dll_procedure(LTextSend[1], Length(LTextSend));

Delphi 2010: how do I convert a UTF8-encoded PAnsiChar to a UnicodeString?

The situation: I’ve an external DLL that uses UTF-8 as its internal string format. The interface functions all use PAnsiChar to pass strings along.
The rest of my application uses Delphi’s native string type; since I’m working with Delphi 2010, that will map to a UnicodeString.
How can I reliably cast those PAnsiChar arguments (which are pointing to UTF-8 encoded strings) to a UnicodeString?
I had this function, which I thought worked fine:
function PUTF8CharToString(Text: PAnsiChar): string;
var
UText: UTF8String;
begin
UText := UTF8String(Text);
Result := string(UText);
end;
...but now I’ve run into a case where the result string is corrupted; when I save the PAnsiChar to file, it’s fine; but when I save the resulting string after conversion using the above function, it’s corrupted.
Or should this work correctly, and is this indicative of some other memory (de)allocation problem?
Edit: I finally managed to get rid of the memory corruption by assigning the converted string to a local variable string, instead of directly passing it to another function.
From System:
function UTF8ToUnicodeString(const S: PAnsiChar): UnicodeString; overload;
UnicodeStr := System.Utf8ToUnicodeString(Text);
Try using SetString() instead of casting:
function PUTF8CharToString(Text: PAnsiChar): string;
var
UText: UTF8String;
begin
SetString(UText, Text, StrLen(Text));
Result := UText;
end;

Resources