Thông tin

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

Điều hành viên: truongphu

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 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)
Syntax: [ Download ] [ Hide ]
Using vb Syntax Highlighting
Private Sub Command1_Click()
    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
Syntax: [ Download ] [ Hide ]
Using vb Syntax Highlighting
Private Sub Command2_Click()
    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!
Syntax: [ Download ] [ Hide ]
Using vb Syntax Highlighting
Private Sub Command3_Click()
    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:
hWnd of window having ClassName and WindowName.rar
(1.33 KiB) Đã tải về 51 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)

Syntax: [ Download ] [ Hide ]
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
Parsed in 0.006 seconds, using GeSHi 1.0.8.4


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


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:
Syntax: [ Download ] [ Hide ]
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
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:
Syntax: [ Download ] [ Hide ]
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
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:

Syntax: [ Download ] [ Hide ]
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
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:
Syntax: [ Download ] [ Hide ]
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
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!
Syntax: [ Download ] [ Hide ]
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
Parsed in 0.004 seconds, using GeSHi 1.0.8.4


Project:
findwindowex classname.rar
(1.54 KiB) Đã tải về 42 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)
truongphu@caulacbovb.com
Hình đại diện của thành viên
truongphu
Support Group Leader
Support Group Leader
 
Bài viết: 3348
Ngày tham gia: CN 04/11/2007 10:57 am
Đến từ: Thị trấn Cam Đức, H Cam Lâm, Khánh hòa

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

Syntax: [ Download ] [ Hide ]
Using vb Syntax Highlighting
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINT_TYPE) As Long
Private Declare Function WindowFromPoint Lib "user32.dll" (ByVal xPoint As Long, ByVal yPoint As Long) As Long

Private Type POINT_TYPE
     x As Long
     y As Long
End Type

Private Sub Timer1_Timer()
     Dim PT As POINT_TYPE
     GetCursorPos PT
     'Gán hWnd cho label
    Label1.Caption = WindowFromPoint(PT.x, PT.y)
End Sub
 
Parsed in 0.040 seconds, using GeSHi 1.0.8.4


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.
Trời đã sinh Du, sao còn sinh ra Lượng?
:((
Hình đại diện của thành viên
VuVanHoanh
Thành viên tích cực
Thành viên tích cực
 
Bài viết: 199
Ngày tham gia: T.Năm 03/06/2010 9:23 pm
Đến từ: Quảng Ninh

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 tất cả
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 tất cả
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
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

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:
Syntax: [ Download ] [ Hide ]
Using vb Syntax Highlighting
h = FindWindow("#32770", vbNullString)
hh = FindWindowEx(h, 0, "Button", "OK")
Parsed in 0.003 seconds, using GeSHi 1.0.8.4


-------

Ghi chú của điều hành viên: 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
truongphu@caulacbovb.com
Hình đại diện của thành viên
truongphu
Support Group Leader
Support Group Leader
 
Bài viết: 3348
Ngày tham gia: CN 04/11/2007 10:57 am
Đến từ: Thị trấn Cam Đức, H Cam Lâm, Khánh hòa

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

Gửi bàigửi bởi pctester2020 » Hôm qua 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"
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


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.