Tác giả: truongphu
Cấp độ bài viết: căn bản
Tóm tắt: Rất nhiều bài viết về hWnd trong Box Tài nguyên, tuy nhiên chúng không được trình bày tuần tự cho các bạn mới quen. bài viết hướng dẫn nầy nhằm mục đích đó
Hướng dẫn tìm hWnd
Có rất nhiều hàm API phục vụ việc tìm hWnd. Bài viết nầy ưu tiên dùng 2 hàm căn bản là FindWindow và FindWindowEx.
FindWindow dùng tìm hWnd cha, FindWindowEx dùng tìm hàm con cháu
A- Tìm hWnd của cửa sổ cha (gốc)
* Khai báo hàm API chung:
- Mã: Chọn tất cả
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Đấy là khai báo hàm API FindWindow chuẩn với 2 đối số lpClassName: String và lpWindowName: String.
Name định dạng String là điều tất nhiên! Tuy nhiên, có lúc, người ta cố ý khai định dạng 2 đối số trên là bất kỳ:
- Mã: Chọn tất cả
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As Any) As Long
* lpClassName là ClassName của cửa sổ chính, xem bài viết của tác giả NoBi
Nếu không biết, ta cho trị số vbNullString
* lpWindowName là tên cửa sổ chính, ấy là Tiêu đề trên TitleBar
Nếu không biết, ta cho trị số vbNullString
* Với định dạng 2 đối số trên là bất kỳ, ta có thể cho giá trị bất kỳ, vd vbNullString hoặc ByVal 0&
A1- Tìm hWnd của cửa sổ cha (gốc) đã biết ClassName và WindowName
- Gọi notepad, cửa sổ notepad hiện ra với title mặc định là "Untitled - Notepad", Classname cửa sổ chính là
"Notepad"
a- Chỉ biết ClassName: (Bảo đảm chỉ có 1 cửa sổ Notepad đang chạy)
Using vb Syntax Highlighting
Private Sub Command1_Click()
Dim y As Long
y = FindWindow("Notepad", vbNullString)
MsgBox y
End Sub
Dim y As Long
y = FindWindow("Notepad", vbNullString)
MsgBox y
End Sub
Parsed in 0.028 seconds, using GeSHi 1.0.8.4
b- Chỉ biết WindowName: hầu như chắc chắn
Using vb Syntax Highlighting
Private Sub Command2_Click()
Dim u As Long
u = FindWindow(vbNullString, "Untitled - Notepad")
MsgBox u
End Sub
Dim u As Long
u = FindWindow(vbNullString, "Untitled - Notepad")
MsgBox u
End Sub
Parsed in 0.003 seconds, using GeSHi 1.0.8.4
c- Biết cả ClassName và WindowName: chắc chắn!
Using vb Syntax Highlighting
Private Sub Command3_Click()
Dim i As Long
i = FindWindow("Notepad", "Untitled - Notepad")
MsgBox i
End Sub
Dim i As Long
i = FindWindow("Notepad", "Untitled - Notepad")
MsgBox i
End Sub
Parsed in 0.003 seconds, using GeSHi 1.0.8.4
Project đính kèm:
A2- WindowName với Unicode: (Tìm hWnd của cửa sổ cha không biết ClassName và WindowName)
a- hàm API FindWindows có khai báo Alias "FindWindowA", nghĩa là ta có quyền khai báo hổ trợ unicode: Alias "FindWindowW", tuy nhiên chưa biết cách dùng.
b- Ta có thể tìm hwnd của cửa sổ title unicode hơi phức tạp một tí, cách làm như sau:
- tìm cửa sổ thứ nhất với hàm FindWindow với 2 đối số Null string
- tìm cửa sổ kế tiếp với hàm GetWindow với đối số là hWnd cửa sổ vừa tìm, và GW_HWNDNEXT
- tiếp tục như thế ...
- trong quá trình tìm hWnd cửa sổ kế tiếp, ta nhận được các WindowName với hàm GetWindowText
- dò tìm trong các WindowName ấy, có dãy ký tự đặc trưng của cửa sổ title unicode, thì tìm ra hwnd
c- Thực hành: dễ hiểu hơn, ta gọi trang forum của CLBVB, có title là: "Câu lạc bộ Visual Basic • Trang chủ - Windows Internet Explorer". Ta sẽ tìm hwnd của cửa sổ có title unicode nầy, với dãy ký tự là "ang"
Code sau đây với khai báo 4 hàm Api ban đầu, Function GetHandle sẽ dò tìm hWnd lần lượt từ cửa sổ đầu tiên, nhờ Function GetWText sẽ tìm title unicode của các cửa sổ ấy. Command1 ra lệnh dò tìm cửa sổ chứa title có chuỗi "ang"
(Một số bạn đã quen thuộc 2 function trên, tuy nhiên tôi đã viết lại 2 function nầy thật gọn)
Using vb Syntax Highlighting
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextW" (ByVal hWnd As Long, ByVal
lpString As Long, ByVal cch As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthW" (ByVal hWnd As Long) As Long
Private Declare Function GetWindow Lib "user32" (ByVal hWnd As Long, ByVal wCmd As Long) As Long
Const GW_HWNDNEXT = 2
Private Sub Command1_Click()
MsgBox GetHandle("ang") & vbCr & GetWText(GetHandle("ang"))
End Sub
Function GetWText$(hWnd&)
Dim length%: length = GetWindowTextLength(hWnd) + 1
GetWText = Space(length)
GetWindowText hWnd, StrPtr(GetWText), length
GetWText = Left(GetWText, Len(GetWText) - 1)
End Function
Function GetHandle&(szTitle$)
GetHandle = FindWindow(vbNullString, vbNullString)
Do While GetHandle <> 0
If InStr(LCase(GetWText(GetHandle)), LCase(szTitle)) Then Exit Function
GetHandle = GetWindow(GetHandle, GW_HWNDNEXT)
Loop
End Function
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextW" (ByVal hWnd As Long, ByVal
lpString As Long, ByVal cch As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthW" (ByVal hWnd As Long) As Long
Private Declare Function GetWindow Lib "user32" (ByVal hWnd As Long, ByVal wCmd As Long) As Long
Const GW_HWNDNEXT = 2
Private Sub Command1_Click()
MsgBox GetHandle("ang") & vbCr & GetWText(GetHandle("ang"))
End Sub
Function GetWText$(hWnd&)
Dim length%: length = GetWindowTextLength(hWnd) + 1
GetWText = Space(length)
GetWindowText hWnd, StrPtr(GetWText), length
GetWText = Left(GetWText, Len(GetWText) - 1)
End Function
Function GetHandle&(szTitle$)
GetHandle = FindWindow(vbNullString, vbNullString)
Do While GetHandle <> 0
If InStr(LCase(GetWText(GetHandle)), LCase(szTitle)) Then Exit Function
GetHandle = GetWindow(GetHandle, GW_HWNDNEXT)
Loop
End Function
Parsed in 0.006 seconds, using GeSHi 1.0.8.4
Project đính kèm:
B- Tìm hWnd của cửa sổ con, cháu
* Khai báo hàm API chung:
- Mã: Chọn tất cả
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
các đối số của hàm FindWindowEx như sau:
- hWnd1 là hWnd của cửa sổ cha, bắt buộc phải có. nếu đối số nầy là Null, đối tượng khảo sát là cửa sổ
DeskTop
- hWnd2 là hWnd của các cửa sổ con kế tiếp, nếu là Null, sẽ tương ứng cửa sổ con đầu tiên
- lpsz1 là classname của cửa sổ con
- lpsz2 là windowname của cửa sổ con
B1- biết hWnd1 (cha) và ClassName (con)
Gọi Notepad, ta đã biết cách tìm hWnd (cha) của Notepad. ClassName của cửa sổ con để ghi có tên "Edit"
Code như sau:
Using vb Syntax Highlighting
Private Sub Command1_Click()
Dim i As Long
i = FindWindow("Notepad", "Untitled - Notepad")
MsgBox i
i = FindWindowEx(i, 0&, "Edit", vbNullString)
MsgBox i
End Sub
Dim i As Long
i = FindWindow("Notepad", "Untitled - Notepad")
MsgBox i
i = FindWindowEx(i, 0&, "Edit", vbNullString)
MsgBox i
End Sub
Parsed in 0.004 seconds, using GeSHi 1.0.8.4
B2- biết hWnd1 (cha) và WindowName (con)
Trên DeskTop (XP) có nút Start, nút nầy nằm trong cửa sổ cha có className là Shell_TrayWnd
Code tìm hWnd nút Start như sau:
Using vb Syntax Highlighting
Private Sub Command2_Click()
Dim h As Long
h = FindWindow("Shell_TrayWnd", vbNullString)
MsgBox h
h = FindWindowEx(h, 0&, vbNullString, "Start")
MsgBox h
End Sub
Dim h As Long
h = FindWindow("Shell_TrayWnd", vbNullString)
MsgBox h
h = FindWindowEx(h, 0&, vbNullString, "Start")
MsgBox h
End Sub
Parsed in 0.003 seconds, using GeSHi 1.0.8.4
B3- Tìm cửa sổ cháu:
Ở mục B2 có nói đến (XP) cửa sổ cha với className là Shell_TrayWnd, có cửa sổ con là nút Start, nó còn nhiều con nữa, một đứa có classname là TrayNotifyWnd (con), đứa con nầy lại chứa thêm vài cửa sổ nữa (cháu) mà một trong những cháu là đồng hồ
Code tìm hwnd đồng hồ góc dưới-phải màn hình như sau:
Using vb Syntax Highlighting
Private Sub Command3_Click()
Dim u As Long
u = FindWindow("Shell_TrayWnd", vbNullString)
MsgBox "cha: " & u
u = FindWindowEx(u, 0&, "TraynotifyWnd", vbNullString)
MsgBox "Con: " & u
u = FindWindowEx(u, 0&, "TrayClockWClass", vbNullString)
MsgBox "Cháu: " & u
End Sub
Dim u As Long
u = FindWindow("Shell_TrayWnd", vbNullString)
MsgBox "cha: " & u
u = FindWindowEx(u, 0&, "TraynotifyWnd", vbNullString)
MsgBox "Con: " & u
u = FindWindowEx(u, 0&, "TrayClockWClass", vbNullString)
MsgBox "Cháu: " & u
End Sub
Parsed in 0.004 seconds, using GeSHi 1.0.8.4
B4- Tìm toàn bộ các cửa sổ con:
Kỹ thuật nầy ít áp dụng cho các trường hợp riêng rẽ, chỉ dùng trong các tool dò tìm hWnd, classname.. tổng quát (vd Spy)
Ta cho chạy code:
- Mã: Chọn tất cả
h = FindWindowEx(hwnd, 0, vbNullString, vbNullString)
- như đã nói, hwnd con, nếu là 0 sẽ tương ứng với cửa sổ con đầu tiên
tiếp theo, thay vì 0, ta thế h tìm được ở trên vào, sẽ tìm ra cửa sổ con kế tiếp
- Mã: Chọn tất cả
h = FindWindowEx(hwnd, h, vbNullString, vbNullString)
Quá trình nầy lập lại cho đến khi tìm hết con, code như sau:
Using vb Syntax Highlighting
Private Sub Command4_Click()
Dim u As Long
u = FindWindow("Shell_TrayWnd", vbNullString)
List1.Clear
List1.AddItem "Cha: " & u
getChild (u)
End Sub
Private Sub getChild(hwnd As Long)
Dim h As Long
h = FindWindowEx(hwnd, 0, vbNullString, vbNullString)
While h <> 0
List1.AddItem h
h = FindWindowEx(hwnd, h, vbNullString, vbNullString)
Wend
End Sub
Dim u As Long
u = FindWindow("Shell_TrayWnd", vbNullString)
List1.Clear
List1.AddItem "Cha: " & u
getChild (u)
End Sub
Private Sub getChild(hwnd As Long)
Dim h As Long
h = FindWindowEx(hwnd, 0, vbNullString, vbNullString)
While h <> 0
List1.AddItem h
h = FindWindowEx(hwnd, h, vbNullString, vbNullString)
Wend
End Sub
Parsed in 0.004 seconds, using GeSHi 1.0.8.4
B5- Tìm toàn bộ các cửa sổ con và cháu:
Tại Sub getChild, nếu ta áp dụng kỹ thuật đệ quy, ta sẽ tìm ra hết các lớo cháu!
Using vb Syntax Highlighting
Private Sub Command5_Click()
Dim k As Long
k = FindWindow("Shell_TrayWnd", vbNullString)
List1.Clear
List1.AddItem "Cha: " & k
getAllChild (k)
End Sub
Private Sub getAllChild(hwnd As Long)
Dim h As Long
h = FindWindowEx(hwnd, 0, vbNullString, vbNullString)
While h <> 0
List1.AddItem h
getAllChild h 'Ðê Quy, Tìm hWnd cho Ðê'n hê't
h = FindWindowEx(hwnd, h, vbNullString, vbNullString)
Wend
End Sub
Dim k As Long
k = FindWindow("Shell_TrayWnd", vbNullString)
List1.Clear
List1.AddItem "Cha: " & k
getAllChild (k)
End Sub
Private Sub getAllChild(hwnd As Long)
Dim h As Long
h = FindWindowEx(hwnd, 0, vbNullString, vbNullString)
While h <> 0
List1.AddItem h
getAllChild h 'Ðê Quy, Tìm hWnd cho Ðê'n hê't
h = FindWindowEx(hwnd, h, vbNullString, vbNullString)
Wend
End Sub
Parsed in 0.004 seconds, using GeSHi 1.0.8.4
Project:
C- Lưu ý:
C1- Ta có thể tìm con cháu với hàm GetParent, chi tiết ở các bài viết của NoBi
C2- Các kỹ thuật tìm hWnd đơn lẽ rất cần biết trước classname, tác giả NoBi đã cung cấp công cụ dò tìm
(rất cần thiết)




