摘要:前面我在自動(dòng)化控制版微信該系列文中更新了控制微信發(fā)送圖片的方法。根據(jù)部分群友實(shí)際工作的需要,本文將分享如何控制微信發(fā)送文件。接下來我將破解這個(gè)領(lǐng)域的世界未解之謎,彌補(bǔ)無人完成這個(gè)功能的缺陷。
大家好,我是小小明。前面我在《UI自動(dòng)化控制PC版微信》該系列文中更新了控制微信發(fā)送圖片的方法。根據(jù)部分群友實(shí)際工作的需要,本文將分享如何控制微信發(fā)送文件。
專欄鏈接:https://blog.csdn.net/as604049322/category_11396772.html
按照前面的思路,我們發(fā)送文本和圖片,都是采用復(fù)制粘貼操作剪切板的方式,而uiautomation 框架本身也提供了復(fù)制文本或圖片的方法,卻沒有提供復(fù)制文件到剪切板的API。
翻遍了全網(wǎng)的資料,目前并沒有人通過python調(diào)用windows api實(shí)現(xiàn)復(fù)制文件到剪切板,僅有人通過pyqt5實(shí)現(xiàn)了復(fù)制文件到剪切板。幸好有大佬通過C#和C++實(shí)現(xiàn)了該操作,假如我們能夠?qū)⑦@些實(shí)現(xiàn)代碼翻譯成Python,或許就能實(shí)現(xiàn)python根據(jù)文件路徑設(shè)置文件到剪切板。
即使實(shí)在實(shí)現(xiàn)不了代碼控制復(fù)制指定文件到剪切板,那么我們也可以使用自動(dòng)化的方式,點(diǎn)擊發(fā)送文件按鈕來完成這個(gè)功能。由于最終已經(jīng)實(shí)現(xiàn)全網(wǎng)都沒人實(shí)現(xiàn)的通過pywin32控制剪切板復(fù)制文件,所以我不需再演示這種簡單的模擬的方法,有興趣的童鞋也可以根據(jù)前文的思路嘗試。
為了實(shí)現(xiàn)該功能翻遍國內(nèi)博客,僅發(fā)現(xiàn)兩篇比較有價(jià)值的參考文章:
C++實(shí)現(xiàn):https://blog.csdn.net/u011393161/article/details/79671093#t9
C#實(shí)現(xiàn):https://blog.csdn.net/LE_Kukly/article/details/80656845
各類問答平臺(tái)有很多人也想通過pywin32實(shí)現(xiàn)該功能,可惜無人回答。
接下來我將破解這個(gè)Python領(lǐng)域的世界未解之謎,彌補(bǔ)無人完成這個(gè)功能的缺陷。
關(guān)于剪貼板的windowsAPI可查看:https://docs.microsoft.com/zh-cn/windows/win32/dataxchg/clipboard
不過由于win32clipboard良好的封裝,我們不需要直接調(diào)用這么底層的api,代碼會(huì)簡化N倍。
參考stackoverflow一位國外大佬的回答:
https://stackoverflow.com/questions/19670697/how-to-set-win32clipboard-data-on-cf-hdrop-format
win32clipboard支持對(duì)STGMEDIUM和DROPFILES結(jié)構(gòu)自動(dòng)解碼,但這位國外大佬也不知道如何構(gòu)造STGMEDIUM和DROPFILES結(jié)構(gòu)。
不過在我參考了前面的文章和幾十次實(shí)驗(yàn)后,已成功構(gòu)造STGMEDIUM和DROPFILES結(jié)構(gòu),最終 完成了這個(gè)功能。
首先我們先看看如何通過win32clipboard獲取當(dāng)前復(fù)制的文件路徑列表:
import win32clipboardwin32clipboard.OpenClipboard()try: files = win32clipboard.GetClipboardData(win32clipboard.CF_HDROP) print(files)finally: win32clipboard.CloseClipboard()
現(xiàn)在我復(fù)制下面三個(gè)文件后執(zhí)行上述代碼:
結(jié)果如下:
("D://tmp//股票數(shù)據(jù).xlsx", "D://tmp//test.txt", "D://tmp//WeChat_double.bat")
說明win32clipboard
確實(shí)能自動(dòng)解析STGMEDIUM和DROPFILES結(jié)構(gòu)的數(shù)據(jù)獲取路徑。
下面我們開始嘗試將指定路徑的文件設(shè)置到剪切板:
閱讀C++實(shí)現(xiàn)的代碼:
//注意用/0分隔多個(gè)路徑TCHAR szFiles[300] = _T("natives_blob.bin/0snapshot_blob.bin/0locales/0");if (OpenClipboard(hWnd)) { EmptyClipboard(); // DROPFILES的頭文件Shlobj.h int nSize = sizeof(DROPFILES) + sizeof(szFiles); HANDLE hData = GlobalAlloc(GHND, nSize); LPDROPFILES pDropFiles = (LPDROPFILES)GlobalLock(hData); pDropFiles->pFiles = sizeof(DROPFILES);#ifdef UNICODE pDropFiles->fWide = TRUE;#else pDropFiles->fWide = FALSE;#endif LPBYTE pData = (LPBYTE)pDropFiles + sizeof(DROPFILES); CopyMemory(pData, szFiles, sizeof(szFiles)); GlobalUnlock(hData); SetClipboardData(CF_HDROP, hData); CloseClipboard();}
可以看到本質(zhì)上復(fù)制文件操作是向剪切版寫入了CF_HDROP類型的消息,消息內(nèi)容為DROPFILES和路徑組成的字節(jié),路徑由Unicode編碼的字節(jié)組成。
那么借助win32clipboard,我們只需要組織出這樣的字節(jié)數(shù)據(jù)即可。
參考:
DROPFILES的結(jié)構(gòu):
typedef struct _DROPFILES { DWORD pFiles; POINT pt; BOOL fNC; BOOL fWide;} DROPFILES, *LPDROPFILES;
參考:https://docs.microsoft.com/zh-cn/windows/win32/api/shlobj_core/ns-shlobj_core-dropfiles
和:
typedef struct tagPOINT { LONG x; LONG y;} POINT, *PPOINT;
參考:https://docs.microsoft.com/en-us/previous-versions/dd162805(v=vs.85)
可以合并成一個(gè)結(jié)構(gòu)體:
typedef struct _DROPFILES { DWORD pFiles; LONG x; LONG y; BOOL fNC; BOOL fWide;} DROPFILES, *LPDROPFILES;
再結(jié)合下面兩行C++代碼,一起翻譯為了python:
pDropFiles->pFiles = sizeof(DROPFILES);pDropFiles->fWide = TRUE;
注意:只考慮使用Unicode編碼的情況,兼容中文。
from ctypes import *class DROPFILES(Structure): _fields_ = [ ("pFiles", c_uint), ("x", c_long), ("y", c_long), ("fNC", c_int), ("fWide", c_bool), ]pDropFiles = DROPFILES()pDropFiles.pFiles = sizeof(DROPFILES)pDropFiles.fWide = True
轉(zhuǎn)換為字節(jié):
bytes(pDropFiles)
b"/x14/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x01/x00/x00/x00"
對(duì)于多個(gè)文本路徑,我們?nèi)绾螌⑵滢D(zhuǎn)換為需要的Unicode雙字節(jié)形式呢?
首先,我們必須清楚Unicode編碼采用UCS-2格式直接存儲(chǔ),而UTF-16完全對(duì)應(yīng)于UCS-2的,即把UCS-2規(guī)定的代碼點(diǎn)通過Big Endian或Little Endian方式直接保存下來。UTF-16包括三種:UTF-16,UTF-16BE(Big Endian),UTF-16LE(Little Endian)。UTF-16通過在文件開頭以名為BOM(Byte Order Mark,U+FEFF)的字符來表明文件是Big Endian還是Little Endian。
Python支持的編碼表:https://docs.python.org/zh-cn/3/library/codecs.html?#standard-encodings
我們只需要將python字符串使用UTF-16編碼后去掉開頭兩個(gè)字節(jié)即可得到對(duì)應(yīng)的Unicode雙字節(jié)。
先測(cè)試復(fù)制兩個(gè)文件:
file = "D://tmp//test.txt/0D://tmp//股票數(shù)據(jù).xlsx/0/0"data = file.encode("U16")[2:]win32clipboard.OpenClipboard()try: win32clipboard.EmptyClipboard() win32clipboard.SetClipboardData( win32clipboard.CF_HDROP, bytes(pDropFiles)+data)finally: win32clipboard.CloseClipboard()
執(zhí)行以上代碼后,嘗試在微信輸入框粘貼:
點(diǎn)擊發(fā)送測(cè)試一下:
可以看到正斜杠分隔的文件路徑發(fā)送出來的文件不正常,我們應(yīng)該將文件路徑統(tǒng)一封裝成反斜杠的形式。
最終封裝的方法如下:
import win32clipboardfrom ctypes import *class DROPFILES(Structure): _fields_ = [ ("pFiles", c_uint), ("x", c_long), ("y", c_long), ("fNC", c_int), ("fWide", c_bool), ]pDropFiles = DROPFILES()pDropFiles.pFiles = sizeof(DROPFILES)pDropFiles.fWide = Truematedata = bytes(pDropFiles)def setClipboardFiles(paths): files = ("/0".join(paths)).replace("/", "http://") data = files.encode("U16")[2:]+b"/0/0" win32clipboard.OpenClipboard() try: win32clipboard.EmptyClipboard() win32clipboard.SetClipboardData( win32clipboard.CF_HDROP, matedata+data) finally: win32clipboard.CloseClipboard()def setClipboardFile(file): setClipboardFiles([file])def readClipboardFilePaths(): win32clipboard.OpenClipboard() paths = None try: return win32clipboard.GetClipboardData(win32clipboard.CF_HDROP) finally: win32clipboard.CloseClipboard()
至此我們就通過pywin32實(shí)現(xiàn)了修改剪切板的內(nèi)容為指定文件。
下面我們繼續(xù)完善之前的程序,前面的發(fā)送功能支持文本和圖片,下面增加支持文件的功能:
import timeimport uiautomation as autofrom uiautomation.uiautomation import Bitmapimport win32clipboardfrom ctypes import *class DROPFILES(Structure): _fields_ = [ ("pFiles", c_uint), ("x", c_long), ("y", c_long), ("fNC", c_int), ("fWide", c_bool), ]pDropFiles = DROPFILES()pDropFiles.pFiles = sizeof(DROPFILES)pDropFiles.fWide = Truematedata = bytes(pDropFiles)def setClipboardFiles(paths): files = ("/0".join(paths)).replace("/", "http://") data = files.encode("U16")[2:]+b"/0/0" win32clipboard.OpenClipboard() try: win32clipboard.EmptyClipboard() win32clipboard.SetClipboardData( win32clipboard.CF_HDROP, matedata+data) finally: win32clipboard.CloseClipboard()def setClipboardFile(file): setClipboardFiles([file])def readClipboardFilePaths(): win32clipboard.OpenClipboard() paths = None try: return win32clipboard.GetClipboardData(win32clipboard.CF_HDROP) finally: win32clipboard.CloseClipboard()wechatWindow = auto.WindowControl( searchDepth=1, Name="微信", ClassName="WeChatMainWndForPC")wechatWindow.SetActive()search = wechatWindow.EditControl(Name="搜索")edit = wechatWindow.EditControl(Name="輸入")messages = wechatWindow.ListControl(Name="消息")sendButton = wechatWindow.ButtonControl(Name="發(fā)送(S)")def selectSessionFromName(name, wait_time=0.1): search.Click() auto.SetClipboardText(name) edit.SendKeys("{Ctrl}v") # 等待微信索引搜索跟上 time.sleep(wait_time) search.SendKeys("{Enter}")def send_msg(content, msg_type=1): if msg_type == 1: auto.SetClipboardText(content) elif msg_type == 2: auto.SetClipboardBitmap(Bitmap.FromFile(content)) elif msg_type == 3: setClipboardFile(content) edit.SendKeys("{Ctrl}v") sendButton.Click()
然后開始測(cè)試:
name = "小小明"selectSessionFromName(name)filename = r"D:/tmp/股票數(shù)據(jù).xlsx"send_msg(filename, msg_type=3)filename = "D:/ZkInspector.jar"send_msg(filename, msg_type=3)
可以看到,我們發(fā)送文件的功能已經(jīng)成功實(shí)現(xiàn)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/121857.html
摘要:四層負(fù)載均衡不會(huì)引起超時(shí)。動(dòng)態(tài)修改包的目標(biāo)地址,并轉(zhuǎn)發(fā)數(shù)據(jù)包使其到達(dá)不同的機(jī)器上來實(shí)現(xiàn)負(fù)載均衡的目的,因此節(jié)點(diǎn)不會(huì)引起超時(shí)。七層負(fù)載均衡等待上游響應(yīng)超時(shí)。例如使用多線程并發(fā)減少遠(yuǎn)程查詢的總體時(shí)間如需數(shù)據(jù)有序,可以使用方案。 B端業(yè)務(wù)經(jīng)常要提供下載報(bào)表的功能,一般的方法是先查詢出所有數(shù)據(jù),然后在內(nèi)存中組裝成報(bào)表(如XLS/XLSX格式)后統(tǒng)一輸出。但是如果生成報(bào)表需要查詢的數(shù)據(jù)量很大,遠(yuǎn)...
摘要:此類文件僅被處理。小白表示沒看懂眾所周知,是的核心配置文件,在啟動(dòng)時(shí)被讀取,那么目錄的其他文件也是可以被識(shí)別,官方還說了除了主之外,還會(huì)在每個(gè)目錄下掃描文件,從被執(zhí)行的文件所在目錄開始一直上升到根目錄所指定的。 神秘的.user.ini文件 .user.ini究竟是個(gè)神秘東東? 我們看看官方怎么說: http://php.net/manual/zh/conf...自 PHP 5.3....
摘要:所以,我們這個(gè)小游戲發(fā)布以后,我們就開始花了很多很多時(shí)間來打擊外掛。二距離判斷像素點(diǎn)判斷該方法采用自目前最火的跳一跳小游戲輔助程序。 作者:Hahn, 騰訊高級(jí)UI工程師商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系騰訊WeTest獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。 原文鏈接:http://wetest.qq.com/lab/view/364.html WeTest 導(dǎo)讀 張小龍:這個(gè)游戲發(fā)布以后,其實(shí)它的效果有點(diǎn)超...
閱讀 3242·2021-10-27 14:20
閱讀 2525·2021-10-08 10:05
閱讀 1624·2021-09-09 09:33
閱讀 2901·2019-08-30 13:16
閱讀 1434·2019-08-29 18:34
閱讀 1169·2019-08-29 10:58
閱讀 1228·2019-08-28 18:22
閱讀 1226·2019-08-26 13:33