Author Topic: problems programming a new text window for cmd.exe/4os2.exe  (Read 38724 times)

Andi B.

  • Hero Member
  • *****
  • Posts: 811
  • Karma: +11/-2
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #15 on: January 09, 2020, 08:06:52 am »
For the redirection I think you can do this in your program. DosCreatePipe and friends may help. I don't have exactly what you need but maybe this snippset gives you a starting point -

Code: [Select]
DosDupHandle( HF_STDOUT, &hfSave);        /* Saves standard output handle      */
DosCreatePipe(&hpR, &hpW, PIPESIZE);      /* Creates pipe                      */
DosDupHandle(hpW, &hfNew);                /* Duplicates standard output handle */

Martin Vieregg

  • Sr. Member
  • ****
  • Posts: 278
  • Karma: +2/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #16 on: January 09, 2020, 11:07:11 pm »
Quote
The function to send the break signal to a process is DosSendSignalException, using the pid of the process and XCPT_SIGNAL_INTERRUPT  or XCPT_SIGNAL_BREAK as the second argument

Thank you for this useful hint. But it does not work. I get the Session PID from DosStartSession (last parameter). DosSendSignalException is running from another thread (because DosExecPgm blocks the thread). DosSendSignalException returns 205  ERROR_NO_SIGNAL_SENT.

Any ideas?

Laurence Pithie

  • Jr. Member
  • **
  • Posts: 62
  • Karma: +1/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #17 on: January 10, 2020, 12:01:37 am »
The 205 error meant that there isn't a process with a signal handler in the process tree. You should set  up an exception handler in the thread that calls DosExecProcess using DosSetExceptionHandler prior to issuing the DosExecProgram
You can run the process asynchronously by passing EXEC_ASYNCRESULT or EXEC_ASYNC as the third parameter in the DosExecPgm call. The latter flag discards any result from the called process.

Martin Vieregg

  • Sr. Member
  • ****
  • Posts: 278
  • Karma: +2/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #18 on: January 10, 2020, 02:07:41 pm »
It still doesn't work even I install an exeption handler for the process. I still get error 205. I run the program asnychrous. The thread rests at DosExecPgm while the program is running and continues when exiting the program.

Could it be possible that only the first cmd.exe which exeuctes the second is in reach for me? I execute cmd.exe first and this cmd.exe executes a second cmd.exe and sends the pipenames as parameters:

program: 'cmd.exe'
parameters: '/C cmd.exe /K <\pipe\mshelloutpipe >\pipe\mshellinpipe 2>\pipe\mshellerrpipe"

If this is a problem, I have to start cmd.exe directly. But how can I hand over the pipe names to the program/process? Via STARTDATA parameter? I haven't found a solution.


Laurence Pithie

  • Jr. Member
  • **
  • Posts: 62
  • Karma: +1/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #19 on: January 10, 2020, 03:19:42 pm »
Yes, you don't have the pid of the second cmd process and there's no simple way to get hold of it. .

You don't need to pass the pipe name to the child process. A child process inherits the open file handles of the parent. Create a pipe in the parent process, Save the parent processes stdin and stdout to temporary file handles and call DosDupHandle on stdin and stdout setting them to the write and read handles of the pipe. Then call DosExecProgram and following that restore stdin and stdout in the parent. At that point anything writtten to the pipe's write handle from the parent should go to stdin for the child and anything written to stdout in the child can be read from the pipe's write handle.


Martin Vieregg

  • Sr. Member
  • ****
  • Posts: 278
  • Karma: +2/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #20 on: January 10, 2020, 04:58:52 pm »
>Create a pipe in the parent process

OK. That has been done from the beginning of my project.

>Save the parent processes stdin and stdout to temporary file handles

OK. I have them via DosCreateNPipe parameter.

>and call DosDupHandle on stdin and stdout setting them to the write and read handles of the pipe.

I assume that the Outpipe of my program is the stdin of the child program and reverse. So I have to reverse the assignments in DosDupHandle.

>Then call DosExecProgram and following that restore stdin and stdout in the parent.

I read the docu of DosExecPgm and indeed, I found:

