• Vui lòng đọc nội qui diễn đàn để tránh bị xóa bài viết
  • Tìm kiếm trước khi đặt câu hỏi

Hướng dẫn tìm hWnd

Các bài viết hướng dẫn, giúp các bạn hiểu và tiếp cận với Visual Basic nhanh hơn
Hình đại diện của người dùng
truongphu
VIP
VIP
Bài viết: 4762
Ngày tham gia: CN 04/11/2007 10:57 am
Đến từ: Cam Đức, Khánh hòa
Has thanked: 14 time
Been thanked: 515 time

Hướng dẫn tìm hWnd

Gửi bàigửi bởi truongphu » T.Năm 29/07/2010 4:03 pm

Tên bài viết: Hướng dẫn tìm hWnd
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 hết

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 hết

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)
  1. Private Sub Command1_Click()
  2.     Dim y As Long
  3.     y = FindWindow("Notepad", vbNullString)
  4.     MsgBox y
  5. End Sub


b- Chỉ biết WindowName: hầu như chắc chắn
  1. Private Sub Command2_Click()
  2.     Dim u As Long
  3.     u = FindWindow(vbNullString, "Untitled - Notepad")
  4.     MsgBox u
  5. End Sub


c- Biết cả ClassName và WindowName: chắc chắn!
  1. Private Sub Command3_Click()
  2.     Dim i As Long
  3.     i = FindWindow("Notepad", "Untitled - Notepad")
  4.     MsgBox i
  5. End Sub


Project đính kèm:
hWnd of window having ClassName and WindowName.rar
(1.33 KiB) Đã tải 788 lần


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)

  1. Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
  2. Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextW" (ByVal hWnd As Long, ByVal
  3. lpString As Long, ByVal cch As Long) As Long
  4. Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthW" (ByVal hWnd As Long) As Long
  5. Private Declare Function GetWindow Lib "user32" (ByVal hWnd As Long, ByVal wCmd As Long) As Long
  6. Const GW_HWNDNEXT = 2
  7.  
  8. Private Sub Command1_Click()
  9. MsgBox GetHandle("ang") & vbCr & GetWText(GetHandle("ang"))
  10. End Sub
  11.  
  12. Function GetWText$(hWnd&)
  13. Dim length%:  length = GetWindowTextLength(hWnd) + 1
  14.     GetWText = Space(length)
  15.     GetWindowText hWnd, StrPtr(GetWText), length
  16. GetWText = Left(GetWText, Len(GetWText) - 1)
  17. End Function
  18.  
  19. Function GetHandle&(szTitle$)
  20.     GetHandle = FindWindow(vbNullString, vbNullString)
  21.     Do While GetHandle <> 0
  22.         If InStr(LCase(GetWText(GetHandle)), LCase(szTitle)) Then Exit Function
  23.         GetHandle = GetWindow(GetHandle, GW_HWNDNEXT)
  24.     Loop
  25. End Function


Project đính kèm:
hwnd of unicode title.rar
(1.38 KiB) Đã tải 747 lần


B- Tìm hWnd của cửa sổ con, cháu

* Khai báo hàm API chung:

Mã: Chọn hết

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:
  1. Private Sub Command1_Click()
  2.     Dim i As Long
  3.     i = FindWindow("Notepad", "Untitled - Notepad")
  4.     MsgBox i
  5.     i = FindWindowEx(i, 0&, "Edit", vbNullString)
  6.     MsgBox i
  7. End Sub


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:
  1. Private Sub Command2_Click()
  2.     Dim h As Long
  3.     h = FindWindow("Shell_TrayWnd", vbNullString)
  4.     MsgBox h
  5.     h = FindWindowEx(h, 0&, vbNullString, "Start")
  6.     MsgBox h
  7. End Sub


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:

  1. Private Sub Command3_Click()
  2.     Dim u As Long
  3.     u = FindWindow("Shell_TrayWnd", vbNullString)
  4.     MsgBox "cha: " & u
  5.     u = FindWindowEx(u, 0&, "TraynotifyWnd", vbNullString)
  6.     MsgBox "Con: " & u
  7.     u = FindWindowEx(u, 0&, "TrayClockWClass", vbNullString)
  8.     MsgBox "Cháu: " & u
  9. End Sub


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 hết

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 hết

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:
  1. Private Sub Command4_Click()
  2.     Dim u As Long
  3.     u = FindWindow("Shell_TrayWnd", vbNullString)
  4.     List1.Clear
  5.     List1.AddItem "Cha: " & u
  6.     getChild (u)
  7. End Sub
  8.  
  9. Private Sub getChild(hwnd As Long)
  10.     Dim h As Long
  11.     h = FindWindowEx(hwnd, 0, vbNullString, vbNullString)
  12.     While h <> 0
  13.         List1.AddItem h
  14.         h = FindWindowEx(hwnd, h, vbNullString, vbNullString)
  15.     Wend
  16. End Sub

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!
  1. Private Sub Command5_Click()
  2.     Dim k As Long
  3.     k = FindWindow("Shell_TrayWnd", vbNullString)
  4.     List1.Clear
  5.     List1.AddItem "Cha: " & k
  6.     getAllChild (k)
  7. End Sub
  8.  
  9. Private Sub getAllChild(hwnd As Long)
  10.     Dim h As Long
  11.     h = FindWindowEx(hwnd, 0, vbNullString, vbNullString)
  12.     While h <> 0
  13.         List1.AddItem h
  14.         getAllChild h 'Ðê Quy, Tìm hWnd cho Ðê'n hê't
  15.        h = FindWindowEx(hwnd, h, vbNullString, vbNullString)
  16.     Wend
  17. End Sub


