cerrar - python ventanas botones




Python-Eventos de cierre de Windows (2)

Si no tiene una consola, configurar un controlador de consola, por supuesto, no puede funcionar. Puede recibir eventos del sistema en un programa GUI (sin consola) haciendo otra ventana (no tiene que estar visible), asegurándose de que tiene una "bomba de mensaje" normal sirviendo, y manejando WM_QUERYENDSESSION - ese es el mensaje informando a su ventana sobre los eventos de apagado y cierre de sesión (y su ventana puede intentar retroceder contra la sesión final devolviendo 0 para este mensaje). ("Servicios de Windows" son diferentes de las aplicaciones normales; si eso es lo que estás escribiendo, mira un ejemplo aquí ).

Al usar win32api.setConsoleCtrlHandler (), puedo recibir eventos shutdown / logoff / etc de Windows y cerrar mi aplicación de manera limpia.

Sin embargo, esto solo funciona cuando se ejecuta la aplicación en python.exe (es decir, tiene una ventana de consola), pero no en pythonw.exe (sin ventana de consola).

¿Hay una forma equivalente en Windows para recibir estos eventos cuando no tienes consola y no hay ventana para recibirlos? O bien, ¿hay una forma programática de ocultar la ventana de la consola?

Para que quede claro, mi objetivo es poder recibir con éxito eventos de apagado / cierre de sesión / etc de Windows, sin mostrar ningún tipo de ventana de consola.

EDITAR: He estado jugando, y he ido un poco más allá. Escribí un código de prueba para esto. Cuando hago un "taskkill / im pythonw.exe" - recibirá el mensaje.

Sin embargo, cuando cierro, reinicio o cierro sesión en Windows, no recibo ningún mensaje.

Aquí está todo:

""" Testing Windows shutdown events """

import win32con
import win32api
import win32gui
import sys
import time
#import os

def log_info(msg):
    """ Prints """
    print msg
    f = open("c:\\test.log", "a")
    f.write(msg + "\n")
    f.close()

def wndproc(hwnd, msg, wparam, lparam):
    log_info("wndproc: %s" % msg)

if __name__ == "__main__":
    log_info("*** STARTING ***")
    hinst = win32api.GetModuleHandle(None)
    wndclass = win32gui.WNDCLASS()
    wndclass.hInstance = hinst
    wndclass.lpszClassName = "testWindowClass"
    messageMap = { win32con.WM_QUERYENDSESSION : wndproc,
                   win32con.WM_ENDSESSION : wndproc,
                   win32con.WM_QUIT : wndproc,
                   win32con.WM_DESTROY : wndproc,
                   win32con.WM_CLOSE : wndproc }

    wndclass.lpfnWndProc = messageMap

    try:
        myWindowClass = win32gui.RegisterClass(wndclass)
        hwnd = win32gui.CreateWindowEx(win32con.WS_EX_LEFT,
                                     myWindowClass, 
                                     "testMsgWindow", 
                                     0, 
                                     0, 
                                     0, 
                                     win32con.CW_USEDEFAULT, 
                                     win32con.CW_USEDEFAULT, 
                                     win32con.HWND_MESSAGE, 
                                     0, 
                                     hinst, 
                                     None)
    except Exception, e:
        log_info("Exception: %s" % str(e))


    if hwnd is None:
        log_info("hwnd is none!")
    else:
        log_info("hwnd: %s" % hwnd)

    while True:
        win32gui.PumpWaitingMessages()
        time.sleep(1)

Siento que estoy bastante cerca de aquí, ¡pero definitivamente me falta algo!


El problema aquí era que el tipo de ventana HWND_MESSAGE en realidad no recibe mensajes de difusión, como WM_QUERYENDSESSION y WM_ENDSESSION.

Entonces, en lugar de especificar win32con.HWND_MESSAGE para el parámetro "ventana principal" de CreateWindowEx (), solo especifiqué "0".

Básicamente, esto crea una ventana real, pero nunca la muestro, así que efectivamente es lo mismo. Ahora, puedo recibir con éxito esos mensajes de difusión y cerrar la aplicación correctamente.





windows