简体   繁体   中英

Is it possible to get the foreground window from a system tray app in windows using python pywin32?

I am using the pywin32's demo win32gui_taskbar.py & extending it to take a screen shot of the window if a particular window is currently the active/foreground window. The screen_shot function is called whenever the user left click's on the system tray icon

import win32api, win32service
import win32gui, win32ui
import win32con, winerror
import sys, os
import time
from PIL import Image

class MainWindow:
    def __init__(self):
        msg_TaskbarRestart = win32gui.RegisterWindowMessage("TaskbarCreated");
        message_map = {
                msg_TaskbarRestart: self.OnRestart,
                win32con.WM_DESTROY: self.OnDestroy,
                win32con.WM_COMMAND: self.OnCommand,
                win32con.WM_USER+20 : self.OnTaskbarNotify,
        }
        # Register the Window class.
        wc = win32gui.WNDCLASS()
        hinst = wc.hInstance = win32api.GetModuleHandle(None)
        wc.lpszClassName = "PythonTaskbarDemo"
        wc.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW;
        wc.hCursor = win32api.LoadCursor( 0, win32con.IDC_ARROW )
        wc.hbrBackground = win32con.COLOR_WINDOW
        wc.lpfnWndProc = message_map # could also specify a wndproc.

        # Don't blow up if class already registered to make testing easier
        try:
            classAtom = win32gui.RegisterClass(wc)
        except win32gui.error, err_info:
            if err_info.winerror!=winerror.ERROR_CLASS_ALREADY_EXISTS:
                raise

        # Create the Window.
        style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
        self.hwnd = win32gui.CreateWindow( wc.lpszClassName, "Taskbar Demo", style, \
                0, 0, win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT, \
                0, 0, hinst, None)
        win32gui.UpdateWindow(self.hwnd)
        self._DoCreateIcons()
    def _DoCreateIcons(self):
        # Try and find a custom icon
        hinst =  win32api.GetModuleHandle(None)
        iconPathName = os.path.abspath(os.path.join( os.path.split(sys.executable)[0], "pyc.ico" ))
        if not os.path.isfile(iconPathName):
            # Look in DLLs dir, a-la py 2.5
            iconPathName = os.path.abspath(os.path.join( os.path.split(sys.executable)[0], "DLLs", 

"pyc.ico" ))
        if not os.path.isfile(iconPathName):
            # Look in the source tree.
            iconPathName = os.path.abspath(os.path.join( os.path.split(sys.executable)[0], "..\\PC\

\pyc.ico" ))
        if os.path.isfile(iconPathName):
            icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE
            hicon = win32gui.LoadImage(hinst, iconPathName, win32con.IMAGE_ICON, 0, 0, icon_flags)
        else:
            print "Can't find a Python icon file - using default"
            hicon = win32gui.LoadIcon(0, win32con.IDI_APPLICATION)

        flags = win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP
        nid = (self.hwnd, 0, flags, win32con.WM_USER+20, hicon, "Python Demo")
        try:
            win32gui.Shell_NotifyIcon(win32gui.NIM_ADD, nid)
        except win32gui.error:
            # This is common when windows is starting, and this code is hit
            # before the taskbar has been created.
            print "Failed to add the taskbar icon - is explorer running?"
            # but keep running anyway - when explorer starts, we get the
            # TaskbarCreated message.

    def OnRestart(self, hwnd, msg, wparam, lparam):
    print "In onrestart"
        self._DoCreateIcons()

    def OnDestroy(self, hwnd, msg, wparam, lparam):
        nid = (self.hwnd, 0)
        win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, nid)
        win32gui.PostQuitMessage(0) # Terminate the app.

    def OnTaskbarNotify(self, hwnd, msg, wparam, lparam):
        if lparam==win32con.WM_LBUTTONUP:
            print "You clicked me."            
            print win32gui.GetWindowText(hwnd)
            print ".." + win32gui.GetWindowText(win32gui.GetForegroundWindow()) 
            self.screen_shoot()
        elif lparam==win32con.WM_LBUTTONDBLCLK:
            print "You double-clicked me - goodbye"
            win32gui.DestroyWindow(self.hwnd)
        elif lparam==win32con.WM_RBUTTONUP:
            print "You right clicked me."            
        return 1

    def screen_shot(self):
        wndh = win32gui.GetForegroundWindow()   
    if "Notepad" in win32gui.GetWindowText(wndh):
            print "Inside if"
            hwndDC = win32gui.GetWindowDC(wndh)
            mfcDC  = win32ui.CreateDCFromHandle(hwndDC)
            saveDC = mfcDC.CreateCompatibleDC()
            saveBitMap = win32ui.CreateBitmap()
            left, top, right, bot = win32gui.GetWindowRect(wndh)
            w = right - left
            h = bot - top
            saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)
            saveDC.SelectObject(saveBitMap)
            saveDC.BitBlt((0, 0), (w, h),  mfcDC,  (0, 0),  win32con.SRCCOPY)
        bmpinfo = saveBitMap.GetInfo()
            bmpstr = saveBitMap.GetBitmapBits(True)
            im = Image.frombuffer('RGB', (bmpinfo['bmWidth'],
                                          bmpinfo['bmHeight']),
                                          bmpstr, 'raw', 'BGRX', 0, 1)
        win32gui.DeleteObject(saveBitMap.GetHandle())
            saveDC.DeleteDC()
            mfcDC.DeleteDC()
            win32gui.ReleaseDC(wndh, hwndDC)
            im.save("c:\screenshot" + str(int(time.time())) + ".png")


    def OnCommand(self, hwnd, msg, wparam, lparam):
        id = win32api.LOWORD(wparam)
        if id == 1023:
            import win32gui_dialog
            win32gui_dialog.DemoModal()
        elif id == 1024:
            print "Hello"
        elif id == 1025:
            print "Goodbye"
            win32gui.DestroyWindow(self.hwnd)
        else:
            print "Unknown command -", id

def main():
    w=MainWindow()
    win32gui.PumpMessages()

if __name__=='__main__':
    main()

In the above code the control never goes inside the if condition in the screen_shot function. How can get this program working? The same screen shot logic works fine when its run as a normal application.

Answering own question... Just realised task bar is also another "window" & upon clicking the system tray icon the focus is shifted to the task window. Which is what is reported as the foreground window & get window text for this window is blank string. I verified this by slightly modifying my program. In the MainWindow class init function after the win32gui.Shell_NotifyIcon(win32gui.NIM_ADD, nid) icon init call added the following code to verify it

while True:
    time.sleep(0.1)
    wndh = win32gui.GetForegroundWindow()   
    print "windowndh" + str(wndh)
    if "Notepad" in win32gui.GetWindowText(wndh):
        # Take screen shot
        print "Inside if"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM