拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 【Python GUI 视窗句柄定位】——使用鼠标指标定位视窗句柄并获得对应的程序属性值,针对流氓软件绰绰有余

【Python GUI 视窗句柄定位】——使用鼠标指标定位视窗句柄并获得对应的程序属性值,针对流氓软件绰绰有余

白鹭 - 2022-02-14 1994 0 0

GUI视窗 使用鼠标指标进行定位程序,获得程序的视窗句柄、视窗类名、视窗标题、执行绪ID、行程ID、行程名称、行程路径、CPU用量、执行绪数、视窗定位及鼠标坐标,并附加五项可操作控制元件,强制置顶、取消置顶、显示顶部、前置终止、打开档案所在位置,可显示定位程序的图示,

pip install 模块名

pip install -U 模块名

import tkinter
from tkinter import *
from tkinter.ttk import *
import win32api
import win32gui
import win32con
import win32ui
import time
from win32 import win32process
import psutil
import subprocess
from PIL import Image
import os

基本的GUI界面,程序的图示可要可不要,也可以自己去制作

root = Tk()
root.title('贱工坊-视窗句柄')  # 程序的标题名称
root.geometry("480x320+512+288")  # 视窗的大小及页面的显示位置
root.resizable(False, False)  # 固定页面不可放大缩小
root.iconbitmap("picture.ico")  # 程序的图示

在程序里创建画布改变颜色,添加图片,这个图片是圆形图示

    canvas = tkinter.Canvas(root, bg="#ebebeb", height=400, width=700, borderwidth=-3)  # 创建画布
    canvas.pack(side='top')  # 放置画布(为上端)

    canvas_2 = tkinter.Canvas(root, bg="#ebebeb",cursor='target', height=50, width=50, borderwidth=-2)  # 创建画布
    canvas_2.place(x=402, y=70)  # 放置画布(为上端)
    image_file = tkinter.PhotoImage(file="./Key.png")  # 加载图片档案
    canvas_2.create_image(0, 0, anchor='nw', image=image_file)  # 将图片置于画布上

在程序里添加文本框,用来放置资料

    # 配置视窗句柄
    var_hwnd = tkinter.StringVar()
    tkinter.Entry(root, width=20,borderwidth=1,bg='#ebebeb',textvariable=var_hwnd).place(x=70,y=10)

    # 配置标题名称
    var_title = tkinter.StringVar()
    tkinter.Entry(root, width=54, borderwidth=1,bg='#ebebeb', textvariable=var_title).place(x=70, y=40)

    # 配置视窗类名
    var_clsname = tkinter.StringVar()
    tkinter.Entry(root, width=20, borderwidth=1, bg='#ebebeb', textvariable=var_clsname).place(x=306, y=10)

    # 配置执行绪ID
    var_hread_id = tkinter.StringVar()
    tkinter.Entry(root, width=10, borderwidth=1, bg='#ebebeb', textvariable=var_hread_id).place(x=70, y=70)

    # 配置行程ID
    var_process_id = tkinter.StringVar()
    tkinter.Entry(root, width=10, borderwidth=1, bg='#ebebeb', textvariable=var_process_id).place(x=204, y=70)

    # 配置程序名称
    var_process = tkinter.StringVar()
    tkinter.Entry(root, width=29, borderwidth=1, bg='#ebebeb', textvariable=var_process).place(x=70, y=100)

    # 配置程序路径
    var_p_bin = tkinter.StringVar()
    tkinter.Entry(root, width=54, borderwidth=1, bg='#ebebeb', textvariable=var_p_bin).place(x=70, y=130)

    # 配置CPU利用率
    var_mem_percent = tkinter.StringVar()
    tkinter.Entry(root, width=20, borderwidth=1, bg='#ebebeb', textvariable=var_mem_percent).place(x=70, y=160)

    # 配置执行绪数
    var_num_threads = tkinter.StringVar()
    tkinter.Entry(root, width=20, borderwidth=1, bg='#ebebeb', textvariable=var_num_threads).place(x=306, y=160)

    # 配置视窗左上
    var_top = tkinter.StringVar()
    tkinter.Entry(root, width=6, borderwidth=1, bg='#ebebeb', textvariable=var_top).place(x=70, y=190)

    # 配置视窗左下
    var_left = tkinter.StringVar()
    tkinter.Entry(root, width=6, borderwidth=1, bg='#ebebeb', textvariable=var_left).place(x=70, y=220)

    # 配置视窗右上
    var_right = tkinter.StringVar()
    tkinter.Entry(root, width=6, borderwidth=1, bg='#ebebeb', textvariable=var_right).place(x=194, y=190)

    # 配置视窗右下
    var_bottom = tkinter.StringVar()
    tkinter.Entry(root, width=6, borderwidth=1, bg='#ebebeb', textvariable=var_bottom).place(x=194, y=220)

    # 配置坐标x,y
    var_point = tkinter.StringVar()
    tkinter.Entry(root, width=24, borderwidth=1, bg='#ebebeb', textvariable=var_point).place(x=70, y=250)

