nppexec
nppexec copied to clipboard
Output from a GUI program gets only after program exists
Hi, I am using nppexec to run my program. It's fine to use with console programs. But if we use it for GUI programs, it displays the output only after the program exists. Is there anyway to get the real time output ?
Most likely it is related to the facts mentioned in NppExec's Manual, section 4.5. Console output redirection:
NppExec uses pipes to redirect child process'es output to NppExec's Console window
and to redirect user's input from NppExec's Console window to child process'es input.
Such approach has several known limitations:
- no output may be shown until child process ends (if this child process performs a lot
of operations without explicit flushing of its output).
Here are more technical details:
- NppExec uses WinAPI function CreatePipe to create a pipe that works as a mediator between NppExec and a running process;
- NppExec uses WinAPI function PeekNamedPipe to check is there is some data within the pipe and calls ReadFile to read the data.
Now, here is what happens when a running process (to which we have connected via the pipe) do not call fflush() on its side:
- The process writes its output to the pipe, and this output is kind of cached within the pipe's internal buffer. WinAPI does not provide ability to set the size of this internal buffer or to specify that we don't want to use this internal buffer within the pipe.
- NppExec calls PeekNamedPipe - and PeekNamedPipe returns FALSE because the internal pipe's buffer is not full. Let me repeat it: the pipe already contains some data from the running process, but since this pipe internally uses some buffer to store this data and this buffer is not full, PeekNamedPipe returns FALSE as if there no data in the pipe. And NppExec, as an external user of this pipe, has no information and no control of this internal pipe's buffer.
- You may ask: well, if we can't rely on PeekNamedPipe, why not calling ReadFile even though PeekNamedPipe returned FALSE? Well, the reality is the following: if you call ReadFile while PeekNamedPipe returned FALSE this ReadFile will return only when the pipe's internal buffer is full or the running process ends. I.e. you would have a blocking call of ReadFile that will wait and wait and wait.
- You may ask: how could it be that Microsoft is not aware of this? Well, Microsoft is aware of this. This question was raised a lot of years ago, it is periodically repeated in forums, including Microsoft's support forums. I can tell even more: somebody even proposed a solution for this! And still, Microsoft does nothing about this. Absolutely nothing.
@d0vgan
First of all thanks for the detailed reply. It's amazing that you have a wonderful ability to explain things clearly. I don't know how I missed that part from manual.
BTW, There is an extension for VS Code named code-runner. It is doing the same job of nppExec. By default, it is displaying program results in output window of VS Code. And we can see the same behavior in output window. But this extension has a settings like this --
"code-runner.runInTerminal": true,
When setting this as true, code-runner will display program results in Terminal window of VS Code. And then we will get program results in real time. No need to wait for the program to exit. Can you mimic this functionality in nppExec ?
Hi, I requiest you to add this code snippet to your user manual. It's an example of if statement to run various source files depends up on their extensions. ` If "$(EXT_PART)" == ".d" then // It's a D source file. npp_save dmd -i -run "$(FULL_CURRENT_PATH)" else if "$(EXT_PART)" == ".nim" then // It's a Nim source file. npp_save nim c -r "$(FULL_CURRENT_PATH)" else messagebox "Unknown File...!"
endif `
When I'll have time, I'll experiment with the approach described here: https://www.codeproject.com/Articles/16163/Real-Time-Console-Output-Redirection especially with the updated version that ia available here: https://github.com/buck54321/PipeStuffer NppExec can't use that implementation "as is" because NppExec not only reads the console output but also allows to send console input to a running process. Correspondingly, more experiments and efforts are needed to adapt this approach to NppExec.
I am glad that you are working on it. I hope you can achieve better results from your experiments. I am expecting a better nppExec which behaves like the code-runner extension for VS Code. It accepts command line arguments for each file extension and when you click the run button, it detects the file extension. Then it uses the appropriate cmd argument for that extension.
This approach looks promising: https://learn.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session
@d0vgan, Thanks. Let me check it.
@d0vgan, Thanks. Let me check it.
I've actually started to experiment with it: https://github.com/d0vgan/nppexec/tree/feature/pseudo-console
The progress so far is mentioned here: https://community.notepad-plus-plus.org/topic/24295/anyone-familair-with-pseudoconsole-api-in-windows-10
I've asked another developer for advice since he uses PseudoConsole in his Python code: https://github.com/veksha/cuda_exterminal/issues/51 From his clarifications, NppExec must support ANSI escape codes to deal with PseudoConsole properly. Which, in its turn, returns us to this: https://github.com/d0vgan/nppexec/issues/14 The circle closed up :)