Board index » delphi » Inherited handles from DCOM server

Inherited handles from DCOM server

Hello,

I have a question about the STDIN handle !

I have a DCOM server that gets a request from a client.
The DCOM server creates a console process and this
process inherited the handles of the DCOM server.

I re-route the STDOUT to a pipe and keep the STDIN.
The created process uses basic routines like read and write,
without using a handle.

However the write rotine works but the read routine can't use
the STDIN Handle inherited from the DCOM Server !

I get a error message, invalid handle !!!!

If I re-create in the (new) console application, with CreateFile,
a new Console, the handle is valid, why ?

What do I forget, is it the security of the DCOM server ????

Regards,

Bernard Stibbe

 

Re:Inherited handles from DCOM server


Quote
Bernard Stibbe wrote:
> The DCOM server creates a console process and this
> process inherited the handles of the DCOM server.

> I re-route the STDOUT to a pipe and keep the STDIN.

...

Quote
> However the write rotine works but the read routine can't use
> the STDIN Handle inherited from the DCOM Server !

> I get a error message, invalid handle !!!!

You can't redirect one of the three handles without redirecting the other
two. What's your code around CreateProcess where you do this redirection?

-Michael

Re:Inherited handles from DCOM server


Michael,

Here is the current code ....

procedure TMedium.do_Execute;
var
  SA: TSecurityAttributes;
  SI: TStartupInfo;
  PI: TProcessInformation;
  StdOutPipeRead, StdOutPipeWrite: THandle;
  WasOK: Boolean;
  Buffer: array[0..9600] of Char;
  tmpBuff: array[0..9600] of Char;
  PBuffer: PChar;
  BytesRead: Cardinal;
  BytesPeek,totBytes, leftBytes: Cardinal;
  Line: String;
  sExecFilePath: String;
  i: Integer;
begin

  with SA do
  begin
    nLength := SizeOf(SA);
    bInheritHandle := True;
    lpSecurityDescriptor := nil;
  end;

  // create pipe for standard output redirection
  CreatePipe(StdOutPipeRead,  // read handle
             StdOutPipeWrite, // write handle
             @SA,             // security attributes
             9600             // number of bytes reserved for pipe
             );
  try
    // Make child process use StdOutPipeWrite as standard out,
    // and make sure it does not show on screen.
    with SI do
    begin
      FillChar(SI, SizeOf(SI), 0);
      cb := SizeOf(SI);
      dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
      wShowWindow := SW_HIDE;

//----------------
// Use a new console input !
//----------------
{
hStdInput := CreateFile ( PChar( 'CONIN$' ) ,
   GENERIC_READ or GENERIC_WRITE,
   FILE_SHARE_READ      or FILE_SHARE_WRITE,
   NIL,
   OPEN_ALWAYS,
   FILE_ATTRIBUTE_NORMAL,
   0 );

Quote
}

// This code works on the client side !!!
//----------------

      hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect
stdinput
      hStdOutput := StdOutPipeWrite;
      hStdError := StdOutPipeWrite;
    end;

    // The ExecStuff
    sExecFilePath := ...

    // launch the sExecFilePath
    WasOK := CreateProcess(nil, PChar(sExecFilePath), nil, nil, TRUE,
CREATE_NEW_CONSOLE, nil, nil, SI, PI);

    // Now that the handle has been inherited, close write to be safe.
    // We don't want to read or write to it accidentally.
   CloseHandle(StdOutPipeWrite);

    // if process could be created then handle its output
    if not WasOK then begin
      PostException(SysErrorMessage(GetLastError));
    end else
      try
        // get all output until dos app finishes
        Line := '';
        repeat
           PBuffer := tmpBuff;
           // Dont block the Service ....
           WasOk := PeekNamedPipe(StdOutPipeRead, PBuffer, 9600,
@BytesPeek, @totBytes, @leftBytes);

           // read block of characters if available (might contain
