• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1351
  • Last Modified:

Problem converting to Delphi 2009 from Delphi 2006

I am converting large applications from Turbo Delphi 2006 to Delphi 2009 (Unicode full support)
Currently, I am blocked on the function listed below (see code)
It runs fine with TD2006 but not with Delphi 2009
I first commented the line OemToAnsi (will solve that later on)
So it compiles
But when running it, I get an access violation in kernel32.dll on the CreateProcess call
No idea why till now
Can somebody help with this ?
Thanks !
function RunDOSInSL(Command:string;SL:TStringList;Dir:string):boolean;
const
   CUANTOBUFFER = 2000;
var
  Seguridades         : TSecurityAttributes;
  PaLeer,PaEscribir   : THandle;
  start               : TStartUpInfo;
  ProcessInfo         : TProcessInformation;
  Buffer              : Pchar;
  BytesRead           : DWord;
  CuandoSale          : DWord;
  tb                  : PDWord;
  UseDir:string;
  BigString:string;
begin
  SL.Clear;
  BigString := '';
  Result := False;
  with Seguridades do
  begin
    nlength              := SizeOf(TSecurityAttributes);
    binherithandle       := true;
    lpsecuritydescriptor := nil;
  end;
  if CreatePipe (PaLeer, PaEscribir, @Seguridades, 0)
   then begin
    Buffer  := AllocMem(CUANTOBUFFER + 1);
    FillChar(Start,Sizeof(Start),#0);
    start.cb          := SizeOf(start);
    start.hStdOutput  := PaEscribir;
    start.hStdInput   := PaLeer;
    start.dwFlags     := STARTF_USESTDHANDLES +
                         STARTF_USESHOWWINDOW;
    start.wShowWindow := SW_HIDE;
    if CreateProcess(nil,PChar(Command),@Seguridades,@Seguridades,true,
                     NORMAL_PRIORITY_CLASS,nil,PChar(UseDir),start,ProcessInfo)
    then begin
      Result := True;
      new(tb);
      repeat
        CuandoSale := WaitForSingleObject( ProcessInfo.hProcess,100);
        repeat
          BytesRead := 0;
          PeekNamedPipe(PaLeer,nil,0,nil,tb,nil);
          if (tb ^= 0) then Break;
           ReadFile(PaLeer,Buffer[0],CUANTOBUFFER,BytesRead,nil);
          Buffer[BytesRead]:= #0;
          OemToAnsi(Buffer,Buffer);
          BigString := BigString + String(Buffer);
        until (BytesRead < CUANTOBUFFER);
        Application.ProcessMessages;
      until (CuandoSale <> WAIT_TIMEOUT);
      dispose(tb);
    end                                          // CreateProcess
    else raiseLastOSError;
    FreeMem(Buffer);
    CloseHandle(ProcessInfo.hProcess);
    CloseHandle(ProcessInfo.hThread);
    CloseHandle(PaLeer);
    CloseHandle(PaEscribir);
    SL.Text := BigString;
  end                                            // CreatePipe
  else raiseLastOSError;
end;

Open in new window

0
LeTay
Asked:
LeTay
  • 9
  • 6
1 Solution
 
HypoCommented:
You should set the first parameter in CreateProcess to the path of the exe-file... I know that it is also passed in the Command parameter, and the help says that you can have the first parameter set to nil if the second parameter contains that name, but I've had the same problem as you have, and it was solved by setting the first Parameter to the exe-file path. If I remember correct, then this problem only exists for CreateProcessW and I never saw it with CreateProcessA, which would explain why you din't get it in Delphi2006.

regards
Hypo
0
 
LeTayAuthor Commented:
Excellent Hypo !
It works
I will give you the point
But I have an additional question concerning the resulting buffer coming back from the execution
Do I post another question or is it okay to post it here
In fact, the result of the function is to return the "stdout" of the executable (console application) into a TStringList (via its text property)
Running now a few sample, I get ... unreadable results
I suppose there is some conversion to do on the Buffer variable or before
I tried unicodestring() and things like that but result is still so strange...
0
 
HypoCommented:
I think the first problem was that your BUFFER variable is PChar (which is a PWideChar in delphi2009) whilst the data read from the pipe is in Ansi format. So first, change OemToAnsi to OemToChar, since OemToAnsi is obsolete and has been replaced by OemToChar... second, create a second targetBuffer, that is a PWideChar (which is PChar in D2009) to which you convert the data in OemToChar. This cfunction would then convert the Ansi data from the pipe into unicode data, that you can then accaumulate in the BigString variable.

The new lines would then be:
var
...
    Buffer : PAnsiChar;
    targetBuffer : PChar;
...
  Buffer[BytesRead] := #0;
  OemToChar(Buffer, targetBuffer);
  BigString := BigString + targetBuffer;
...

regards
Hypo
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LeTayAuthor Commented:
I will test this probably the 10th of June
I keep you informed
Thanks
0
 
LeTayAuthor Commented:
Hello Hypo
Sorry to have tested your solution so lately
It is "almost" perfect
There is still a little thing not working
I debugged to be sure : during the OemToChar conversion of Buffer to targetBuffer, all characters are correctly converted except the hexa 13 and 10 (CR-LF) that separates each line.
In debug mode these characters are show as little squares
How can I fix this and really have the 13 and 10 remaining like that
Thanks
0
 
HypoCommented:
Hi,
I think that the characters #13 and #10 will always be displayed as squares when you look at them in the debugger (as will other control characters as well)... have you tried adding the text to a multiline control? how are the characters represented then?

regards
Hypo
0
 
LeTayAuthor Commented:
Hypo
In debug mode,when I look at the content of Buffer, it shows something like #D#A for these characters
Once "move" to targetBuffer, they are badly converted, that's sure : I tried to locate in debug mode via the expression Pos(chr(13),targetBuffer) but this returns zero
Indeed, the statement to put targetBuffer into the TStringList SL is SL.Text := targetBuffer
0
 
LeTayAuthor Commented:
Hypo,
No final idea to fix this ?
Thanks
0
 
HypoCommented:
Hi,
I've created a small test application, and I've got the same result as you (#13#10 is not converted correctly). Do you know why the original code used the OemToAnsi function? because if you can skip that function then it might solve your problem...

I know i recommended you to change from OemToAnsi to OemToChar, but what if you skip that function compleatley, and just let Delphi convert the strings instead?

Like this:

var
...
  Buffer : PAnsiChar;
...
  if (tb ^= 0) then Break;
    ReadFile(PaLeer,Buffer[0],CUANTOBUFFER,BytesRead,nil);
  Buffer[BytesRead] := #0;
  BigString := BigString + String(Buffer);



does it work then?

/Hypo
0
 
LeTayAuthor Commented:
I will try next week
This is an application I developed at my customer site where I will go one week from now
0
 
LeTayAuthor Commented:
I still have a problem with that famous #13#10 that is badly "converted" whatever conversion function I apply ...
Can somebody help on that ?
0
 
LeTayAuthor Commented:
I posted again the question ,more precisly on this forum : "Get the result (stdout) of a console application in a string" and got the answer right away
0
 
HypoCommented:
So you've got an answer to your addional question now then?  
0
 
LeTayAuthor Commented:
Yes and the solution is so trivial !
0
 
HypoCommented:
Man... I thought I solved your original problem?

"Excellent Hypo !
It works
I will give you the point
But I have an additional question concerning the resulting buffer coming back from the execution
Do I post another question or is it okay to post it here"
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 9
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now