Quote
The new process inherits all file handles and pipes of its parent, although not necessarily with the same access rights:

- Files are inherited except for those opened with no inheritance indicated.
- Pipes are inherited.

A child process inherits file handles obtained by its parent process with DosOpen calls that indicated inheritance. The child process also inherits handles to pipes created by the parent process with DosCreatePipe. This means that the parent process has control over the meanings of standard input, output, and error. For example, the parent could write a series of records to a file, open the file as standard input, open a listing file as standard output, and then execute a sort program that takes its input from standard input and writes to standard output.

Because a child process can inherit handles, and a parent process controls the meanings of handles for standard I/O, the parent can duplicate inherited handles as handles for standard I/O. This permits the parent process and the child process to coordinate I/O to a pipe or file. For example, a parent process can create two pipes with DosCreatePipe requests. It can issue DosDupHandle to redefine the read handle of one pipe as standard input (hex 0000), and the write handle of the other pipe as standard output (hex 0001). The child process uses the standard I/O handles, and the parent process uses the remaining read and write pipe handles. Thus, the child process reads what the parent process writes to one pipe, and the parent process reads what the child process writes to the other pipe.

>At that point anything writtten to the pipe's write handle from the parent should go to stdin for the child and anything written to stdout in the child can be read from the pipe's write handle.

I will try it and report here.

Laurence Pithie

  • Jr. Member
  • **
  • Posts: 62
  • Karma: +1/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #21 on: January 10, 2020, 06:16:27 pm »
>OK. I have them via DosCreateNPipe parameter.
No, you haven't. You need to save the current stdin and stdout to  temporary file handles, your main process is a PM application, stdin and stdout are not necessarily what you think they are in that context, they're certainly not connecte to a console and you'll need to restore them at the end of this process. If you use a named pipe you don't have a file handle you have a handle to a named pipe. They're both unsigned longs, but they point to completely different structures. I suspect that the outcome will be tears before bedtime. Use an unamed pipe, you get two file handles a read handle and a write handle on the return from that call.

>>and call DosDupHandle on stdin and stdout setting them to the write and read handles of the pipe.

>I assume that the Outpipe of my program is the stdin of the child program and reverse. So I have to reverse the assignments in DosDupHandle.

No, your child process inherits the parent processes stdin and stdout which you set to the read and write handles of the pipe using the DosDupHandle call. Don't reverse them, you dup the read file handle with your parent process stdout so that the parent processs standard output is now the write filehandle of the pipe and then dup the read handle with the read file handle. Following this the parent process's standard input and standard output are the read and write filehandles of the unnamed pipe respectively. When your child process inherits the parent't processes stin and stout they'll be correctly linked to the appropraite ends of the pipe.

Following the call to DosExecProgram restore the parent process stdin and stdout from where you saved them at the start of this proces.
Now, when the parent process writes to the write file handle of the pipe it will go to the stdin of the child process because the other end of the write filehandle in the parent is connected to the read filehandle in the child and vice versa.


Martin Vieregg

  • Sr. Member
  • ****
  • Posts: 278
  • Karma: +2/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #22 on: January 10, 2020, 06:48:32 pm »
If I understand it right,

- I have to use DosCreatePipe (an unnamed pipe) three times for stdin, stdout and stderr (but at this moment, they are not assigned yet) and I will get real file handles, 3 are used, 3 are not used. Or do I only use one Pipe with read and write? (But where is stderr then?)

- I call DosDupHandle and assign them to stdin, stdout and stderr.

>you dup the read file handle to your parent process stdout
but that means reverse.

When terminating the program, what do I have to do ?

Laurence Pithie

  • Jr. Member
  • **
  • Posts: 62
  • Karma: +1/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #23 on: January 10, 2020, 08:24:11 pm »
