[Windows] Sending CTRL-C event to console application

Discussion in 'Python' started by Daniel Clark, Feb 8, 2007.

  1. Daniel Clark

    Daniel Clark Guest

    I have a Windows command line based application that only shuts down
    cleanly if it sees "CTRL-C" on the console. I need to automate the
    running of this application, but still allow the user sitting at the
    machine to cancel the process cleanly if he/she needs to. In Unix this
    would be a tiny shell script that used "kill -15", but under Windows
    there does not seem to be an easy way to do this, at least that I can
    find.

    Below is a test program, based on CreateProcess.py from "Python
    Programming on Win32". The
    win32api.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, pid) lines
    don't seem to do anything. What they should do is nothing in the case
    of notepad, and exit out of the dir builtin process in the case of the
    cmd.exe process.

    Any ideas on how to make this work?

    # CreateProcessDc.py
    #
    # Demo of creating two processes using the CreateProcess API,
    # then waiting for the processes to terminate.

    import win32process
    import win32event
    import win32con
    import win32api
    import time

    # Create a process specified by commandLine, and
    # The process' window should be at position rect
    # Returns the handle to the new process.
    def CreateMyProcess(commandLine, rect):
    # Create a STARTUPINFO object
    si = win32process.STARTUPINFO()
    # Set the position in the startup info.
    si.dwX, si.dwY, si.dwXSize, si.dwYSize = rect
    # And indicate which of the items are valid.
    si.dwFlags = win32process.STARTF_USEPOSITION | \
    win32process.STARTF_USESIZE
    # Set Creation Flags
    CreationFlags = win32process.CREATE_NEW_CONSOLE | \
    win32process.CREATE_NEW_PROCESS_GROUP | \
    win32process.NORMAL_PRIORITY_CLASS
    # Rest of startup info is default, so we leave it alone.
    # Create the process.
    info = win32process.CreateProcess(
    None, # AppName
    commandLine, # Command line
    None, # Process Security
    None, # ThreadSecurity
    0, # Inherit Handles?
    CreationFlags,
    None, # New environment
    None, # Current directory
    win32process.STARTUPINFO()) # startup info.
    ##si) # startup info.
    # Return the handle to the process.
    # Recall info is a tuple of (hProcess, hThread, processId,
    threadId)
    return (info[0], info[2])

    def RunEm():
    pids = []
    handles = []
    # First get the screen size to calculate layout.
    screenX = win32api.GetSystemMetrics(win32con.SM_CXSCREEN)
    screenY = win32api.GetSystemMetrics(win32con.SM_CYSCREEN)
    # First instance will be on the left hand side of the screen.
    rect = 0, 0, screenX/2, screenY
    handle, pid = CreateMyProcess("notepad", rect)
    handles.append(handle)
    pids.append(pid)
    # Second instance of Notepad will be on the right hand side.
    rect = screenX/2+1, 0, screenX/2, screenY
    cmd2 = "cmd /k dir /s/p c:\\"
    handle, pid = CreateMyProcess(cmd2, rect)
    handles.append(handle)
    pids.append(pid)

    # Now we have the processes, wait for them both
    # to terminate.
    # Rather than waiting the whole time, we loop 10 times,
    # waiting for one second each time, printing a message
    # each time around the loop
    countdown = range(1,10)
    countdown.reverse()
    for i in countdown:
    print "Waiting %d seconds for apps to close" % i
    rc = win32event.WaitForMultipleObjects(
    handles, # Objects to wait for.
    1, # Wait for them all
    1000) # timeout in milli-seconds.
    if rc == win32event.WAIT_OBJECT_0:
    # Our processes closed!
    print "Our processes closed in time."
    break
    # else just continue around the loop.
    else:
    # We didn't break out of the for loop!
    print "Giving up waiting - sending CTRL-C to processes"
    for pid in pids:
    try:
    print "Sending CTRL-C to process with pid: " +
    str(pid)

    win32api.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, pid)

    win32api.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, pid)

    win32api.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, pid)

    win32api.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, pid)

    win32api.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, pid)
    except win32api.error:
    pass
    print "Waiting 10 seconds, then going to terminate processes"
    time.sleep(10)
    print "Giving up waiting - killing processes"
    for handle in handles:
    try:
    win32process.TerminateProcess(handle, 0)
    except win32process.error:
    # This one may have already stopped.
    pass

    if __name__=='__main__':
    RunEm()
     
    Daniel Clark, Feb 8, 2007
    #1
    1. Advertising

  2. En Thu, 08 Feb 2007 15:54:05 -0300, Daniel Clark <>
    escribió:

    > I have a Windows command line based application that only shuts down
    > cleanly if it sees "CTRL-C" on the console. I need to automate the
    > running of this application, but still allow the user sitting at the
    > machine to cancel the process cleanly if he/she needs to. In Unix this
    > would be a tiny shell script that used "kill -15", but under Windows
    > there does not seem to be an easy way to do this, at least that I can
    > find.
    >
    > Below is a test program, based on CreateProcess.py from "Python
    > Programming on Win32". The
    > win32api.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, pid) lines
    > don't seem to do anything. What they should do is nothing in the case
    > of notepad, and exit out of the dir builtin process in the case of the
    > cmd.exe process.
    >
    > Any ideas on how to make this work?


    From your process creation code:

    > CreationFlags = win32process.CREATE_NEW_CONSOLE | \
    > win32process.CREATE_NEW_PROCESS_GROUP | \
    > win32process.NORMAL_PRIORITY_CLASS


    From http://msdn2.microsoft.com/en-us/library/ms683155.aspx
    "Only those processes in the group that share the same console as the
    calling process receive the signal. In other words, if a process in the
    group creates a new console, that process does not receive the signal, nor
    do its descendants."

    Maybe you have better luck on a Windows programming group, asking how to
    send a Ctrl-C event (or a SIGINT signal) to another process attached to a
    different console.

    --
    Gabriel Genellina
     
    Gabriel Genellina, Feb 9, 2007
    #2
    1. Advertising

  3. Daniel Clark

    Daniel Clark Guest

    Re: Sending CTRL-C event to console application

    On Feb 8, 9:12 pm, "Gabriel Genellina" <> wrote:
    > En Thu, 08 Feb 2007 15:54:05 -0300, Daniel Clark <>
    > escribió:
    > > I have a Windows command line based application that only shuts down
    > > cleanly if it sees "CTRL-C" on the console. I need to automate the
    > > running of this application, but still allow the user sitting at the
    > > machine to cancel the process cleanly if he/she needs to. In Unix this
    > > would be a tiny shell script that used "kill -15", but under Windows
    > > there does not seem to be an easy way to do this, at least that I can
    > > find.

    >
    > > Below is a test program, based on CreateProcess.py from "Python
    > > Programming on Win32". The
    > > win32api.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, pid) lines
    > > don't seem to do anything. What they should do is nothing in the case
    > > of notepad, and exit out of the dir builtin process in the case of the
    > > cmd.exe process.

    >
    > > Any ideas on how to make this work?

    >
    > From your process creation code:
    >
    > > CreationFlags = win32process.CREATE_NEW_CONSOLE | \
    > > win32process.CREATE_NEW_PROCESS_GROUP | \
    > > win32process.NORMAL_PRIORITY_CLASS

    >
    > Fromhttp://msdn2.microsoft.com/en-us/library/ms683155.aspx
    > "Only those processes in the group that share the same console as the
    > calling process receive the signal. In other words, if a process in the
    > group creates a new console, that process does not receive the signal, nor
    > do its descendants."


    Thanks, although I'm 99% sure I've also tried it without
    CREATE_NEW_CONSOLE (with a process that should just die if sent CTRL-
    C, so it was monitorable via Task Manager) and it still didn't work.

    I'm going to try taking a different approach by using a GUI Automation
    tool like WATSUP [1] or pywinauto[2] next.

    > Maybe you have better luck on a Windows programming group, asking how to
    > send a Ctrl-C event (or a SIGINT signal) to another process attached to a
    > different console.


    >From what I've found via Google [3], Windows has no real concept of

    signals, and no equivalent to SIGINT.

    [1] WATSUP - Windows Application Test System Using Python
    http://www.tizmoi.net/watsup/intro.html

    [2] pywinauto - Python Win32 Automation
    http://www.openqa.org/pywinauto/

    [3] how to send a SIGINT to a Python process?
    http://mail.python.org/pipermail/python-list/2005-October/343461.html
     
    Daniel Clark, Feb 9, 2007
    #3
  4. Daniel Clark

    Daniel Clark Guest

    Re: Sending CTRL-C event to console application

    On Feb 9, 9:12 am, "Daniel Clark" <> wrote:
    > I'm going to try taking a different approach by using a GUI Automation
    > tool like WATSUP [1] or pywinauto[2] next.


    This works:

    AutoIT [1] code (compiled to an executable):
    Run(@ComSpec & ' /k ' & $CmdLineRaw )
    This was necessary because other means of starting cmd.exe didn't
    actually spawn a new window. Syntax is just like:
    C:\> autoitrun.exe "cd c:\Program Files\Tivoli\TSM & dir /s/p"
    And that will pop up a new cmd.exe window with a dir /s/p listing of
    cd c:\Program Files\Tivoli\TSM

    Python code (changes service to be able to interact with desktop and
    then runs the above):

    import win32service
    import os, sys

    def EnsureInteractiveService(servicename):
    scm = win32service.OpenSCManager(None, None,
    win32service.SC_MANAGER_ALL_ACCESS)
    try:
    svc = win32service.OpenService(scm, servicename,
    win32service.SC_MANAGER_ALL_ACCESS)
    except:
    print '''Error: Couldn't open service with name "''' +
    servicename + '''"'''
    sys.exit(1)
    oldsvccfg = win32service.QueryServiceConfig(svc)
    win32service.ChangeServiceConfig(svc, # scHandle
    oldsvccfg[0] |
    win32service.SERVICE_INTERACTIVE_PROCESS, # serviceType
    oldsvccfg[1], # startType
    oldsvccfg[2], # errorControl
    oldsvccfg[3], # binaryFile
    oldsvccfg[4], # loadOrderGroup
    oldsvccfg[5], # bFetchTag
    oldsvccfg[6], # serviceDeps
    oldsvccfg[7], # acctName
    '', # password
    oldsvccfg[8]) # displayName
    win32service.CloseServiceHandle(svc)
    win32service.CloseServiceHandle(scm)

    EnsureInteractiveService("TSM for WPLC")
    os.chdir("c:\\Program Files\\WPLC-TSM\\updates")
    os.system("autoitrun.exe dir /s/p")

    [1] AutoIt v3 - Automate and Script Windows Tasks
    http://www.autoitscript.com/autoit3/
     
    Daniel Clark, Feb 9, 2007
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Terry Xie
    Replies:
    2
    Views:
    10,984
    Igor N. Kolomiyets
    Jan 29, 2004
  2. Danny

    Implement Ctrl-C, Ctrl-V

    Danny, Aug 14, 2003, in forum: C++
    Replies:
    5
    Views:
    662
    CBFalconer
    Aug 15, 2003
  3. Danny

    Implement Ctrl-C, Ctrl-V

    Danny, Aug 14, 2003, in forum: C Programming
    Replies:
    5
    Views:
    680
    CBFalconer
    Aug 15, 2003
  4. Angus
    Replies:
    5
    Views:
    2,177
    Michael Rauscher
    Nov 18, 2006
  5. Replies:
    2
    Views:
    1,441
    Munna
    Jul 10, 2008
Loading...

Share This Page