程序添加标签,用来标注

        tkinter.Label(canvas, bg="#ebebeb", text='视窗句柄').place(x=10, y=8)
        tkinter.Label(canvas, bg="#ebebeb", text='视窗标题').place(x=10, y=38)
        tkinter.Label(canvas, bg="#ebebeb", text='视窗类名').place(x=248, y=8)
        tkinter.Label(canvas, bg="#ebebeb", text='执行绪ID').place(x=10, y=68)
        tkinter.Label(canvas, bg="#ebebeb", text='行程ID').place(x=154, y=68)
        tkinter.Label(canvas, bg="#ebebeb", text='行程名称').place(x=10, y=98)
        tkinter.Label(canvas, bg="#ebebeb", text='行程路径').place(x=10, y=128)
        tkinter.Label(canvas, bg="#ebebeb", text='CPU用量').place(x=10, y=158)
        tkinter.Label(canvas, bg="#ebebeb", text='执行绪数').place(x=258, y=158)
        tkinter.Label(canvas, bg="#ebebeb", text='视窗左上').place(x=10, y=188)
        tkinter.Label(canvas, bg="#ebebeb", text='视窗左下').place(x=10, y=218)
        tkinter.Label(canvas, bg="#ebebeb", text='视窗右上').place(x=134, y=188)
        tkinter.Label(canvas, bg="#ebebeb", text='视窗右下').place(x=134, y=218)
        tkinter.Label(canvas, bg="#ebebeb", text='坐标x,y').place(x=10, y=248)

程序内放置一个CSDN博主二维码,直达博主主页,图片的尺寸是 200x80 ,二维码由博主制作,内置为博主的主页链接

    # 放置二维码
    canvas_4 = tkinter.Canvas(root, bg="red", height=80, width=200, borderwidth=-2)
    canvas_4.place(x=250, y=190)
    image_file_4 = tkinter.PhotoImage(file="./share.png")  # 加载图片档案
    canvas_4.create_image(0, 0, anchor='nw', image=image_file_4)  # 将图片置于画布上

获取鼠标的坐标,通过坐标获取视窗句柄,然后通过句柄获取视窗标题、视窗类名、执行绪ID、行程ID和视窗坐标,然后通过行程ID获取程序名称、程序路径、CUP用量和执行绪数,通程序式路径获取软件图示,这里关联着鼠标的bind <B1-Motion>左键持续移动,只要鼠标左键持续移动则会执行如下代码,动一下执行一次

            point = win32api.GetCursorPos()  # 鼠标位置
            hwnd = win32gui.WindowFromPoint(point)   # 视窗句柄
            title = win32gui.GetWindowText(hwnd)    # 视窗标题
            clsname = win32gui.GetClassName(hwnd)   # 视窗类名
            hread_id, process_id = win32process.GetWindowThreadProcessId(hwnd)  #执行绪ID  行程ID
            process = psutil.Process(process_id)     # 程序名称  通过行程ID获取
            p_bin = psutil.Process(process_id).exe()   # 程序路径  通过行程ID获取
            mem_percent = psutil.Process(process_id).memory_percent()   # CPU利用率  通过行程ID获取
            num_threads = psutil.Process(process_id).num_threads()     # 执行绪数  通过行程ID获取
            left, top, right, bottom = win32gui.GetWindowRect(hwnd)   #视窗坐标  通过视窗句柄获取 四个角的坐标
            picture()    # 更换软件图示
            ICON(p_bin)  # 获取软件图示
            var_hwnd.set(hwnd)
            var_title.set(title)
            var_clsname.set(clsname)
            var_hread_id.set(hread_id)
            var_process_id.set(process_id)
            var_process.set(process.name())
            var_p_bin.set(p_bin)
            var_mem_percent.set(mem_percent)
            var_num_threads.set(num_threads)
            var_left.set(left)
            var_top.set(top)
            var_right.set(right)
            var_bottom.set(bottom)
            var_point.set(point)

