[DUG] Variable in String

Jolyon Smith jsmith at deltics.co.nz
Mon Jun 27 09:46:01 NZST 2011


Aha!  J  Quite possibly...

 

SetLength(sDir, MAX_PATH);

ZeroMemory(@sDir[1], MAX_PATH);

if Succeeded(SHGetFolderPath(0, CSIDL_Program_Files, 0, 0, PAnsiChar(sDir))) then

FW_Path := sDir;

 

Yes, you are setting the string length to MAX_PATH, so any string data with a length of LESS than MAX_PATH will contain null chars after the actual string value as part of the string value data itself!

 

If you inspect the value of sDir it will appear to be correct, because the code displaying the string contents will almost certainly be treating the first NULL it finds as the string terminator, irrespective of the string length you have set, but when you try to combine that string with other strings using the Delphi string handling functions, the explicit LENGTH of the string will be used, not the null terminator:

 

So, building on my previous example:

 

 s := ‘hat’#0#0;

 s := s + ‘ and gloves’;

 

// At this point “s” contains:   ‘hat’#0#0’ and gloves”

 

 

To fix your code you have at least two options:

 

1)      After getting the contents of sDir, call SetLength() again and set the actual length of the string

2)      Use a char array in the windows API call and exploit the RTL support for auto conversion of PChars to and from strings

 

I myself would go with the latter.  The Windows API is designed to work with “raw” pointers to char arrays – co-ercing functions that *modify* buffer contents to accept Delphi strings makes me nervous (functions that just accept string data without modifying it are a different matter, and I have no trouble simply casting a string to a PChar in those circumstances).  J

 

 

Also, I am guessing from your use of PANSIChar that you are using Delphi 2007 or earlier – this code will fail if/when you move to Delphi 2009 as the SHGetFolderPath() routine in those later versions will expect/require a PWIDEChar param.

 

The easiest way to deal with this is to simply use PChar instead – in D2007< PChar = PANSIChar and in D2009+ PChar = PWideChar.  But, to further protect yourself, the ZeroMemory() call should use MAX_PATH * SizeOf(Char) to indicate the number of zero bytes to write (Char can change size depending on Delphi versions).

 

Having said that, I suspect (but am not 100% sure) that the ZeroMemory() call is redundant in this case.

 

 

Alternatively you could explicitly use the ANSI version of SHGetFolderPath (SHGetFolderPathA) with a PANSIChar, but this is likely to get even messier with the use of String in the Delphi Unicode compatibility arena, since a “String” cannot be typecast as a PANSIChar in D2009+.

 

 

I also think you may need to +1 on MAX_PATH to allow for the null terminator that the Windows API is most likely to include in any return value.

 

 

Whew – that’s quite a start to a Monday morning.  J

 

hth

 

Jolyon

 

 

 

 

From: delphi-bounces at delphi.org.nz [mailto:delphi-bounces at delphi.org.nz] On Behalf Of Bob Pawley
Sent: Monday, 27 June 2011 08:58
To: 'NZ Borland Developers Group - Delphi List'
Subject: Re: [DUG] Variable in String

 

Hi Jolyon

 

I was wondering if my problem is a conflict between how I derive the value of the variable (PAnsiChar).

 

Here is the code for doing that.

 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://listserver.123.net.nz/pipermail/delphi/attachments/20110627/5096b88a/attachment-0001.html 


More information about the Delphi mailing list