許多人包括我自己,對於window與process或Thread間的對應,常感困擾,我就目前所知者,大概的介紹一下:一個Process有自己4GB的位址空間,這個觀念比較容易接受,但是它卻不是執行程式的單位,真正執行程式者是Thread,每個Process被Create時,便會有一個主thread 來執行它,我們又可以Create其他的Thread來執行程式,假設現在就有兩個thread於這個Process了,那麽,這兩個Thread原則上是共用Process的同一個位址空間,例如:背景列印,但是至少有兩個Thread在做事,它的好處不用說明太多大家都可以明白,但它同時也會有其他問題(如同步、如果一個thread一個不小心當了,那有可能會使整個Process死掉),這些不在討論范圍。而window呢,它一定有一個thread來執行它,但一個Thread卻可以有不只一個的 Windows或根本沒有。另外,一個Process有一個的唯一的Process ID而每個Thread也有唯一的ThreadID,而控制Process 則大多透過Process Handle(hProcess)而非 Process ID,正如透過hWnd來控制Window一樣。如同前面所言,一個window有一個Thread在執行它,那該如何取得呢?請用 Declare Function GetWindowThreadProcessId Lib "user32" _ (ByVal hwnd As Long, lpdwProcessId As Long) As Long 這個function傳入一個hwnd而取得Process ID(其第二個三數),而傳回值是 ThreadID。而使用OpenProcess()來取得Process Handle,底下程式的目的是取得 Window ClassName, 與Window Title,我們搜尋window時,常使用FindWindow() 但這個function傳入的三數第一個便是Window ClassName,但我們經常不知道 ClassName透過它,我們可輕易來得知,進而做許多的控制。 程式使用方式: 1.先將想查詢的window叫出,放在桌面上 2.執行本程式,把不必要的window關掉,直到想查詢的window看得見(不必全部) 3.在form1的Command1上按下mouse的右鍵不要放掉,這時會看到mouse變問號加箭頭 而且form1不見了,代表您可以拖拉mouse了。 4.移到想查詢的window上面,放掉mouse,而後form1再度出現,上有所要的資訊
一個form , 一個ommandBox, 2 labels Private Type POINTAPI X As Long Y As Long End Type Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, _ ByVal hWndInsertAfter As Long, al X As Long, ByVal Y As Long, _ ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long Private Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, _ ByVal yPoint As Long) As Long Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _ (ByVal hwnd As Long, ByVal lpClassName As String, _ ByVal nMaxCount As Long) As Long Private Declare Function GetWindowThreadProcessId Lib "user32" _ (ByVal hwnd As Long, lpdwProcessId As Long) As Long Private Declare Function OpenProcess Lib "kernel32" _ (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _ ByVal dwProcessId As Long) As Long Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long Private Declare Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long, _ ByVal uExitCode As Long) As Long Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _ (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, ByVal lpWindowName As String) As Long Const HWND_TOP = 0 Const HWND_BOTTOM = 1 Const SWP_NOSIZE = &H1 Const SWP_NOMOVE = &H2 Const PROCESS_QUERY_INFORMATION = &H400 Private TitleName As String Private ClassName As String Private hProcess As Long Private Candisplay As Boolean Private Sub Command1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single) Dim aa As Long If Button = vbRightButton Then 將window設定成在底層 aa = SetWindowPos(Me.hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE) Me.MousePointer = vbArrowQuestion End If End Sub Private Sub Command1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single) Dim aa As Long Dim pt As POINTAPI Dim hwnd5 As Long Dim str5 As String Dim len5 As Long Dim thrid As Long, pid As Long If Button = vbRightButton Then 設定window到上層 aa = SetWindowPos(Me.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE) Me.MousePointer = vbDefault 取得mouse目前的座標,不能用mouseup Event的x,y因那是相對於form的座標 aa = GetCursorPos(pt) 取得pt所在座標,是落在那一個window上面 hwnd5 = WindowFromPoint(pt.X, pt.Y) len5 = 256 ClassName = String(255, 0) 取得該window的Class name aa = GetClassName(hwnd5, ClassName, len5) ClassName = Left(ClassName, aa) len5 = 256 TitleName = String(255, 0) 取得該window的title aa = GetWindowText(hwnd5, TitleName, len5) TitleName = Left(TitleName, aa) 依hwnd取得相對應的threadID(thrid), ProcessID(pid) thrid = GetWindowThreadProcessId(hwnd5, pid) 取得Process Handle hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid) 有了hProcess那可做事可多啦,例如:可偵測 它何時結束,或強制它結束等等 Call TerminateProcess(hProcess, 38) 最好別這麽做,否則,嘿嘿,你自己試 Label1.Caption = " Title = " + TitleName Label2.Caption = "Calss Name = " + ClassName End If End Sub