Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - Martin Vieregg

Pages: [1] 2 3 ... 7
Silvan, a good idea. I compiled the simple text program SendException.exe.

Executing without parameter shows an help text:
sendexception.exe sends an exception to a PID. Enter the PID value in decimal first and the Execption type as second parameter.
Sample:  sendexception 197 2

To recognize the cmd.exe session to observate, run go.exe in the cmd session you want to identify: GO 1.5
The PID we need is in the first row in the line of CMD.EXE, where GO.EXE is shown as child.

In this window, I run "dir /s" which takes a lot of time.
I tried the following input and I got:

Code: [Select]
[C:\]sendexception 106 1
DosSendSignalException returns 205

[C:\]sendexception 106 2
DosSendSignalException returns 209

[C:\]sendexception 106 4
DosSendSignalException returns 205

So the behaviour corresponds to my main program. Now the question is how to send these exceptions to cmd.exe. 209 means ERROR_INVALID_SIGNAL_NUMBER  what is completely suspect to me. 205 means ERROR_NO_SIGNAL_SENT, see the link Silvan posted above.

>CTRL-C works here in Larson Manager.

When pressing Ctrl-C in Larsen Commander, I get a menu with four options:
- Ctrl-C Break
- Ctrl-Break
- exit
- kill.

Ctrl-C Break and Ctrl-Break does not work, exit and kill works. My version is 1.6 milestone 3. I run C:\>  dir /s

>So why did it work for me ? I could start a session and redirect stdout and stdin without a problem.

All works fine, but only sending the Ctrl-C exception to the cmd.exe child does not work. This is the only problem.

>Perhaps your problem is that you are sending the CTRL-C to cmd.exe instead of the child process that cmd is running, make in my example?

Yes, meanwhile I have thought about this problem, too. My main program (the editor) creates a thread where cmd.exe gets executed asynchronously, that means the thread calls  DosExecPgm call and this call returns the PID which I need for sending the exception if a user in the editor presses Ctrl-C. Then the thread waits for terminating cmd.exe by using DosWaitChild. I have only one child PID. The thread which calls DosExecPgm and then waits has only a Thread ID (TID), not a PID.

So the main interest should be at the commandline window itself. The window is a PM program and inside, there is a textmode program running. Perhaps I send the exception to the wrong part ? But I have got only one PID. (Perhaps someone can explain it further what cmd.exe is.)

>Larson Commander seems to be able to do it.

A very interesting hint. I nearly daily use Larsen Commander. The cmd output window is indeed really interesting. It even supports marking text. I haven't checked it yet under this aspect. In opposite to my program, every command starts a new instance of cmd.exe. cmd.exe and its own PID is seen in GO and TOP. That means that it also starts DosExecPgm.
But - what a pity - Ctrl-C Breaks and Ctrl-Break also does not work ! Killing and exiting works. Killing ist clear, but what is exiting (while a long output is running) ? What could be the difference to killing ?This would be an option for Ctrl-C if the classic break does not work.

Anyway, searching a program which has done the job is a goodl way to find the solution.

Laurence also assumed that it should work, but it does not.

- I start cmd.exe via DosExecPgm without failure
- I get a valid PID which corresponds to the shown value in the TOP program
- The thread where I call DosExecPgm waits correctly with DosWaitChild
- In the main thread (user input), I call DosSendSignalException with the valid PID and XCPT_SIGNAL_INTR or XCPT_SIGNAL_BREAK
- but DosSendSignalException returns error 205 and the Exception does not reach cmd.exe.

I observe the steps with a log file.

This is the problem what is discussed the last 15 posts and noone has an idea what the problem could be. A lot of reasons for malfunction are eliminated now.

Besides this point, it seems that I have got all other problems solved and the program already works fine.

I think I cannot run cmd.exe via session by using DosStartSession because only DosExecPgm inherits the standard pipes stdin/stdout/stderr. Meanwhile, I fear we're spinning circles. At the first try, I used DosStartSession and Named Pipes. And I changed to DosExecPgm and unnamed pipes with DosDupHandle with the hope of managing the Ctrl-C Interrupt communication problem. Besides this point, the two ways are basically working. But I have a weak idea that DosExecPgm is the smarter option. In both cases, I can stop it. The DosStartSession variant has got DosStopSession, the DosExecPgm variant DosKillProcess. I cannot believe that there is no solution for sending Ctrl-C to cmd.exe. If noone has got an idea to send Ctrl-C to cmd.exe, I will program a kill option in several steps: One waiting for a finished line output and the harder one with immidiately killing the process. But Ctrl-S should suspend cmd.exe. I can suspend a thread but can I suspend a process? I fear not. And what about sessions? Can I suspend sessions? How does the parent process gets informed if the session ends itseif? I also fear that it is not possible. (With the DosExecPgm variant, I can wait for finishing with DosWaitChild.) Anyway, freezing the output of the parent editor should go. But what happens if the pipe is full? Does the OS suspend the process or do I get an error?

>A process calls DosSetSignalExceptionFocus to become the signal focus.

But I cannot execte CMD.EXE code. I tried to use DosSetSignalExceptionFocus before calling DosExecPgm, but it seems that this property of the parent process is not inherited. DosSetSignalExceptionFocus always refers to the calling process and I cannot hand over a PID in the function call.

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);

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?

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?

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.

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 ?

>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:

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.

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.

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?

Meanwhile, I could program the basic functionality. It basically works fine already. I needed to program several threads: One for stdin, one for stderr, one for cmd.exe itself. stdout commands (the commands the user enters) are sent via main thread. It was only a few hundred lines of new code, but very tricky and nervy. It works now both with cmd.exe and 4os2.exe. Colors are already working. The problem with the unknown output end of a cmd.exe command is not a real problem. The user always can enter input while cmd.exe output is running but that doesn't matter because noone will do so. The problems above are solved. The next jobs is to implement a selection of editor functionality which I have already programmed for ME Editor which will be quite easy.

But I didn't manage to send a Ctrl-C character/message to cmd.exe to stop execution of a current command output. I tried ASCII #3 and ESC[Cm and ESC#3. Any idea how to send the break command to cmd.exe /4os2.exe? Has anyone studied the 4os2 source code?

Then I wonder if the fine working command to execute cmd.exe via my program
program: 'cmd.exe'
parameters: '/C cmd.exe /K <\pipe\mshelloutpipe >\pipe\mshellinpipe 2>\pipe\mshellerrpipe"

which starts cmd.exe twice is really necessary. Any ideas? Can I use pipenames in the OS/2 STARTDATA structure?

Pages: [1] 2 3 ... 7