No you need to create one pipe for stdin and stdout. You provide three parameters to the DosCreatePipe, Two HFILE pointers and the size of the pipe. Which one you designate the read handle and the write handle is arbitrary, what get's written to one end of a filehandle can be read at the other, so if you dup stdin with the first handle then your child process will inherit that connected to it's standard inout, so whatevr the parentr process writes to the first filehandle will be read by the standard input of the child, the process for the second file handle is similar, duping it with stdout so that it's inherited as the stdout of the child process. The parent can then read from that file handle anything the child writes to it's standout. Data can travel both ways through each filehandle, however coordinating reading and writing to a signel channel would be complex and error prone, hence the abstraction provides two channels and you use one for reading and one for writing.  If you want to connect stderr to a pipe you'll need to create a second pipe, dup stderr to one of the filehandles and use that filehandle tin  the parent to read the output of stderr in the child. If you're being tidy you call DosClose on the other filehandle.

So, each call to DosCreatPipe gives you two file handles.

In the parent
1. ***Save your stdin and stdout***
2  Dup one filehandle with stdin, one with stdout, The parent process's stdin is now the filehandle from the pipe. Ditto for stdout. The parents stdinput is connected to the filehandle in the pipe, the child process inherits that filehandle as it's standar output, so that's where it reads from.
3. Call DosExecProg, the child inherits the parents stdin and stdout which are the two filehandles returnd from the pipe call.
4. In the parent
***restore the saved stdin and stdout***
 So stdin in the parent is not stdin in the child. The parent writes to the filehandle that's connected to the child processes stdin. 

In the child
1 The filehandle that was returned in the DosCreatePipe call in the parent is inherited as stdin, the OS tells the child it's value is 0.
2. The other filehandle returned by the call to DosCreateFile in the parent is inherited by the child as it's standard output. The OS tells the child that it's value is 1.

The child reads from the filehandle with the value 0 and writes to the filehandle with the value 1. The parent reads and writes to the pipe, it's restored it's standard input and standard output to their original values after the call to DosExecProgram.

stdin and sdout are abstractions provided by the operating system. Every process reads from fd0 and writes to fd1, The OS  juggles what they actually point to behind the curtain. The parent process changes what it's stdin and stdout point to from fd0 and fd1 to whatever value is returned in the call to DosCreatePipe, the child inherits those values as it's stdin and stdout and the parent resores it's original stdin and stdout. So the parents stdout and stdin aren't coinnected ot the childs, the filehandles returnd from the call to DosCreatePipe are.


Martin Vieregg

  • Sr. Member
  • ****
  • Posts: 278
  • Karma: +2/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #24 on: January 12, 2020, 10:30:51 am »
Thank you for the hints, Laurence. I finished now programming (the length of the code is less now), it seems to be quite simple. After a second try, it works yet.

The main progress I made by studying a sample code popen.c

A pipe has got two ends: one for reading and one for writing. (Laurence told us that the reverse direction is also possitble.) So what to do is

1. DosCreatePipe with two handles:  A "write-end" and a "read-end" for the pipe. So a pipe is always defined by a pair of file handles. The "write-end" is for the parent program and the "read-end" for the child program when sending data from parent to child (the user enters command input in my parent editor) or reverse for sending cmd.exe output into the editor. I need three pipes for handling stdin, stdout and stderr.

2. To tell the child the correct filehandles for the child-end of the pipe, I need to use DosDupHandle. The child-end file handles are duped to the filehandle values 0, 1 2 for stdin, stdout and stderr. When using DosExecPgm to start the child program, these handles get available for the child.

Restoring and Saving the file handles with additional DosDupHandle calls are not necessary in a PM app, but can be done.
« Last Edit: January 13, 2020, 11:35:04 pm by Martin Vieregg »

Martin Vieregg

  • Sr. Member
  • ****
  • Posts: 278
  • Karma: +2/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #25 on: January 13, 2020, 11:48:54 pm »
After I managed the pipes, the Ctrl-C break is still not working. At the moment, I generate a thread where cmd.exe gets executed synchronous. While running cmd.exe, the thread "hangs" in the DosExecPgm function call. The necessary DosSendSignalException call when a user in the parent program editor enters Ctrl-C needs a process identification (PID). But I have only a thread identification (TID) from my thread. How do I get the PID ? Do I have to run cmd.exe asynchronous?

