d0vgan / nppexec

NppExec (plugin for Notepad++)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

bug - cannot send ctrl-c to python when started externally

badrelmers opened this issue · comments

Hi,
I need to run python and wait for it to finish, so I run it like this (as it is suggested in the manual):

cmd /C start /wait C:\Python37x64\python.exe -c "from time import sleep; sleep(1000)"

but now if I send ctrl-c to this newly created python window nothing happen, python do not receive the signal.

the same command works fine if I run it from the run menu which come with notepad++

I m using the last nppexec v0.7.1 and notepad++ 32 v8.1.5 on win 7 64

is there anything I can do to solve this? thank you


image

What if you omit the cmd /C start /wait part, thus executing only C:\Python37x64\python.exe -c "from time import sleep; sleep(1000)" ?
I mean, do you really need cmd /C start /wait, why not running Python directly in NppExec's Console?

And, to answer your original question, the Ctrl-C in case of cmd /C start /wait C:\Python37x64\python.exe is sent to the cmd (since it is cmd that is running in NppExec's Console).
In terms of internal implementation, NppExec uses the following WinAPI call:

GenerateConsoleCtrlEvent(CTRL_C_EVENT, dwProcessId);

where the dwProcessId corresponds to the cmd process.
Well, maybe NppExec should walk through the process tree and find the last child of the process that is running in NppExec's Console and send ctrl-c to the last child? I mean, in our case, we have the following process tree:

cmd.exe       // runs directly in NppExec's Console - root process
  python.exe  // runs from cmd.exe - child process

In general, the process tree may be deeper (e.g. Python may run another child process and so on). So the question of ctrl-c is a general question: should ctrl-c be always sent to the root process or to the last child process in the process tree? In the latter case, we may end up with a need of multiple ctrl-c required to end the whole process tree: the first ctrl-c exits the last child process, the second ctrl-c exits the previous child process (which is a parent of the last child process) and so on.

What if you omit the cmd /C start /wait part, thus executing only C:\Python37x64\python.exe -c "from time import sleep; sleep(1000)" ?

yes without cmd /C start /wait ctrl-c works fine, but I need to wait for the end of the called process to do some cleaning at the end.

I mean, do you really need cmd /C start /wait, why not running Python directly in NppExec's Console?

I don't use the NppExec's Console because changing habits is hard :/ , I just cannot work with an internal console (even the vscode one), I find it hard to manage the console as I m accustomed.

Well, maybe NppExec should walk through the process tree and find the last child of the process that is running in NppExec's Console and send ctrl-c to the last child?

I think this can be solved in two ways:

  1. the Nppexec manual says to use cmd /C start /wait as a workaround for npp_run to run a command externally and wait for it to finish. so I think the solution would be to detect if cmd /C start /wait was used , and if yes then send the ctrl-c to the command which was run by cmd /C start /wait not to cmd (which is python in our case). but this may seems hackish.

  2. I propose to add a new command npp_run_wait which works like npp_run but can wait for the end of the called command. is it possible?

Another possibility might be to use this technique while calling CreateProcess in NppExec

I have 0 experience with C/C++ so I cannot comment on this :/

thank you very much.

Yes, introducing a job object associated with the running process (as explained in the article from the above link) allows to kill the whole process tree when the first running process is killed.
This change will be available in the next release of NppExec. Maybe I'll upload a pre-release (not final) version of NppExec to sourceforge in the next week or two to make it available for wider testing.

great, killing the whole process tree is excellent. thank you

Unfortunately the same problem still occurs.

I see that you added the feature of killing the program and its children's, but the problem that I described in my first post is not this, but something else.
The problem is that in the above example, Python does not receive ctrl-c sent from my keyboard to the python console opened by NppExec (using cmd /C start /wait ...). but the feature you added works when I kill the parent process.

ctrl-c does not always mean killing, it may mean a lot of things when you catch it inside python.

But I am happy that you added the feature to kill the children's of the program. This is a great thing, this is undoubtedly a great addition. thank you

Hmm, could you elaborate what exactly you are doing when "Python does not receive ctrl-c sent from my keyboard" ?
If it is pressing ctrl-c in Python's console window (i.e. in the system's window that looks like a terminal window with its black background), then you are actually explicitly dealing with the console window itself and NppExec is not invoked with interaction with this window, i.e. NppExec neither processes nor catches any key pressed in it.

I mean exactly the following:
I open the Nppexec console
image
I run python like that

cmd /C start /wait F:\_bin\_bin\Python37x64\python.exe -c "from time import sleep; sleep(1000)"

I get the black console window
image
then I press ctrl-c on this window, the window do not receive ctrl-c

but if I use npp_run to run python like that:

npp_run F:\_bin\_bin\Python37x64\python.exe -c "from time import sleep; sleep(1000)"

then the black window receive ctrl-c
so Nppexec seems to block ctrl-c when we use cmd /C start /wait

OK, I think I've identified the root cause of it! I was additionally providing a flag CREATE_NEW_PROCESS_GROUP, for which the documentation says:
"If this flag is specified, CTRL+C signals will be disabled for all processes within the new process group"
Somehow I've missed that.

You can try to have a quick fix by patching the exisiting file "NppExec.dll":
at offset 000255CA, change 02 to 00
at offset 000255CF, change 02 to 00
This will remove the flag CREATE_NEW_PROCESS_GROUP.

super, this solved it. thank you very very much
for the others ; this change should be done on this version NppExec20220128_dll in dev

It works perfectly now, ctrl-c is sent directly to the python console. thank you very much for your work and time.

NppExec v0.8