I’m running a Shell in Interactive mode (2) to launch redis-server. When I want to stop it on the Mac, I Write ChrB( 3 ) and then wait. That’s the same as hitting ctrl-C in a terminal and it works perfectly.
Not so in Windows. I can’t figure out how to tell the server to stop and the only thing I’ve been able to do so far is to force it to quit by starting another shell and issuing taskkill /pid the_pid /f, which doesn’t give it an opportunity to cleanup and is not what I want.
It turns out I can’t do that because there may be a password of which I am unaware, so I’m back to my original question. How can I send a running shell a ctrl-C or otherwise signal it to end?
Particularly this line in some sample code on the page:
proc.StandardInput.WriteLine("\\x3");
Comment from the code snippets author: [quote](To clarify: \x3 is the hex escape sequence for the hex character 3, which is ctrl+c. It’s not just a magic number. )[/quote]
I found a solution, but I’m not marking it as an answer just yet as I’d still like to hear from an engineer.
Starting with this post, I came up with the following code based on declares:
#if TargetWindows then
declare function AttachConsole lib kWindowsLib (dbProcessId As UInt32) As Boolean
declare function GenerateConsoleCtrlEvent lib kWindowsLib (dwCtrlEvent as Int32, dwProcessGroupId As UInt32) As Boolean
if AttachConsole( PID.Val ) then
call SetConsoleCtrlHandler( nil, true )
call GenerateConsoleCtrlEvent( 0, 0 )
DoWindowsTeardown = true
end if
#else
static ctrlC as string = ChrB( 3 ).DefineEncoding( nil )
ServerShell.Write ctrlC
#endif
When the shell is being torn down, it executes this:
#if TargetWindows then
if DoWindowsTeardown then
declare function FreeConsole lib kWindowsLib () As Boolean
call SetConsoleCtrlHandler( nil, false )
call FreeConsole()
DoWindowsTeardown = false
end if
#endif
The SetConsoleCtrlHandler is defined as an external method like this:
Private Function SetConsoleCtrlHandler(handler As Ptr, add As Boolean) as Boolean
And kWindowsLib = "kernel32.dll"
Finally, PID.Val is the actual PID of my running process, not the one reported by Shell.PID. Fortunately, redis-server reports that back to me when it starts.
I have no idea if I’m doing the right thing but it certainly works the way I want it. My server is signaled to stop just as if I had pressed ctrl-C in the Terminal and cleans itself up.
<https://xojo.com/issue/52363>[/quote] @Kem Tekinay I posted a sample project on that case that works on my machine. Please try it on your machine and compare it to your code.
I will, but your comment says “I just tried this on my mac…” Did you mean you tried it on your Mac through a VM running Windows? Or that you missed that this was a Windows-specific problem?
I just looked, and it looks like the latter. I’ll update the case.