前言
有一次我服務(wù)器中招了頻繁的彈出重啟對話框并重啟的事情(進(jìn)入安全模式?jīng)]有找到和啟動此命令有關(guān)的程序),我不得不在有限的時間里嘗試找到此進(jìn)程并Kill掉它,使用pchunter和process monitor均沒有在有限的時間內(nèi)找到正確的進(jìn)程,后來發(fā)現(xiàn)好像也沒有類似的小工具,于是絕對自己寫一個。
? windows的朋友都知道對于windows來說最重要的兩個系統(tǒng)API庫就是kernel32.dll和user32.dll,kernel32.dll主要是和內(nèi)核交互我們此時用不到,user32.dll主要是處理windows用戶界面的api庫,正是我們需要的。于是我找到了user32.dll的庫開發(fā)文檔,打算用golang寫一個小工具。
2000 years later...
放棄了,不是windows開發(fā)者,看user32.dll還是短時間存在一定困難,且golang沒有相關(guān)的調(diào)用庫,直接load user32.dll感覺是找麻煩。此時又想起python大法,發(fā)現(xiàn)python最優(yōu)秀的地方就是庫太多了,存在pywin32這么個庫來轉(zhuǎn)接windows的API。
需求
快速開發(fā)一個應(yīng)急小程序,可以鼠標(biāo)點點點查看窗體程序的進(jìn)程號
再快速一點
設(shè)計實現(xiàn)
考慮把大象放冰箱鼠標(biāo)點擊一下就能查看窗體的進(jìn)程號分幾步:
獲取點擊時鼠標(biāo)坐標(biāo)
獲取鼠標(biāo)點擊位置窗口句柄
獲取窗口標(biāo)題的函數(shù)和進(jìn)程號
監(jiān)聽鼠標(biāo)按鍵事件觸發(fā)上述過程
pywin32的函數(shù)命名和user32.dll的庫函數(shù)名字是類似的,于是我直接在pywin32的開發(fā)文檔里面搜索CursorPos發(fā)現(xiàn)存在win32gui.GetCursorPos()函數(shù)獲取鼠標(biāo)坐標(biāo),操作很簡單
from win32 import win32gui
point =win32gui.GetCursorPos()#point為鼠標(biāo)坐標(biāo)
對照User32的開發(fā)文檔和pywin32的開發(fā)文檔搜索出獲取窗口句柄的函數(shù)、窗口標(biāo)題、和窗口進(jìn)程的函數(shù)
from win32 import win32gui,win32process
win32gui.WindowFromPoint()#獲取當(dāng)前窗口句柄
win32gui.GetWindowText()#獲取當(dāng)前窗口標(biāo)題
win32process.GetWindowThreadProcessId() #獲取當(dāng)前窗口進(jìn)程和線程
搜索pywin32關(guān)于mouse和CursorPos,沒有發(fā)現(xiàn)有關(guān)于鼠標(biāo)監(jiān)聽的函數(shù),只搜到win32gui._TrackMouseEvent,我們知道“_”開頭的函數(shù)一般是內(nèi)部函數(shù)能用也不好用。要不怎么說python大法好呢,隨便搜索下得知pynput庫可以監(jiān)聽鼠標(biāo)鍵盤事件,官方Demo代碼足以。
最后實現(xiàn)我們的demo代碼
from win32 import win32gui,win32process
from pynput.mouse import Listener,Button
while True:
#官方鼠標(biāo)監(jiān)聽Demo代碼
def on_click(x, y,button,pressed):
if not pressed:
return False
with Listener( on_click=on_click,on_scroll=on_scroll) as listener:
listener.join()
point =win32gui.GetCursorPos()#獲取鼠標(biāo)坐標(biāo)
p=win32gui.WindowFromPoint(point)#獲取鼠標(biāo)坐標(biāo)位置窗口句柄
p_name=win32gui.GetWindowText(p)#獲取窗口句柄對應(yīng)的進(jìn)程名
_,p_id=win32process.GetWindowThreadProcessId(p)#獲取窗口句柄對應(yīng)的PID
print(p_name,p_id)
執(zhí)行Python xxx.py 測試沒問題,然而pyinstaller打包失敗,Pynput無法打包成pyd,作為應(yīng)急使用,就不研究為啥打包失敗了,考慮類似win32gui._TrackMouseEvent實現(xiàn),我們可以利用Sleep函數(shù)自己簡單實現(xiàn)鼠標(biāo)懸停效果,都沒10行代碼就解決問題。
from win32 import win32gui,win32process
import time
while True:
point1 =win32gui.GetCursorPos()#獲取鼠標(biāo)坐標(biāo)
time.sleep(2)#模擬鼠標(biāo)兩秒懸停
point2 =win32gui.GetCursorPos()#獲取鼠標(biāo)坐標(biāo)
if point2 == point1:
p=win32gui.WindowFromPoint(point2)#獲取鼠標(biāo)坐標(biāo)位置窗口句柄
p_name=win32gui.GetWindowText(p)#獲取窗口句柄對應(yīng)的進(jìn)程名
_,p_id=win32process.GetWindowThreadProcessId(p)#獲取窗口句柄對應(yīng)的PID
print(p_name,p_id)
測試python xxx.py執(zhí)行成功,pyinstaller打包測試成功。
代碼實現(xiàn)
代碼量不多,調(diào)整下格式即可:
#coding=utf-8
#date 2020.12.23
#depand:python3.8,win32
#描述:鼠標(biāo)懸停窗體2秒輸出進(jìn)程名和PID
from win32 import win32gui,win32process
import time
import sys
def get_PID(point):
try:
p=win32gui.WindowFromPoint(point)
p_name=win32gui.GetWindowText(p)
_,p_id=win32process.GetWindowThreadProcessId(p)
print(p_name,p_id)
except:
print("win32獲取窗體信息失敗 error")
sys.exit(1)
def main():
while True:
point1 =win32gui.GetCursorPos()#獲取鼠標(biāo)坐標(biāo)
time.sleep(2)
point2 =win32gui.GetCursorPos()#獲取鼠標(biāo)坐標(biāo)
if point2 == point1:
get_PID(point2)
if __name__ == "__main__":
main()
使用Pyinstaller打包,打包完大概6.7mb,這也是Python無奈的地方,隨便幾行代碼就這么大,最好還是用編譯語言實現(xiàn),幾十kb就行了。本例中代碼量不多,但是看win32的開發(fā)文檔過程還是蠻痛苦的,希望能給大家提供一些思考問題的思路。Python版最后執(zhí)行效果如下:
