Solved

Problem converting to Delphi 2009 from Delphi 2006

Posted on 2009-05-20
15
1,318 Views
Last Modified: 2012-05-07
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
Comment
Question by:LeTay
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 6
15 Comments
 
LVL 12

Expert Comment

by:Hypo
ID: 24431350
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
 

Author Comment

by:LeTay
ID: 24431725
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
 
LVL 12

Expert Comment

by:Hypo
ID: 24431912
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
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!

 

Author Comment

by:LeTay
ID: 24448521
I will test this probably the 10th of June
I keep you informed
Thanks
0
 

Author Comment

by:LeTay
ID: 24801991
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
 
LVL 12

Expert Comment

by:Hypo
ID: 24802582
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
 

Author Comment

by:LeTay
ID: 24802795
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
 

Author Comment

by:LeTay
ID: 25334779
Hypo,
No final idea to fix this ?
Thanks
0
 
LVL 12

Expert Comment

by:Hypo
ID: 25335033
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
 

Author Comment

by:LeTay
ID: 25335298
I will try next week
This is an application I developed at my customer site where I will go one week from now
0
 

Author Comment

by:LeTay
ID: 25533499
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
 

Accepted Solution

by:
LeTay earned 0 total points
ID: 25940905
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
 
LVL 12

Expert Comment

by:Hypo
ID: 25941021
So you've got an answer to your addional question now then?  
0
 

Author Comment

by:LeTay
ID: 25941032
Yes and the solution is so trivial !
0
 
LVL 12

Expert Comment

by:Hypo
ID: 25941109
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

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…
Attackers love to prey on accounts that have privileges. Reducing privileged accounts and protecting privileged accounts therefore is paramount. Users, groups, and service accounts need to be protected to help protect the entire Active Directory …

726 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question