Page 1 of 1
Launch Persistent Shell
Posted: Wed Sep 22, 2021 10:04 pm
by studawg66
I have an external script that I want to trigger on openStack, but the cmd (shell) window needs to stay open. If I run this executable outside of LC, the cmd window stays open because of my input command, so it says "Press enter to exit" and awaits that key stroke.
But whenever I do a "get shell(myScript)" in LC it launches the command line utility but then immediately closes it. Is there a way to keep that cmd window open, awaiting the input request?
Re: Launch Persistent Shell
Posted: Fri Sep 24, 2021 10:06 am
by Bernard
Why can't I reply to this. My reply (with sample code) always fails to be accepted by the forum software.
Re: Launch Persistent Shell
Posted: Fri Sep 24, 2021 10:09 am
by Bernard
studawg66 wrote: ↑Wed Sep 22, 2021 10:04 pm
I have an external script that I want to trigger on openStack, but the cmd (shell) window needs to stay open. If I run this executable outside of LC, the cmd window stays open because of my input command, so it says "Press enter to exit" and awaits that key stroke.
But whenever I do a "get shell(myScript)" in LC it launches the command line utility but then immediately closes it. Is there a way to keep that cmd window open, awaiting the input request?
Code: Select all
get shell("start x /K dir "); put the long time
(replace x with cmd dot exe above)
will open a terminal window and list the files in that directory (the defaultFolder). The terminal window will have focus.
I'm not clear if you want to stop execution of your code whilst you are waiting for the user to interact with your terminal window. In the above case LC will continue processing (as evidenced by the long time appearing in the message box.
Re: Launch Persistent Shell
Posted: Fri Sep 24, 2021 10:10 am
by Bernard
it looks like the characters "cmd dot exe" are banned by the forum software.
Re: Launch Persistent Shell
Posted: Fri Sep 24, 2021 5:48 pm
by studawg66
Thanks, Bernard!
I was able to make a slight modification to your suggestion and it worked like a charm!
I added the "min" flag to minimize the cmd window as soon as it launches, so that gets it out of the way and lets it do its thing.
Code: Select all
get shell("start /min x /k C:/temp/myprogram dot exe")
where x is cmd dot exe
Re: Launch Persistent Shell
Posted: Fri Sep 24, 2021 9:32 pm
by studawg66
I thought this next step would be easy but I'm struggling. How would I close out this cmd window on closing the LC application?
I tried several things in the "closeStack" routine, like:
...and some other iterations of that. But I can't seem to find a way to make it happen. Is this possible? Is there a way to pass more information to that open cmd instance after the initial "start" command has been run? Like an enter key, or an exit command?
Re: Launch Persistent Shell
Posted: Fri Sep 24, 2021 9:40 pm
by FourthWorld
In the Linux shell you can append a command with & to return control to the parent process.
I don't know the shell syntax for that on Windows, but maybe easier to just use the "open process" command with the "for neither" option.
Re: Launch Persistent Shell
Posted: Fri Sep 24, 2021 10:37 pm
by mtalluto
I have used: [start /b] to manage running extra processes. This method does not run the app in another window. It feels more like a deamon.
https://ss64.com/nt/start.html
Re: Launch Persistent Shell
Posted: Sat Sep 25, 2021 12:03 pm
by Bernard
studawg66 wrote: ↑Fri Sep 24, 2021 9:32 pm
I thought this next step would be easy but I'm struggling. How would I close out this cmd window on closing the LC application?
I tried several things in the "closeStack" routine, like:
...and some other iterations of that. But I can't seem to find a way to make it happen. Is this possible? Is there a way to pass more information to that open cmd instance after the initial "start" command has been run? Like an enter key, or an exit command?
I'm not aware of anyway to use Windows taskkill with the "title" given to a cmd-dot-exe instance. You would need the process ID to target a specific window (you could perhaps just get a list of all cmd-dot-exe PIDs and kill them all with Windows
, but that would be a very unfriendly thing to do to users of your application.
Perhaps what you need is "open process" rather than shell() -- see the LC Dictionary. Once another exe is opened via open process you can write to it/read from it then call "close process" when you have finished.
Shell() is the simple/limited way to do things. Open process is more powerful but also can be more complicated.
Re: Launch Persistent Shell
Posted: Sat Sep 25, 2021 2:04 pm
by Bill
Code: Select all
-- a file to pipe output to
put "%userprofile%/Documents/myCommand.txt" into tFile
-- set up your command window title
put quote & "MyCommandWindow" & quote into myTitle
--build your command in a string
put "start <Your_Program.exe> & title" && myTitle && "& tasklist /v /fo csv | findstr /i" && myTitle &&">>" && tFile into tCom
get shell(tCom)
Then item 2 of the file is the PID with quotes.
You probably want to set that file path up entirely with Livecode so you can access it for read directly.
Re: Launch Persistent Shell
Posted: Mon Sep 27, 2021 8:00 pm
by studawg66
Thanks for these responses! I have tried a couple of the suggestions but it is not accomplishing what I'm looking for. I think it would help if I provided more detail on what I'm doing.
I built an external executable that disables the Windows screensaver by wrapping the following python code in an exe:
Code: Select all
import ctypes
ctypes.windll.kernel32.SetThreadExecutionState(0x80000002)
input('{Screensaver has been DISABLED. Press Enter or close this window to enable it.}')
The input line was required to keep the thread open, because if the script just runs and closes the thread (returns to the prompt or closes the window), that ThreadExecutionState returns to its default value and the screensaver is enabled again.
So I have the following in Livecode in the openStack routine to run this script:
Code: Select all
get shell("start /min cmd-dot-exe /k C:/temp/SleepDisable-dot-exe")
This runs that script, keeps it active, and immediately minimizes it to get it out of the way of my Livecode GUI.
It works, but I would like to be able to clear things out when I close Livecode. Right now the only way is to close Livecode then go close that cmd window manually. Not a huge deal but if there was some way to interact with that open cmd window or to kill it, that would clean things up for the end user and not have screensavers permanently disabled by 17 open cmd windows
Ideally, I would love for Livecode to directly access that "kernel32.dll" SetThreadExecutionState function without need of this external cmd window, but I've asked that elsewhere on these forums and received no response. So if you have any ideas there, I'm all ears!
I hope this makes more sense.
Re: Launch Persistent Shell
Posted: Wed Sep 29, 2021 12:48 pm
by Bernard
Assuming you STARTed the program and set the title of that process to (say) _MyTitle_ you should be able to kill off the hidden process when you close your own app using
Code: Select all
put "_MyTitle_" into tTitle
put quote into q
shell( merge( "taskkill /FI [[q]]WINDOWTITLE eq [[tTitle]][[q]]" ) )
I just tried killing a process this way and it worked. Let us know if it doesn't work for you.
You may have to use this version:
taskkill /F /FI "WINDOWTITLE eq _MyTitle_"
where /F means "force closure".
Re: Launch Persistent Shell
Posted: Wed Sep 29, 2021 8:07 pm
by studawg66
Ah, yes. Naming the task! This worked perfectly!
To summarize, I disable the screensaver by calling my "SleepDisable.exe" program and NAME it "SleepDisable" for future, using the "/min" to minimize the window immediately, and the "/k" parameter to keep the window open, which keeps my SleepDisable function running:
Code: Select all
get shell("start /min " & quote & "SleepDisable" & quote & " cmd-dot-exe /k " & quote & myFilePath & quote)
Then, on a closeStack request, I run the following, which looks for open processes called "SleepDisable" and kills them:
Code: Select all
get shell("taskkill /FI " & quote & "WINDOWTITLE eq SleepDisable*" & quote)
Works like a charm! Thanks again for getting me on the right track.