VB控制外部程序
|
admin
2014年4月9日 2:31
本文熱度 7720
|
最近要寫一個程序,用來控制外部一個軟件的設(shè)置等等,網(wǎng)上收集了許多資料,自己經(jīng)過嘗試得出了想要的效果,這里把我這兩天學到的和理解的貼出來,讓以后的要做類似東西的朋友少一些彎路。
首先,說一下我想實現(xiàn)的效果
【目標】 1、運行我的程序,可以通過我的程序打開和關(guān)閉該外部軟件。
2、可以使用我的程序控制外部軟件的按鍵點擊、可以控制文本框的文本寫入和讀取。
(其實看起來很簡單 ,還是搞了我兩天時間啊…… )
其次,說一下我的方案和過程
【方法】
方法一:使用按鍵精靈模擬鼠標的點擊事件,然后通過VB的sendkeys()函數(shù)發(fā)送按鍵精靈的快捷鍵實現(xiàn)點擊
1、啟動軟件:這個有兩種方法,大家都應(yīng)該知道,函數(shù)有shell,該函數(shù)專門用來打開外部軟件的;另外一個是API函數(shù)WinExeC。這兩個都能達到啟動的效果,所以啟動是很簡單的。
'例程Shell returnvalue = Shell("C:\Program Files\DekTec\StreamXpress\StreamXpress.exe", 1)'返回該軟件的任務(wù)ID AppActivate returnvalue'激活該軟件 '例程WinExeC Declare Function WinExec Lib "kernel32" Alias "WinExec" (ByVal lpCmdLine As String, ByVal nCmdShow As Long) As Long lngtemp = WinExec("C:\Program Files\DekTec\StreamXpress\StreamXpress.exe", 2)'返回值>32表示打開成功 2、移動窗體:因為只是使用按鍵精靈模擬鼠標點擊,所以必須固定窗體的位置,否則沒有效果,或者點擊到其他位置,固定窗體的位置我用的是API函數(shù)MoveWindow(當然還有其他函數(shù)),將被控軟件窗體移動到左上角。在需要移動窗體的過程中必須獲取窗體的句柄,這里使用API函數(shù)FindWindow來獲取窗體的句柄。例程如下:(前面這些可是一帆風順啊,哈哈)
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public Declare Function MoveWindow Lib "user32" (ByVal hwnd As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long
Public Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
hWnd = FindWindow(vbNullString, "DekTec StreamXpress - Transport-Stream Player")'獲取窗體句柄
If hWnd = 0 Then
MsgBox "窗體DekTec StreamXpress Transport-Stream Player未找到"
Exit Sub
End If
GetWindowRect hWnd, RECT'獲取窗體的尺寸,方便移動窗體
temp = MoveWindow(hWnd, 0, 0, RECT.Right - RECT.Left, RECT.Bottom - RECT.Top, 1) If temp = 0 Then MsgBox "Move failed!" 3、制作按鍵精靈鼠標點擊:就是寫一個單擊按鍵的腳本,設(shè)置其快捷鍵方式:Alt+F10(這個要不常用,不讓每次都響應(yīng)按鍵精靈去了),上圖:
就這個,夠簡單吧…… ,在鍵盤上試了試,OK,沒問題……然而悲劇才剛剛開始
插一腳:這里說一個簡單的獲取要點擊位置的方法,我看了一些很多的方法,覺得這個是最簡便的,調(diào)用API的GetCursorPos函數(shù),用鼠標指向需要點擊的地方就直接獲取了這一點的位置。代碼如下:
Public Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Public Type POINTAPI
x As Long
y As Long
End Type Private Sub Timer1_Timer()‘注意要用到timer控件哈 Dim cursorp As POINTAPI GetCursorPos cursorp Text1 = cursorp.x & "," & cursorp.y End Sub 4、接下來就是使用我的程序發(fā)送快捷鍵了,這個簡單,使用sendkeys函數(shù)即可,以前使用過,代碼如下SendKeys "+{F10}"
這里出問題了…… 不管怎么搞,按鍵精靈就是一點響應(yīng)也沒有,去問了一些人,說是按鍵精靈設(shè)置的原因,按鍵精靈有普通模式、硬件模式和超級模式,一般選擇超級模式就搞定了,我就找到修改了然后還是不行,最后我把快捷鍵設(shè)置成了一個字母就OK了,但是這會影響到其他輸入……一頭霧水,到現(xiàn)在都沒弄明白。但是也因為這個原因促使我想其他方法,現(xiàn)在想想要用按鍵精靈,以后還要確保它被開啟才能使用程序,也怪麻煩的,直接一個程序不加其他東西最好
方法二:使用FindWindowEx和SendMessage配合完成外部控件的控制+SPY++工具
- 上面的方法沒行通,只有換方法了,我們已經(jīng)從上面的方法中獲取了主窗體的句柄,要控制里面的控件,就需要獲取控件的句柄,通過函數(shù) FindWindowEx就可以獲取控件的句柄,于是開始動手寫代碼了(關(guān)于 FindWindowEx 的介紹我空間里有)
Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As
Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
htxt0 = FindWindowEx(hWnd, 0, "Edit", vbNullString) 這里 FindWindowEx需要的參數(shù)有頂級窗體句柄(已獲取),子窗體句柄(就是從這個句柄后查找下一個句柄,為0表示從第一個開始),lpsz1表示類名(即控件的類名),lpsz2是一樣的。
- FindWindowEx 我們一般的使用方法是如果知道標題名(如按鈕“確定”),直接使用即可,如下
hbtn=FindWindowEx(hwnd,0,vbNullString,"確定")
但是我們這里按鍵是圖形按鈕,所以不能使用上面直接給出標題名的查找方法,只能通過類名進行查找,我要查找一個按鈕 控件的句柄,寫了如下代碼
hbtn = FindWindowEx(hWnd, 0, "ThunderRT6CommandButton", vbNullString)
這個地方獲取的句柄始終是0,也就是獲取失敗,這是什么原因呢?我查詢了一些資料,發(fā)現(xiàn)因為我們不知到其他軟件的編程工具是什么,所以就不能知道它控件的類名,這里也就是說類名是錯誤的。那類名如何獲取呢?這里我就要隆重的推出一塊強大的小工具了 Spy++,許多寫過窗體的控制的朋友都知道的
這里我們可以看到這個軟件能直接獲取各控件的類名和句柄,這個軟件的設(shè)計過程我已轉(zhuǎn)到控件,可以看一下,很有幫組的。獲取了句柄和類名后就可以看是寫程序了 htxt0 = FindWindowEx(hWnd, 0, "Edit", vbNullString)
htxt1 = FindWindowEx(hWnd, htxt0, "Edit", vbNullString)
htxt2 = FindWindowEx(hWnd, htxt1, "Edit", vbNullString)
htxt3 = FindWindowEx(hWnd, htxt2, "Edit", vbNullString)
htxt4 = FindWindowEx(hWnd, htxt3, "Edit", vbNullString)
htxt5 = FindWindowEx(hWnd, htxt4, "Edit", vbNullString)
這是一個text控件的獲取,這里我可以循環(huán)獲取然后比較句柄值,同spy++獲取的一樣就是我們要找的控件了(目前我只知道沒有標題名的控件只有這種方法,其他還沒了解過),需要注意的是這個時候需要控制的軟件不能關(guān)閉重新打開,因為這樣句柄就變了,但是一旦找到是哪個控件,這個就不受限制了。OK控件的句柄我們已經(jīng)獲取到了,我們可以隨意操控它了……
3.強大的SendMessage函數(shù)
API中有一個SendMessage的函數(shù),它是一個非常強大的函數(shù),它可以給windows系統(tǒng)發(fā)送許多命令,然后操控系統(tǒng)中的一些東西,我們這里需要發(fā)送的就是控制按鍵和文本的命令(具體函數(shù)的詳解空間里有)
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Const WM_LBUTTONDOWN = &H201
Public Const WM_LBUTTONUP = &H202
Public Const WM_GETTEXT = &HD
Public Const WM_SETTEXT = &HC
Public Const WM_GETTEXTLENGTH = &HE
Dim bytSend(3) As Byte
bytSend(0) = &H35
bytSend(1) = &H30
bytSend(2) = &H30
SendMessage htxt, WM_SETTEXT, 0, bytSend(0)'發(fā)送字符數(shù)組到文本控件
slen = SendMessageByString(htxt, WM_GETTEXT, 255, ByVal gets)'接收文本控件里的數(shù)據(jù),返回到gets里
注意:這里要注意傳送文本到文本控件時使用的是字符數(shù)組發(fā)送,而不是字符串,字符串發(fā)送會出現(xiàn)非法字符。
方法三:Mouse_event的使用
mouse_event函數(shù)是一個API函數(shù),它模擬了我們鼠標的動作,因為采用sendmessage方法我控制的按鍵太多需要獲取太多的句柄比較麻煩,于是采用函數(shù)mouse_event,僅僅需要知道鼠標要點擊的位置就可以了,而前面我說了getcursorpos函數(shù)能很好的獲取坐標值,所以相比這個更好用一些,寫了如下代碼
Public Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long)
Public Const MOUSEEVENTF_ABSOLUTE = &H8000 ' absolute move Public Const MOUSEEVENTF_LEFTDOWN = &H2 ' left button down Public Const MOUSEEVENTF_LEFTUP = &H4 ' left button up Public Const MOUSEEVENTF_MIDDLEDOWN = &H20 ' middle button down Public Const MOUSEEVENTF_MIDDLEUP = &H40 ' middle button up Public Const MOUSEEVENTF_MOVE = &H1 ' mouse move Public Const MOUSEEVENTF_RIGHTDOWN = &H8 ' right button down Public Const MOUSEEVENTF_RIGHTUP = &H10 ' right button up Public Const MOUSETRAILS = 39
mouse_event MOUSEEVENTF_LEFTDOWN, RECT.Left + 23, RECT.Top + 458, 0, 0
mouse_event MOUSEEVENTF_LEFTUP, RECT.Left + 23, RECT.Top + 458, 0, 0
結(jié)果鼠標是有單擊動作,但是只是在原點即鼠標點單擊,查了一些資料沒能解決,想到它僅僅就是在鼠標指向點點擊,何不將鼠標移到要點擊的地方,然后通過,點擊鼠標的位置達到點擊效果呢,于是改變方法寫了以下代碼,使用 SetCursorPos函數(shù)把鼠標移動到要點擊的點
Public Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long) As Long
SetCursorPos 23, 458
mouse_event MOUSEEVENTF_LEFTDOWN Or MOUSEEVENTF_ABSOLUTE, 0, 0, 0, 0
mouse_event MOUSEEVENTF_LEFTUP Or MOUSEEVENTF_ABSOLUTE, 0, 0, 0, 0
OK! 問題解決,當然這里的鼠標位置可以自己通過其他動態(tài)設(shè)定最好
該文章在 2014/4/9 2:31:32 編輯過
| |
全部評論1 |
|
admin
2014年4月9日 2:37
用API FindWindow查找目標窗口的句柄,再用SendMessage或PostMessage發(fā)送按鍵消息:
【
'Form代碼:
Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long '
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Sub Command1_Click()
Dim l_HwndSendTo As Long '為目標窗口句柄
l_HwndSendTo = FindWindow(vbNullString, "目標窗口名") '根據(jù)窗口名獲得窗口句柄
SendMessage l_HwndSendTo, &H100, 27, 0
'第二
'個參數(shù)表示發(fā)送的是按鍵按下消息,此時第三個參數(shù)是按鍵
'的Ascii碼
SendMessage l_HwndSendTo, &H101, 27, 0
End Sub
】
-----------
注意可能您要發(fā)送的目標實際上可能是窗口的一個子窗口(如某個按鈕),這個時候需要用FindWindowEx獲得其子窗口的句柄,再用SendMessage發(fā)送消息。
{{
FindWindowEx("父窗口句柄", ByVal 0&, "子窗口類型(如Button)", "子窗口名")
}} 該評論在 2014/4/9 2:37:01 編輯過
|
|
|