Laurence Pithie

  • Jr. Member
  • **
  • Posts: 62
  • Karma: +1/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #26 on: January 14, 2020, 02:43:58 pm »
According to the toolkit documentation for DosExecPgm
Quote
If asynchronous execution is indicated, DosExecPgm places the process ID of the started child process into the first doubleword of the pRes structure. If EXEC_ASYNCRESULT is specified for execFlag, the parent process can issue DosWaitChild (after DosExecPgm) to examine the result code returned when the child process ends. If the value of execFlag, is EXEC_ASYNC, the result code of the asynchronous child process is not returned to the parent process.
If the process is run synchronously the codeTerminate field of the RESULTCODES structure contains the result code returned on completion of the process. When the process is run asynchronously the  codeTerminate field contsins the pid of the process. So to get the pid you need to run the process ansynchronously, and, if you want both the pid and the resultcode you have to run it asynchronously and call DosWaitChild.

Martin Vieregg

  • Sr. Member
  • ****
  • Posts: 278
  • Karma: +2/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #27 on: January 14, 2020, 05:08:50 pm »
OK, now the child (cmd.exe) runs asynchrously and I exeute DosWaitChild after starting cmd.exe by using DosExecPgm. All functions return no error. The returned PID is zero (is that normal?) The program still runs fine with the modifications.

Because my parent program is an editor which already has a function for pressing Ctrl-C, I don't think I need to install an exception handler in the main process. If the exception handler is necessary nevertheless, what do I write into the @function which is related to the exception?

Although I have now the PID, DosSendSignalException (PID, XCPT_SIGNAL_INTR) has no effect. The function is definitely executed in the main thread when pressing Ctrl-C in the parent editor. It still returns the value 205 (no process or no process with exception handler). Any ideas?

Laurence Pithie

  • Jr. Member
  • **
  • Posts: 62
  • Karma: +1/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #28 on: January 14, 2020, 08:02:03 pm »
A returned pid of zero isn't normal. You can check  what pid you should be getting by running top and looking for the cmd process you launched. If you're using  zero as the pid in your call to DosSendSignalException then the Exception will not be sent to your process. There isn't a process with a pid of zero, SYSINIT is the base process and its pid is 1. So that's why you're getting a 205 error, there's no process with that pid.

The PID of the process will, if the EXEC_ASYNC flag is used, be in the RESULTCODES->codeTerminate field when the call to DosExecPgm returns. Are you saving the value before you call DosWaitChild? DosWaitChild will set that value to zero for a normal exit.

Martin Vieregg

  • Sr. Member
  • ****
  • Posts: 278
  • Karma: +2/-0
    • View Profile
Re: problems programming a new text window for cmd.exe/4os2.exe
« Reply #29 on: January 14, 2020, 10:07:04 pm »
Oops, that was my failure. The return value has been set to another value later. Now the PID which I save corresponds to the TOP value. But DosSendSignalException still returns 205. My program log sends:

2020.1.14 21:40:55.699: exec DosExecPgm
2020.1.14 21:40:55.699: cmd.exe has been started. child_PID 213
...
2020.1.14 21:40:59.900: ScanEvent Ctrl-C, PID 213
2020.1.14 21:40:59.900: DosSendSignalException returns 205
2020.1.14 21:41:0.369: ScanEvent Ctrl-C, PID 213
2020.1.14 21:41:0.369: DosSendSignalException returns 205
2020.1.14 21:41:1.900: ExternProgThread still running
(User ends program)
2020.1.14 21:41:1.900: Bytes read 0
2020.1.14 21:41:1.900: not finished
2020.1.14 21:41:1.900: End cmd.exe child_PID 213 rc 0
2020.1.14 21:41:2.29: Bytes read 0 (from cmd.exe stdout)
2020.1.14 21:41:2.29: ExternProgThread has ended normally
2020.1.14 21:41:2.29: PipeinFinish
2020.1.14 21:41:2.29: App.Terminate


DosWaitChild works fine, the thread suspends correctly. The exception is sent via:
                  ULONG Exception = XCPT_SIGNAL_INTR;
                  rc = DosSendSignalException(child_PID, Exception);