carriage returns and line feeds)
           if BytesPeek > 0 then begin
              WasOK := ReadFile(StdOutPipeRead, Buffer, BytesPeek,
BytesRead, nil);

              // has anything been read?
              if BytesRead > 0 then begin
                // finish buffer to PChar
                Buffer[BytesRead] := #0;
                // combine the buffer with the rest of the last run
                Line := Line + Buffer;
              end;
           end;
        until (not WasOK or ... ) ;

        ...

      finally
        // Close all remaining handles
        CloseHandle(PI.hThread);
        CloseHandle(PI.hProcess);
      end;
  finally
      // Remove carriage returns and pass them as a line
      while pos(#13#10, line) > 0 do begin
        PostInfo(copy(Line,1,pos(#13#10, line)-1));
        line := copy(line, pos(#13#10, line)+2, length(line));
      end;
      CloseHandle(StdOutPipeRead);
  end;
end;

Quote
Michael Winter <[email protected]> wrote in message <news:[email protected]>...
> Bernard Stibbe wrote:

> > The DCOM server creates a console process and this
> > process inherited the handles of the DCOM server.

> > I re-route the STDOUT to a pipe and keep the STDIN.

> ...

> > However the write rotine works but the read routine can't use
> > the STDIN Handle inherited from the DCOM Server !

> > I get a error message, invalid handle !!!!

> You can't redirect one of the three handles without redirecting the other
> two. What's your code around CreateProcess where you do this redirection?

> -Michael

Re:Inherited handles from DCOM server


Michael,

Here is the current code ....

procedure TMedium.do_Execute;
var
  SA: TSecurityAttributes;
  SI: TStartupInfo;
  PI: TProcessInformation;
  StdOutPipeRead, StdOutPipeWrite: THandle;
  WasOK: Boolean;
  Buffer: array[0..9600] of Char;
  tmpBuff: array[0..9600] of Char;
  PBuffer: PChar;
  BytesRead: Cardinal;
  BytesPeek,totBytes, leftBytes: Cardinal;
  Line: String;
  sExecFilePath: String;
  i: Integer;
begin

  with SA do
  begin
    nLength := SizeOf(SA);
    bInheritHandle := True;
    lpSecurityDescriptor := nil;
  end;

  // create pipe for standard output redirection
  CreatePipe(StdOutPipeRead,  // read handle
             StdOutPipeWrite, // write handle
             @SA,             // security attributes
             9600             // number of bytes reserved for pipe
             );
  try
    // Make child process use StdOutPipeWrite as standard out,
    // and make sure it does not show on screen.
    with SI do
    begin
      FillChar(SI, SizeOf(SI), 0);
      cb := SizeOf(SI);
      dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
      wShowWindow := SW_HIDE;

//----------------
// Use a new console input !
//----------------
{
hStdInput := CreateFile ( PChar( 'CONIN$' ) ,
   GENERIC_READ or GENERIC_WRITE,
   FILE_SHARE_READ or FILE_SHARE_WRITE,
   NIL,
   OPEN_ALWAYS,
   FILE_ATTRIBUTE_NORMAL,
   0 );
if not setSTdHandle(STD_INPUT_HANDLE , hStdInput ) then exit;

Quote
}

// This code works on the client side !!!
//----------------

      hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect
stdinput
      hStdOutput := StdOutPipeWrite;
      hStdError := StdOutPipeWrite;
    end;

    // The ExecStuff
    sExecFilePath := ...

    // launch the sExecFilePath
    WasOK := CreateProcess(nil, PChar(sExecFilePath), nil, nil, TRUE,
CREATE_NEW_CONSOLE, nil, nil, SI, PI);

    // Now that the handle has been inherited, close write to be safe.
    // We don't want to read or write to it accidentally.
   CloseHandle(StdOutPipeWrite);

    // if process could be created then handle its output
    if not WasOK then begin
      PostException(SysErrorMessage(GetLastError));
    end else
      try
        // get all output until dos app finishes
        Line := '';
        repeat
           PBuffer := tmpBuff;
           // Dont block the Service ....
           WasOk := PeekNamedPipe(StdOutPipeRead, PBuffer, 9600, @BytesPeek,
@totBytes, @leftBytes);

           // read block of characters if available (might contain carriage
returns and line feeds)
           if BytesPeek > 0 then begin
              WasOK := ReadFile(StdOutPipeRead, Buffer, BytesPeek,
BytesRead, nil);

              // has anything been read?
              if BytesRead > 0 then begin
                // finish buffer to PChar
                Buffer[BytesRead] := #0;
                // combine the buffer with the rest of the last run
                Line := Line + Buffer;
              end;
           end;
        until (not WasOK or ... ) ;

        ...

      finally
        // Close all remaining handles
        CloseHandle(PI.hThread);
        CloseHandle(PI.hProcess);
      end;
  finally
      // Remove carriage returns and pass them as a line
      while pos(#13#10, line) > 0 do begin
        PostInfo(copy(Line,1,pos(#13#10, line)-1));
        line := copy(line, pos(#13#10, line)+2, length(line));
      end;
      CloseHandle(StdOutPipeRead);
  end;
end;

Quote
"Michael Winter" <[email protected]> wrote in message

news:[email protected]
Quote
> Bernard Stibbe wrote:

> > The DCOM server creates a console process and this
> > process inherited the handles of the DCOM server.

> > I re-route the STDOUT to a pipe and keep the STDIN.

> ...

> > However the write rotine works but the read routine can't use
> > the STDIN Handle inherited from the DCOM Server !

> > I get a error message, invalid handle !!!!

> You can't redirect one of the three handles without redirecting the other
> two. What's your code around CreateProcess where you do this redirection?

> -Michael

Re:Inherited handles from DCOM server


Quote
Bernard Stibbe wrote:
> Here is the current code ....

Looks ok so far. However, I remember I had to deal with DuplicateHandle
somehow when redirecting console in/output, but I can't access that project
now. Look here for some examples how to redirect. And see my other posting.

-------- (copied from Peter:)
  spawning DOS apps with redirecton:
 TRedirector       http://www.pana.com/robert/Dcomp.html
 TGUI2Console      www.delphipages.com in the 'NonVisual' section
   code example: http://www.prel.btinternet.co.uk/downloads/console.zip
                 http://www.delphi3000.com/articles/article_2112.asp
    http://www.torry.net/tasks.htm,  look for DosCommand
--------

-Michael

Re:Inherited handles from DCOM server


Bernhard,

excuse my last posting, I didn't read your's carefully enough. Give me
another try:

Quote
Bernard Stibbe wrote:
> I have a DCOM server that gets a request from a client.
> The DCOM server creates a console process and this
> process inherited the handles of the DCOM server.

> I re-route the STDOUT to a pipe and keep the STDIN.
> The created process uses basic routines like read and write,
> without using a handle.

> However the write rotine works but the read routine can't use
> the STDIN Handle inherited from the DCOM Server !

> I get a error message, invalid handle !!!!

That means the console process can write to the (redirected) pipe, but can
not read from it's stdin, right?

(1) What would you expect the console process to read from the stdin it
inherits from the DCOM server?

(2) If memory serves, a GUI's std handles are invalid by default. I. e. if
you read(ln)/write(ln) in a GUI application you get an invalid file handle
error. That invalid handle is what you inherit to the console process.

-Michael

Re:Inherited handles from DCOM server


Hello Michael,

I generate keystrokes, reading them from a datafile, and forward those to
the stdin.

The console application doesn't know that it has been started by
a DCOM server and gets it data from a script.

The console application is an old application (< 10 years),
developed on a mainframe and still used in the insurance world.
We ported all the console applications to a windows environment.

Regards,

Bernard Stibbe

Quote
Michael Winter <[email protected]> wrote in message

news:[email protected]
Quote
> Bernard Stibbe wrote:

> > GUI's std handles are indeed invalid by default, because it is not a
> > console application.
> > Now I also understand why I should not inherited the IO handles from
> > the (GUI) DCOM server

> > Is the only solution create a new console, like

> > hStdInput := CreateFile ( PChar( 'CONIN$' ) ,

> I'm not sure, but I think creating a simple file or another pipe would do,
> too. However, what I don't understand is what do you expect the console
> application to read from stdin if nothing writes to it?

> -Michael

Re:Inherited handles from DCOM server


Quote
Bernard Stibbe wrote:
> I generate keystrokes, reading them from a datafile, and forward those
> to the stdin.

Okay, but wouldn't it then be better to use another pipe which redirects
stdin, and put the keystrokes into the writing end?

-Michael

Other Threads