Project:
findwindowex classname.rar
(1.54 KiB) Đã tải 717 lần


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)


o0o--truongphu--o0o

.........
Ghé thăm:
Chuyện Linh Tinh

Hình đại diện của người dùng
VuVanHoanh
Thành viên danh dự
Thành viên danh dự
Bài viết: 1259
Ngày tham gia: T.Năm 03/06/2010 9:23 pm
Đến từ: Kim Sơn - Đông Triều - Quảng Ninh
Has thanked: 22 time
Been thanked: 138 time
Liên hệ:

Re: Hướng dẫn tìm hWnd

Gửi bàigửi bởi VuVanHoanh » T.Tư 18/08/2010 6:04 pm

Góp ý: một cách khác để tìm hWnd của một đối tượng nào đó trên màn hình
Sử dụng 2 hàm API GetCursorPos và WindowFromPoint
Cần 1 form, 1 label, 1 timer

  1. Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINT_TYPE) As Long
  2. Private Declare Function WindowFromPoint Lib "user32.dll" (ByVal xPoint As Long, ByVal yPoint As Long) As Long
  3.  
  4. Private Type POINT_TYPE
  5.      x As Long
  6.      y As Long
  7. End Type
  8.  
  9. Private Sub Timer1_Timer()
  10.      Dim PT As POINT_TYPE
  11.      GetCursorPos PT
  12.      'Gán hWnd cho label
  13.     Label1.Caption = WindowFromPoint(PT.x, PT.y)
  14. End Sub
  15.  


P/s: Cảm ơn bạn DQHưng đã nhắc nhở
Sửa lần cuối bởi VuVanHoanh vào ngày T.Sáu 20/08/2010 9:29 am với 3 lần sửa.
Since 2008...
One love! :x

pctester2020
Thành viên chính thức
Thành viên chính thức
Bài viết: 26
Ngày tham gia: T.Hai 22/12/2008 11:33 am
Been thanked: 1 time

Re: Hướng dẫn tìm hWnd

Gửi bàigửi bởi pctester2020 » T.Hai 06/09/2010 9:20 am

Chào bác Phú,

Cháu muốn việt hóa nút OK trong MsgBox theo Unicode nhưng không bắt được hwnd của nút OK

Mã: Chọn hết

Public Function UniMsg(ByVal sUniText As String, Optional ByVal Title As String = "UniMsg()", Optional Button As VbMsgBoxStyle = vbInformation, Optional ByVal hWnd As Long = 0) As VbMsgBoxResult
'---------------------------------------------------------------------------------------
' Function  : UniMsg
' Author    : truongphu (truongphu@caulacbovb.com - Support Group Leader)
' Address   : Cam Duc, Cam Lam, Khanh Hoa
'---------------------------------------------------------------------------------------
   
    UniMsg = MessageBox(hWnd, StrPtr(sUniText), StrPtr(Title), Button)
    DefWindowProcW StrPtr(Title), &HC, &H0&, StrPtr(Title)
   
    'Tim nut OK
    Dim hButton As Long
    hButton = FindWindowEx(StrPtr(sUniText), 0&, "Button", "OK")        '-> ko tim duoc nut OK
    DefWindowProcW hButton, &HC, 0&, StrPtr(Telex2Uni("DDosng"))
End Function



Tham số sUniText được chuyển đổi từ hàm Telex2Uni:

Mã: Chọn hết

