Well, setting aside the obfuscation of burying the real work of the routine as 
a side effect of code that exists merely to provide the scaffolding required to 
make that call, this code actually contains an error:

 

   setlength(temp, 100); //has to be big enough first

   setlength(temp, getEnvironmentVariable(PChar('USERNAME'), PChar(temp), 
length(temp)));

 

Since GetEnvironmentVariable() works with a plain null terminated buffer, the 
length of the buffer that you indicate in the call to it needs to reflect the 
expected presence of that terminator in the buffer.  But the null terminator on 
a String type variable is implicit, and not part of the payload and so not 
reflected in the length.

 

If the USERNAME were exactly 100 characters in length, your call to 
GetEnvironmentVariable() would fail, even though the buffer you are passing is 
actually the right size.

 

i.e.  you should actually call

 

   getEnvironmentVariable(PChar('USERNAME'), PChar(temp), length(temp) + 1)

 

This to my mind perfectly illustrates the problem: treating one type (a string) 
as if it were another in a situation where the differences are actually 
important.

 

Passing a String value to an external routine that simple READS from a null 
terminated buffer is much more straightforward and less error prone (imho – due 
to being reminded of what you are working with by the very nature of what you 
are working with) than trying to pass a pointer which is actually an offset 
into a complex String type to a function that expects to modify a plain null 
terminated buffer.

 

When reading from a string, the payload can be safely naively regarded as a 
null terminated buffer by a function that is unaware of the greater complexity 
of the type of value it is actually being passed.

 

But when writing to a null terminated buffer, there be dragons when that buffer 
isn’t just a null terminated buffer but actually the payload of a far more 
complex type.

 

 

If an external routine expected a pointer to an unsigned 32 bit value I doubt 
you would consider it sensible to contrive to pass a pointer to an signed 
16-bit variable, even if you always got the desired results (at least, up to 
now... ).  J

 

 

 

From: delphi-boun...@delphi.org.nz [mailto:delphi-boun...@delphi.org.nz] On 
Behalf Of John Bird
Sent: Wednesday, 29 June 2011 13:19
To: NZ Borland Developers Group - Delphi List
Subject: Re: [DUG] Variable in String

 

Jolyon I imagine you have an opinion on doing this your way rather than like 
this example below – I would be interested in hearing your reasoning.

 

A similar example – this is the sort of code I have been using....

 

setlength(temp, 100); //has to be big enough first

setlength(temp, getEnvironmentVariable(PChar('USERNAME'), PChar(temp), 
length(temp)));

 

 

John

 

 

From: Jolyon Smith <mailto:jsm...@deltics.co.nz>  

Sent: Monday, June 27, 2011 10:07 AM

To: 'NZ Borland Developers Group - Delphi List' <mailto:delphi@delphi.org.nz>  

Subject: Re: [DUG] Variable in String

 

Sorry Bob, I meant to include an example of your code tweaked to use “raw” a 
char array with the Windows API routine.  Here it is (this version displays 
results rather than storing in a variable, but you get the idea J ) :

 

var

  dir: array of Char;

  s: String;

begin

  s := ‘’;

 

  SetLength(dir, MAX_PATH + 1);

  if Succeeded(SHGetFolderPath(0, CSIDL_Program_Files, 0, 0, @dir[0])) then

    s := PChar(dir);

 

  ShowMessageFmt(s + ' (%d chars)', [Length(s)]);

 

  // Outcome:  s has both the right length *and* is null terminated correctly

end;

 

 

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.

 

SetLength(sDir, MAX_PATH);

ZeroMemory(@sDir[1], MAX_PATH);

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

FW_Path := sDir;

 

Bob

 

From: Jolyon Smith <mailto:jsm...@deltics.co.nz>  

Sent: Wednesday, June 22, 2011 3:49 PM

To: 'NZ Borland Developers Group - Delphi List' <mailto:delphi@delphi.org.nz>  

Subject: Re: [DUG] Variable in String

 

Don’t quote FW_Path element of the program path – you need to quote the entire 
path AND program file name when/if any part of the path or the filename itself 
does – or may – contain spaces:

 

e.g.   “path a\sub a\sub b\prog.exe”

 

not   “path a”\sub\prog.exe

 

 

So in your case, this should do the trick:

 

   FW_Path     := X;  

   DXF         := openDialog1.FileName;        

   ProgramName := ‘”’ + FW_Path + '\FWTools2.4.7\bin\ogr2ogr” "-f" "PostgreSQL" 
PG:"host=192........ user=postgres dbname=E5R password=........" "'+ DXF +'" 
-nln Import_Process';

   ShowMessage(ProgramName);

 

 

hth

 

From: delphi-boun...@delphi.org.nz [mailto:delphi-boun...@delphi.org.nz] On 
Behalf Of Bob Pawley
Sent: Thursday, 23 June 2011 10:30
To: DUG
Subject: [DUG] Variable in String

 

Hi

 

I’m having trouble with using a variable in a string path.

 

When I use the variable FW_Path := ‘C:\Program Files (x86)’ with two single 
quotes, the following works well and ShowMessage(ProgramName); displayed the 
full path ..

 

When I reference FW_Path to a variable X I get an error returned “Can Not 
run....” The variable  X is returned as C:\Program Files (x86) without quotes. 

 

I attempted Quote String and got the following ‘C:\Program Files (x86) with one 
single quote.

 

Both cases return the same error - and in both cases ShowMessage(ProgramName); 
displayed none of the path after C:\Program Files (x86).

 

Help would be appreciated.

 

Bob

 

   FW_Path := QuoteStr(X);  

  DXF  := openDialog1.FileName;        

  ProgramName :=FW_Path+'\FWTools2.4.7\bin\ogr2ogr "-f" "PostgreSQL" 
PG:"host=192........ user=postgres dbname=E5R password=........" "'+ DXF +'" 
-nln Import_Process';

       ShowMessage(ProgramName);

  _____  

_______________________________________________
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

  _____  

_______________________________________________
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

_______________________________________________
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