这个代码的用处是用来获取软件的图示,通过路径获取,并持续保存替换 icon.png 图片

# 获取软件图示
    def ICON(exePath2):
        try:
            exePath = exePath2.replace("\\", "/")  # 替换
            large, small = win32gui.ExtractIconEx(f'{exePath}', 0)
            useIcon = large[0]
            destroyIcon = small[0]
            win32gui.DestroyIcon(destroyIcon)
            hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
            hbmp = win32ui.CreateBitmap()
            hbmp.CreateCompatibleBitmap(hdc, ico_x, ico_x)
            hdc = hdc.CreateCompatibleDC()
            hdc.SelectObject(hbmp)
            hdc.DrawIcon((0, 0), useIcon)
            bmpstr = hbmp.GetBitmapBits(True)
            img = Image.frombuffer(
                'RGBA',
                (32, 32),
                bmpstr, 'raw', 'BGRA', 0, 1
            )
            img.save('icon.png')
        except:
            pass

将保存好扽图片进行加载进来,pictures.png 是软件的默认图示,而 icon.png 则是保存下来的图示进行替换,所以指标指向哪里就会替换为哪一个软件的图示,原理就是这样,只是有一部分的软件图示获取不了或使用不了,会造成软件内图示变白

    image_file_3 = tkinter.PhotoImage(file="pictures.png")  # 软件第一次打开时要呈现的图片
    Button_2 = Button(canvas_3,image=image_file_3).place(x=0, y=0)
    # 更换软件图示
    def picture():
        try:
            image_file_3.config(file='icon.png')   # 替换
        except:
            pass

这是能获取到图示的

这是获取不到图示或使用不了图示的,只有绝少部分获取不到或使用不了,不影响软件的使用,

下面的是按钮所对应的函式控制元件,用来置顶、取消置顶、显示顶部、终止程序和打开档案所在位置,这里要注意的是我采用的taskkill 计算机自带的终止指令,可以不会支持win7以下的计算机命令,还有就是我这个终止命令会把程序的子程序也终止掉,所以尽量不要去尝试终止档案夹和桌面之类的,如果终止掉了荧屏会全白,可以使用【ctrl+alt+delete】进入任务管理器,新建任务,explorer 回车即可恢复,但是有可能你的资料都会被强行关闭,

    # 置顶 通过句柄
    def set_top():
        try:
            win32gui.SetWindowPos(var_hwnd.get(), win32con.HWND_TOPMOST, 0, 0, 0, 0,win32con.SWP_NOMOVE | win32con.SWP_NOACTIVATE | win32con.SWP_NOOWNERZORDER | win32con.SWP_SHOWWINDOW | win32con.SWP_NOSIZE)
        except:
            pass
    # 取消置顶 通过句柄
    def set_down():
        try:
            win32gui.SetWindowPos(var_hwnd.get(), win32con.HWND_NOTOPMOST, 0, 0, 0, 0,win32con.SWP_SHOWWINDOW | win32con.SWP_NOSIZE | win32con.SWP_NOMOVE)
        except:
            pass
    # 显示在顶部 通过句柄
    def set_yop_p():
        try:
            win32gui.SetForegroundWindow(var_hwnd.get())
        except:
            pass

    # 终止程序
    def kill():
        try:
            subprocess.Popen("taskkill /F /T /PID " + var_process_id.get(), shell=True)
            subprocess.Popen("taskkill /F /T /IM " + process.get(), shell=True)
        except:
            pass

    # 打开档案夹
    def bin():
        pbin = var_p_bin.get().replace("\\", "/")  # 替换
        pbin = os.path.split(pbin)[0].replace("\\", "/")
        os.startfile(str(pbin))