Public Function Telex2Uni(ByVal TelexStr As String) As String ' Chuyen chuoi go theo kieu Telex thanh chuoi tieng Viet Unicode
'---------------------------------------------------------------------------------------
' Function  : Telex2Uni
' Author    : phantronghiep07
' Phone     : 0915 080 282
'---------------------------------------------------------------------------------------
    Dim i As Integer
    Dim MaAcii, Telex
   
     MaAcii = Array(7845, 7847, 7849, 7851, 7853, 226, 225, 224, 7843, 227, 7841, 7855, 7857, 7859, _
                                7861, 7863, 259, 250, 249, 7911, 361, 7909, 7913, 7915, 7917, 7919, 7921, 432, _
                                7871, 7873, 7875, 7877, 7879, 234, 233, 232, 7867, 7869, 7865, 7889, 7891, 7893, _
                                7895, 7897, 244, 243, 242, 7887, 245, 7885, 7899, 7901, 7903, 7905, 7907, 417, _
                                237, 236, 7881, 297, 7883, 253, 7923, 7927, 7929, 7925, 273, 7844, 7846, 7848, _
                                7850, 7852, 194, 193, 192, 7842, 195, 7840, 7854, 7856, 7858, 7860, 7862, 258, _
                                218, 217, 7910, 360, 7908, 7912, 7914, 7916, 7918, 7920, 431, 7870, 7872, 7874, _
                                7876, 7878, 202, 201, 200, 7866, 7868, 7864, 7888, 7890, 7892, 7894, 7896, 212, _
                                211, 210, 7886, 213, 7884, 7898, 7900, 7902, 7904, 7906, 416, 205, 204, 7880, 296, _
                                7882, 221, 7922, 7926, 7928, 7924, 272)
                       
     Telex = Array("aas", "aaf", "aar", "aax", "aaj", "aa", "as", "af", "ar", "ax", "aj", "aws", "awf", _
                            "awr", "awx", "awj", "aw", "us", "uf", "ur", "ux", "uj", "uws", "uwf", "uwr", "uwx", _
                            "uwj", "uw", "ees", "eef", "eer", "eex", "eej", "ee", "es", "ef", "er", "ex", "ej", _
                            "oos", "oof", "oor", "oox", "ooj", "oo", "os", "of", "or", "ox", "oj", "ows", "owf", _
                            "owr", "owx", "owj", "ow", "is", "if", "ir", "ix", "ij", "ys", "yf", "yr", "yx", "yj", _
                            "dd", "AAS", "AAF", "AAR", "AAX", "AAJ", "AA", "AS", "AF", "AR", "AX", _
                            "AJ", "AWS", "AWF", "AWR", "AWX", "AWJ", "AW", "US", "UF", "UR", "UX", _
                            "UJ", "UWS", "UWF", "UWR", "UWX", "UWJ", "UW", "EES", "EEF", "EER", _
                            "EEX", "EEJ", "EE", "ES", "EF", "ER", "EX", "EJ", "OOS", "OOF", "OOR", _
                            "OOX", "OOJ", "OO", "OS", "OF", "OR", "OX", "OJ", "OWS", "OWF", "OWR", _
                            "OWX", "OWJ", "OW", "IS", "IF", "IR", "IX", "IJ", "YS", "YF", "YR", "YX", _
                            "YJ", "DD")
                           
    Telex2Uni = TelexStr
    For i = 0 To 133
        Telex2Uni = Replace(Telex2Uni, Telex(i), ChrW(MaAcii(i)))
    Next i
    Telex2Uni = Replace(Telex2Uni, "'", "") ' Neu muon hien thi ko dau thi phai go ky tu ' . Vd: Vi'sual Ba'sic
End Function

Hình đại diện của người dùng
truongphu
VIP
VIP
Bài viết: 4762
Ngày tham gia: CN 04/11/2007 10:57 am
Đến từ: Cam Đức, Khánh hòa
Has thanked: 14 time
Been thanked: 515 time

Re: Hướng dẫn tìm hWnd

Gửi bàigửi bởi truongphu » T.Hai 06/09/2010 3:14 pm

1- Trong bài viết của bạn ở trên, có hàm UniMsg và tìm nut OK (không tìm được) của truongphu.
Vậy tôi viết toàn bộ như trên hồi nào thế?

Bạn muốn trích dẫn, phải trích dẫn đúng nguyên văn, không thể viết bừa bãi như thế
----------

2- tìm hWnd nút OK của thông báo MsgBox bất kể ascii hay uni, ta chỉ cần:
  1. h = FindWindow("#32770", vbNullString)
  2. hh = FindWindowEx(h, 0, "Button", "OK")


-------

[mod=]3- các câu hỏi khác không liên quan bài viết, mời ra Box Thảo luận VB6[/mod]
o0o--truongphu--o0o

.........
Ghé thăm:
Chuyện Linh Tinh

pctester2020
Thành viên chính thức
Thành viên chính thức
Bài viết: 26
Ngày tham gia: T.Hai 22/12/2008 11:33 am
Been thanked: 1 time

Re: Hướng dẫn tìm hWnd

Gửi bàigửi bởi pctester2020 » T.Tư 08/09/2010 9:03 am

Chào bác Phú,

Thật ra, cháu chỉ ứng dụng code của bác cho phù hợp với ứng dụng của cháu và vẫn để nguyên quyền tác giả. Mong bác hiểu và giúp đỡ

Vấn đề đổi tên nút OK, cháu thấy có lẽ phải sử dụng kỹ thuật Hooking nếu ko muốn viết toàn bộ Class MsgBox. Vì sau khi Msgbox xuất hiện thì ta nhấn nút OK để thoát, sau đó mới tìm hwnd của nút OK thì làm sao thấy? Không chừng tìm lộn nút OK trên Form thì "tiêu"


Quay về “[VB] Bài viết hướng dẫn”

Đang trực tuyến

Đang xem chuyên mục này: Không có thành viên nào trực tuyến.1 khách