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-boun...@delphi.org.nz [mailto:delphi-boun...@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.

 

_______________________________________________
NZ Borland Developers Group - Delphi mailing list
Post: delphi@delphi.org.nz
Admin: http://delphi.org.nz/mailman/listinfo/delphi
Unsubscribe: send an email to delphi-requ...@delphi.org.nz with Subject: 
unsubscribe

Reply via email to