按钮控制元件

    Button(root, text='强制置顶',   command=set_top).place(x=10, y=280)
    Button(root, text='取消置顶', command=set_down).place(x=100, y=280)
    Button(root, text='显示顶部', command=set_yop_p).place(x=190, y=280)
    Button(root, text='强制终止', command=kill).place(x=280, y=280)
    Button(root, text='打开档案所在位置', command=bin).place(x=370, y=280)

这个是最关键的,只有这个控制元件才能起到指标移动是执行命令,canvas_2 指的是在 canvas_2的画布下可以使用,<B1-Motion> 指的是鼠标左键并移动 待触发控制元件,showMenu 指的是要执行的命令函式,

# 鼠标移动控制元件
    canvas_2.bind("<B1-Motion>", showMenu)

废话不多说,上代码,

运行不成功的可以要注意,是不是没有图片,最上方有数据链接,里面包括图片和源档案,可以免费下载,代码都不用复制了

完整代码:

import tkinter
from tkinter import *
from tkinter.ttk import *
import win32api
import win32gui
import win32con
import win32ui
import time
from win32 import win32process
import psutil
import subprocess
from PIL import Image
import os

def main():
    root = Tk()
    root.title('贱工坊-视窗句柄')  # 程序的标题名称
    root.geometry("480x320+512+288")  # 视窗的大小及页面的显示位置
    root.resizable(False, False)  # 固定页面不可放大缩小
    root.iconbitmap("picture.ico")  # 程序的图示

    canvas = tkinter.Canvas(root, bg="#ebebeb", height=400, width=700, borderwidth=-3)  # 创建画布
    canvas.pack(side='top')  # 放置画布(为上端)

    canvas_2 = tkinter.Canvas(root, bg="#ebebeb",cursor='target', height=50, width=50, borderwidth=-2)  # 创建画布
    canvas_2.place(x=402, y=70)  # 放置画布(为上端)
    image_file = tkinter.PhotoImage(file="./Key.png")  # 加载图片档案
    canvas_2.create_image(0, 0, anchor='nw', image=image_file)  # 将图片置于画布上

    canvas_3 = tkinter.Canvas(root, bg="red",  height=40, width=40, borderwidth=-2)  # 创建画布
    canvas_3.place(x=332, y=74)  # 放置画布(为上端)


    # 配置视窗句柄
    var_hwnd = tkinter.StringVar()
    tkinter.Entry(root, width=20,borderwidth=1,bg='#ebebeb',textvariable=var_hwnd).place(x=70,y=10)

    # 配置标题名称
    var_title = tkinter.StringVar()
    tkinter.Entry(root, width=54, borderwidth=1,bg='#ebebeb', textvariable=var_title).place(x=70, y=40)

    # 配置视窗类名
    var_clsname = tkinter.StringVar()
    tkinter.Entry(root, width=20, borderwidth=1, bg='#ebebeb', textvariable=var_clsname).place(x=306, y=10)

    # 配置执行绪ID
    var_hread_id = tkinter.StringVar()
    tkinter.Entry(root, width=10, borderwidth=1, bg='#ebebeb', textvariable=var_hread_id).place(x=70, y=70)

    # 配置行程ID
    var_process_id = tkinter.StringVar()
    tkinter.Entry(root, width=10, borderwidth=1, bg='#ebebeb', textvariable=var_process_id).place(x=204, y=70)

    # 配置程序名称
    var_process = tkinter.StringVar()
    tkinter.Entry(root, width=29, borderwidth=1, bg='#ebebeb', textvariable=var_process).place(x=70, y=100)

    # 配置程序路径
    var_p_bin = tkinter.StringVar()
    tkinter.Entry(root, width=54, borderwidth=1, bg='#ebebeb', textvariable=var_p_bin).place(x=70, y=130)

    # 配置CPU利用率
    var_mem_percent = tkinter.StringVar()
    tkinter.Entry(root, width=20, borderwidth=1, bg='#ebebeb', textvariable=var_mem_percent).place(x=70, y=160)

    # 配置执行绪数
    var_num_threads = tkinter.StringVar()
    tkinter.Entry(root, width=20, borderwidth=1, bg='#ebebeb', textvariable=var_num_threads).place(x=306, y=160)

    # 配置视窗左上
    var_top = tkinter.StringVar()
    tkinter.Entry(root, width=6, borderwidth=1, bg='#ebebeb', textvariable=var_top).place(x=70, y=190)

    # 配置视窗左下
    var_left = tkinter.StringVar()
    tkinter.Entry(root, width=6, borderwidth=1, bg='#ebebeb', textvariable=var_left).place(x=70, y=220)

    # 配置视窗右上
    var_right = tkinter.StringVar()
    tkinter.Entry(root, width=6, borderwidth=1, bg='#ebebeb', textvariable=var_right).place(x=194, y=190)

    # 配置视窗右下
    var_bottom = tkinter.StringVar()
    tkinter.Entry(root, width=6, borderwidth=1, bg='#ebebeb', textvariable=var_bottom).place(x=194, y=220)

    # 配置坐标x,y
    var_point = tkinter.StringVar()
    tkinter.Entry(root, width=24, borderwidth=1, bg='#ebebeb', textvariable=var_point).place(x=70, y=250)

    image_file_3 = tkinter.PhotoImage(file="pictures.png")  # 软件第一次打开时要呈现的图片
    Button_2 = Button(canvas_3, image=image_file_3).place(x=0, y=0)
    # 更换软件图示
    def picture():
        try:
            image_file_3.config(file='icon.png')   # 替换
        except:
            pass
    # 图示尺寸
    ico_x = 32
    # 获取软件图示
    def ICON(exePath2):
        try:
            exePath = exePath2.replace("\\", "/")  # 替换
            large, small = win32gui.ExtractIconEx(f'{exePath}', 0)
            useIcon = large[0]
            destroyIcon = small[0]
            win32gui.DestroyIcon(destroyIcon)
            hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
            hbmp = win32ui.CreateBitmap()
            hbmp.CreateCompatibleBitmap(hdc, ico_x, ico_x)
            hdc = hdc.CreateCompatibleDC()
            hdc.SelectObject(hbmp)
            hdc.DrawIcon((0, 0), useIcon)
            bmpstr = hbmp.GetBitmapBits(True)
            img = Image.frombuffer(
                'RGBA',
                (32, 32),
                bmpstr, 'raw', 'BGRA', 0, 1
            )
            img.save('icon.png')
        except:
            pass


    # 通过鼠标移动获取函式
    def showMenu(event):
        try:
            point = win32api.GetCursorPos()  # 鼠标位置
            hwnd = win32gui.WindowFromPoint(point)   # 视窗句柄
            title = win32gui.GetWindowText(hwnd)    # 视窗标题
            clsname = win32gui.GetClassName(hwnd)   # 视窗类名
            hread_id, process_id = win32process.GetWindowThreadProcessId(hwnd)  #执行绪ID  行程ID
            process = psutil.Process(process_id)     # 程序名称  通过行程ID获取
            p_bin = psutil.Process(process_id).exe()   # 程序路径  通过行程ID获取
            mem_percent = psutil.Process(process_id).memory_percent()   # CPU利用率  通过行程ID获取
            num_threads = psutil.Process(process_id).num_threads()     # 执行绪数  通过行程ID获取
            left, top, right, bottom = win32gui.GetWindowRect(hwnd)   #视窗坐标  通过视窗句柄获取 四个角的坐标
            picture()    # 更换软件图示
            ICON(p_bin)  # 获取软件图示
            var_hwnd.set(hwnd)
            var_title.set(title)
            var_clsname.set(clsname)
            var_hread_id.set(hread_id)
            var_process_id.set(process_id)
            var_process.set(process.name())
            var_p_bin.set(p_bin)
            var_mem_percent.set(mem_percent)
            var_num_threads.set(num_threads)
            var_left.set(left)
            var_top.set(top)
            var_right.set(right)
            var_bottom.set(bottom)
            var_point.set(point)
        except:
            pass

    # 置顶 通过句柄
    def set_top():
        try:
            win32gui.SetWindowPos(var_hwnd.get(), win32con.HWND_TOPMOST, 0, 0, 0, 0,win32con.SWP_NOMOVE | win32con.SWP_NOACTIVATE | win32con.SWP_NOOWNERZORDER | win32con.SWP_SHOWWINDOW | win32con.SWP_NOSIZE)
        except:
            pass
    # 取消置顶 通过句柄
    def set_down():
        try:
            win32gui.SetWindowPos(var_hwnd.get(), win32con.HWND_NOTOPMOST, 0, 0, 0, 0,win32con.SWP_SHOWWINDOW | win32con.SWP_NOSIZE | win32con.SWP_NOMOVE)
        except:
            pass
    # 显示在顶部 通过句柄
    def set_yop_p():
        try:
            win32gui.SetForegroundWindow(var_hwnd.get())
        except:
            pass

    # 终止程序
    def kill():
        try:
            subprocess.Popen("taskkill /F /T /PID " + var_process_id.get(), shell=True)
            subprocess.Popen("taskkill /F /T /IM " + process.get(), shell=True)
        except:
            pass

    # 打开档案夹
    def bin():
        pbin = var_p_bin.get().replace("\\", "/")  # 替换
        pbin = os.path.split(pbin)[0].replace("\\", "/")
        os.startfile(str(pbin))

    def Label():
        # 标签
        tkinter.Label(canvas, bg="#ebebeb", text='视窗句柄').place(x=10, y=8)
        tkinter.Label(canvas, bg="#ebebeb", text='视窗标题').place(x=10, y=38)
        tkinter.Label(canvas, bg="#ebebeb", text='视窗类名').place(x=248, y=8)
        tkinter.Label(canvas, bg="#ebebeb", text='执行绪ID').place(x=10, y=68)
        tkinter.Label(canvas, bg="#ebebeb", text='行程ID').place(x=154, y=68)
        tkinter.Label(canvas, bg="#ebebeb", text='行程名称').place(x=10, y=98)
        tkinter.Label(canvas, bg="#ebebeb", text='行程路径').place(x=10, y=128)
        tkinter.Label(canvas, bg="#ebebeb", text='CPU用量').place(x=10, y=158)
        tkinter.Label(canvas, bg="#ebebeb", text='执行绪数').place(x=258, y=158)
        tkinter.Label(canvas, bg="#ebebeb", text='视窗左上').place(x=10, y=188)
        tkinter.Label(canvas, bg="#ebebeb", text='视窗左下').place(x=10, y=218)
        tkinter.Label(canvas, bg="#ebebeb", text='视窗右上').place(x=134, y=188)
        tkinter.Label(canvas, bg="#ebebeb", text='视窗右下').place(x=134, y=218)
        tkinter.Label(canvas, bg="#ebebeb", text='坐标x,y').place(x=10, y=248)

    # 鼠标移动控制元件
    canvas_2.bind("<B1-Motion>", showMenu)
    Button(root, text='强制置顶',   command=set_top).place(x=10, y=280)
    Button(root, text='取消置顶', command=set_down).place(x=100, y=280)
    Button(root, text='显示顶部', command=set_yop_p).place(x=190, y=280)
    Button(root, text='强制终止', command=kill).place(x=280, y=280)
    Button(root, text='打开档案所在位置', command=bin).place(x=370, y=280)

    # 放置二维码
    canvas_4 = tkinter.Canvas(root, bg="red", height=80, width=200, borderwidth=-2)
    canvas_4.place(x=250, y=190)
    image_file_4 = tkinter.PhotoImage(file="./share.png")  # 加载图片档案
    canvas_4.create_image(0, 0, anchor='nw', image=image_file_4)  # 将图片置于画布上

    Label()
    root.mainloop() #运行

if __name__ == '__main__':
    main()

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *