Lập trình tương tác với các Dialog , Menu hệ thống của Excel

Liên hệ QC

doveandrose

hello
Tham gia
3/7/09
Bài viết
2,375
Được thích
2,264
Chào các bạn diễn đàn GPE
lâu nay chúng ta thường gặp rất nhiều cửa sổ Dialog , hoặc Menu hệ thống của Excel
Nhưng có bao giờ các bạn thử tìm cách lấy nội dung trên các cửa sổ đó ?
Tôi đã từng đặt vấn đề này , và tôi chỉ nhận được câu trả lời "không có manh mối"
Cái Bill dành cho chúng ta chỉ là
Mã:
Application.Dialogs(dialogID).Show
để xem . Như kiểu muốn nói với chúng ta là : Chỉ được xem , cấm sờ vào hiện vật
Điều này làm tôi ức chế đã lâu , tôi lục lọi các nơi , và cuối cùng tôi cũng tìm ra cách truy cập vào các cửa sổ ấy :
Dùng UIAutomation
với UIAutomation , tôi tin rằng chúng ta có thể
Truy cập vào các Dialog hệ thống để lấy nội dung trong ấy ra
Truy câp vào các Menu ( Như menu Auto Filter ) để lấy nội dung trên Menu
Bắt sự kiện Cell TextChange khi Đang ở chế độ Edit Mode


Chúng ta sẽ không nói nhiều về Lý thuyết mà đi thẳng vào áp dụng đầu tiên :
Lấy nội dung trên Dialog Select Sheet của Excel : Đồng nghĩa với việc lấy các Sheet trên File đang đóng hoặc mở chính xác nhất
khi làm việc cùng UIAutomation thì bắt buộc phải check vào thư viện UIAutomationClient

d3c97029eeb16bb59031ec79719f1558.png


nói 1 chút về các Object của UIAutomation
CUIAutomation : đây là cái lò sản xuất ra các Object khác , đồng thời cung cấp các phương thức để làm việc với các Object UIAutomation
IUIAutomationElement : đây là thành phần cơ bản đại diện cho mọi đối tượng UI của Hệ điều hành , từ 1 cửa sổ ứng dụng , hay 1 control , 1 menu , 1 toolTip,...
kể cả những Control nhỏ bé không được cấp chỉ số HWND . Chúng ta sẽ làm việc chủ yếu với Object này


Xác định Cửa Sổ Excel
Mã:
Set myApp = cUI.ElementFromHandle(ByVal Application.Hwnd)

Khi Dialog Select Sheet hiện ra thì có Danh sách Sheet nằm sẵn trong Control Listbox của Dialog để chúng ta lấy không ? rất tiếc là không
Vì Excel đang làm nhiệm vụ chạy Code rất bí mật để lấy Danh sách Sheet, khi nào có kết quả thì mới dán lên Dialog sau (bất đồng bộ)
Vậy phải làm sao ?
Chúng ta nhìn thấy rằng khi đã có Danh sách Sheet thì Dialog tự động Select item đầu tiên của Listbox
thông thường khi viết Code , chúng ta AddItem cho Listbox xong xuôi thì mới nghĩ đến chuyện Select Item nào
Vậy suy bụng ta ra bụng người , khi Select Item có nghĩa là Đã AddItem xong
Ta sẽ bắt sự kiện Selection trên Listbox của Dialog
Để làm được điều này UIAutomation cung cấp Interface IUIAutomationEventHandler
Thực hiện :
Các bạn tạo mới 1 Class Module
gõ vào Class lệnh này
Implements IUIAutomationEventHandler
gõ Enter
bây giờ trong Combobox góc trên bên trái bạn bấm vào rồi chọn IUIAutomationEventHandler

5669670f407a8277bc1d4fcd498ee2ad.png


nó sẽ tự động hiện ra
Private Sub IUIAutomationEventHandler_HandleAutomationEvent(ByVal sender As UIAutomationClient.IUIAutomationElement, ByVal eventId As Long)
đây là nơi chúng ta thực hiện Code khi Sự kiện Selection xảy ra
Bạn Click vào Property của Class Module này

a097d8a0c128532108bc92b83dd28412.png



Nó đang ở Chế độ Private
Sửa lại thành PublicNotCreateAble
Save

Quay lại Sub , trước khi Dialog hiện ra , ta phải gắn Track sự kiện
Mã:
cUI.AddAutomationEventHandler UIA_SelectionItem_ElementSelectedEventId, myApp, _
TreeScope_Descendants, Nothing, New Class1

UIA_SelectionItem_ElementSelectedEventId : mã số cho biết sẽ Track sự kiện SelectionItem
TreeScope_Descendants : nói rằng sẽ Track sự kiện trên tất cả Control con cháu của cửa sổ Excel
Bây giờ khi sự kiện SelectionItem xảy ra thì ta làm gì đây ?
Ta làm quen các Object mới
IUIAutomationTreeWalker : giúp truy tìm các thành phần cha hoặc con của IUIAutomationElement
khi Sự kiện Selection xảy ra thì nó được tính cho Control ListItem của Listbox vì vậy Sender là 1 ListItem

Mã:
Set myForm = walker.GetParentElement(sender) 'Listbox
Set myForm = walker.GetParentElement(myForm) 'Dialog Select Sheet

ta gọi GetParentElement 2 lần để tìm đến cửa sổ cha
IUIAutomationCondition : thiết lập điều kiện để truy tìm các thành phần IUIAutomationElement
có rất nhiều loại Condition có thể thiết lập , như truy theo Name ( caption của 1 cửa sổ ), ClassName , theo ControlType,...
ở đây là dùng truy theo ControlType
Mã:
Set condition = cUI.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ListItemControlTypeId)

TreeScope : tầm vực tìm kiếm
TreeScope_Descendants : tìm ở tất cả vùng con cháu dòng họ của 1 IUIAutomationElement
TreeScope_Children : chỉ tìm thành phần con trực tiếp của 1 IUIAutomationElement
TreeScope_Element : trỏ đến chính IUIAutomationElement đó

khi gọi
Mã:
Set elemColl = myForm.FindAll(TreeScope_Descendants, condition)
ta đã có Danh sách các ListItem của Listbox
Ta dùng Thuộc tính CurrentName để lấy giá trị Text của các ListItem
Mã:
If elemColl.Length > 0 Then   
    ReDim rsSheetNames(1 To elemColl.Length, 1 To 1)
    For r = 1 To elemColl.Length Step 1
        rsSheetNames(r, 1) = elemColl.GetElement(r - 1).CurrentName
    Next
End If
Cuối cùng ta cần Force Click nút OK trên Dialog để đóng nó lại
Mã:
Set condition = cUI.CreatePropertyCondition(UIA_NamePropertyId, "OK")
Set OKbtn = myForm.FindFirst(TreeScope_Children, condition)
Set clickPattern = OKbtn.GetCurrentPattern(UIA_InvokePatternId)
clickPattern.Invoke ' send CLick

Gán kết quả ra Sheet
Mã:
Sheet1.Range("B2:B1000").ClearContents
If IsArray(rsSheetNames) Then
    Sheet1.Range("B2").Resize(UBound(rsSheetNames)).Value = rsSheetNames
End If
Sheet1.Range("C3").ClearContents

Gỡ bỏ mọi Track sự kiện ra khỏi Cửa sổ Excel
Mã:
cUI.RemoveAllEventHandlers
Set cUI = Nothing

Tôi đã trình bày các bước cơ bản nhất để tương tác với các cửa sổ Dialog hệ thống của Excel
Chắc chắn còn nhiều thiếu sót vì chỉ trình bày ở dạng giới thiệu
Còn rất nhiều vấn đề chúng ta cần bàn thêm , mong được trao đổi với các bạn
Trong lần tới chúng ta sẽ nói về việc :
Lấy Nội dung trên Menu AutoFilter của Excel
Hẹn gặp lại các bạn .
 

File đính kèm

  • Book1.xlsb
    20 KB · Đọc: 40
  • Data.xlsx
    10.6 KB · Đọc: 38
Và anh ấy đã ra chiêu...Vấn đề này lúc trước chúng ta đã bàn rất nhiều...như: Menu của AutoFilter, List Sheets Tab,...
Rất cảm ơn DoveAndRose...đã nghiên cứu...!!

Đọc thôi bà con ơi! (nhưng bao giờ mới thấm đây ta...--=0--=0--=0)
 
Upvote 0
Nếu máy không có sẵn thư viện này thì phải làm như thế nào? (Thực ra thì nhìn tưởng là có nhưng thực tế là không có)
Capture.JPG
 
Upvote 0
Upvote 0
Và anh ấy đã ra chiêu...Vấn đề này lúc trước chúng ta đã bàn rất nhiều...như: Menu của AutoFilter, List Sheets Tab,...
Rất cảm ơn DoveAndRose...đã nghiên cứu...!!

Đọc thôi bà con ơi! (nhưng bao giờ mới thấm đây ta...--=0--=0--=0)
thì hôm mục xả xì chét có nói thì ra là vậy......nhưng chưa hiểu lắm ..chưa biết ứng làm gì
Cảm ơn Bạn ý --=0
 
Upvote 0
Bạn tìm trong máy của bạn phai UIAutomationCore.dll trong đường dẫn C:\Windows\System32 rồi Copy qua địa chỉ mà VBA đã ghi
(ở đây là C:\USER\Huuthang\.......) thử xem sao
Sau khi làm theo, thư viện đã có, check không báo lỗi nhưng dùng Macro không có kết quả. Cụ thể như sau:

Chạy sub hello thì hiện ra Dialog select sheet. Click OK thì Dialog biến mất còn mọi thứ thì vẫn như cũ; Click Cancel thì báo lỗi và ô C3 bị lỗi #REF!
 
Upvote 0
Sau khi làm theo, thư viện đã có, check không báo lỗi nhưng dùng Macro không có kết quả. Cụ thể như sau:

Chạy sub hello thì hiện ra Dialog select sheet. Click OK thì Dialog biến mất còn mọi thứ thì vẫn như cũ; Click Cancel thì báo lỗi và ô C3 bị lỗi #REF!

cùng 1 đoạn Code mình đem qua máy 32 bit và 1 máy 64 bit đều chạy được , nhưng đem chạy trên máy ảo của mình thì lại không được
Các bạn nào không chạy được đoạn code trong file excel nữa thì xin báo cho mình biết
Nếu nhiều bạn cũng không chạy được đoạn Code thì chắc Topic không tiếp tục được nữa
Mình không đủ khả năng biết vấn đề nằm ở đâu , có thể File UIAutomationcore.DLL có tham chiếu đến các file thư viện khác trên HĐH chăng ? Cám ơn các bạn đã xem qua Topic
 
Upvote 0
cùng 1 đoạn Code mình đem qua máy 32 bit và 1 máy 64 bit đều chạy được , nhưng đem chạy trên máy ảo của mình thì lại không được
Các bạn nào không chạy được đoạn code trong file excel nữa thì xin báo cho mình biết
Nếu nhiều bạn cũng không chạy được đoạn Code thì chắc Topic không tiếp tục được nữa
Mình không đủ khả năng biết vấn đề nằm ở đâu , có thể File UIAutomationcore.DLL có tham chiếu đến các file thư viện khác trên HĐH chăng ? Cám ơn các bạn đã xem qua Topic
Mạnh Mới thử win7+Office 2010; Winxp+Office2010 Chạy Tốt ..........
 
Upvote 0
Các bạn nào không chạy được đoạn code trong file excel nữa thì xin báo cho mình biết

Mình cũng không chạy được!
Tức là code chạy bình thường, có hiện ra hộp Select Sheet và chỉ có thế thôi, không có bất cứ kết quả nào trên sheet xuất hiện cả
Kiểm tra bằng code:
Mã:
MsgBox TypeName(rsSheetNames)
ra kết quả Empty
(mình dùng Windows 7 + Office 2010)
 
Upvote 0
Mình cũng không chạy được!
Tức là code chạy bình thường, có hiện ra hộp Select Sheet và chỉ có thế thôi, không có bất cứ kết quả nào trên sheet xuất hiện cả
Kiểm tra bằng code:
Mã:
MsgBox TypeName(rsSheetNames)
ra kết quả Empty
(mình dùng Windows 7 + Office 2010)



Sau khi làm theo, thư viện đã có, check không báo lỗi nhưng dùng Macro không có kết quả. Cụ thể như sau:

Chạy sub hello thì hiện ra Dialog select sheet. Click OK thì Dialog biến mất còn mọi thứ thì vẫn như cũ; Click Cancel thì báo lỗi và ô C3 bị lỗi #REF!


đây là File được viết lại theo cách khác , mời các vị anh hùng thử lại
 

File đính kèm

  • Book1.xlsb
    14.1 KB · Đọc: 26
Upvote 0
đây là File được viết lại theo cách khác , mời các vị anh hùng thử lại
Đã test thành công.
Còn một thắc mắc nữa.
Bạn tìm trong máy của bạn phai UIAutomationCore.dll trong đường dẫn C:\Windows\System32 rồi Copy qua địa chỉ mà VBA đã ghi
(ở đây là C:\USER\Huuthang\.......) thử xem sao
Có cách nào đăng ký lại file thư viện trong C:\Windows\System32 không? Để file thư viện ngoài desktop không ổn lắm.
 
Upvote 0
Đã test thành công.
Còn một thắc mắc nữa.

Có cách nào đăng ký lại file thư viện trong C:\Windows\System32 không? Để file thư viện ngoài desktop không ổn lắm.

cái này phải hỏi những người có kinh nghiệm chứ hỏi tôi cũng như không
Bill hành động thật quái lạ , biết thừa là máy nào cũng có cái thư viện đó nằm ở chỗ C:\Windows\System32 mà tự nhiên dời địa chỉ VBA ra chỗ khác ..... Bạn tìm kiếm trên Google có giải pháp nào không ?
còn bạn nào không sử dụng được Code ở trên nữa không xin báo cho tôi được biết ?
 
Upvote 0
cái này phải hỏi những người có kinh nghiệm chứ hỏi tôi cũng như không
Bill hành động thật quái lạ , biết thừa là máy nào cũng có cái thư viện đó nằm ở chỗ C:\Windows\System32 mà tự nhiên dời địa chỉ VBA ra chỗ khác ..... Bạn tìm kiếm trên Google có giải pháp nào không ?
còn bạn nào không sử dụng được Code ở trên nữa không xin báo cho tôi được biết ?
cách đơn giản copy File UIAutomationCore.dll ra cùng Folder với File Excel xong Register lại nó là ok ....Xong Xóa File UIAutomationCore.dll trong cùng Folder với File Excel đi ... mới thử xong
 
Upvote 0
Chào các bạn
Bây giờ chúng ta nói về việc :
lấy nội dung trên Menu Autofilter
Như chúng ta đã biết , Menu autofilter khi hiện ra sẽ chứa 1 danh sách không trùng đã được Sort sẵn của cột đang chọn
Chúng ta hoàn toàn có thể tự Code ra danh sách này , thậm chí là đầy đủ hơn . Vì menu Autofilter chỉ được chứa có 10 000 Unique Item . Nhưng để thỏa mãn sở thích hay nghịch , tôi lại thích nhờ Bill tính toán hộ , tôi chỉ lấy kết quả --=0--=0
Để làm được điều này , ta phải tiếp tục sử dụng Track sự kiện , ở đây tôi chọn sự kiện FocusChanged
Trong UIAutomation , FocusChanged là Global Event , có nghĩa nó sẽ tác động lên mọi Cửa sổ , Control ,... đang mở trên Desktop . Bất cứ cái gì được Focus đều kích hoạt sự kiện FocusChanged .

Đầu tiên ta sẽ cài Track sự kiện và truyền phím tắt để mở AutoFilter , Menu này chỉ mở khi trang tính đang Active
Mã:
Public Sub hello()
rsArr = ""
If Sheet1.[E100000].End(xlUp).Row > 2 Then
    rsArr = ""
    Set cUI = New CUIAutomation
    cUI.AddFocusChangedEventHandler Nothing, New Class2
    If Not Sheet1.AutoFilterMode Then Sheet1.Range("D2:E2").AutoFilter
    Sheet1.[E2].Activate
    Application.SendKeys "%{DOWN}"
End If
End Sub

tương tự bài trước , ta tạo mới 1 Class Module với lệnh
Implements IUIAutomationFocusChangedEventHandler
và nhờ cửa sổ VBA sinh ra thủ tục
Private Sub IUIAutomationFocusChangedEventHandler_HandleFocusChangedEvent(ByVal sender As UIAutomationClient.IUIAutomationElement)

Dùng các chương trình dò Event , tôi chọn ra Control có tên GroupControlType , khi xảy ra sự kiện Focus lên Control này thì Danh sách các Item trên Menu đã có . Các Item này được gọi là TreeItemControl . Vậy công thức truy tìm các Item này như sau
Mã:
Set condition = cUI.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_TreeItemControlTypeId)
Set elemColl = myMenu.FindAll(TreeScope_Descendants, condition)

nếu thành công , ta gán giá trị các TreeItem vào mảng
Mã:
If elemColl.Length > 0 Then
    ReDim rsArr(1 To elemColl.Length - 1, 1 To 1)
    For r = 1 To elemColl.Length - 1 Step 1
        rsArr(r, 1) = elemColl.GetElement(r).CurrentName
    Next

và Đóng Menu , có thể dùng cách Click nút Cancel bằng Code , hoặc truyền Phím ESC đều được
Mã:
Set condition = cUI.CreatePropertyCondition(UIA_NamePropertyId, "Cancel")
Set CancelBtn = myMenu.FindFirst(TreeScope_Descendants, condition)
Set clickPattern = CancelBtn.GetCurrentPattern(UIA_InvokePatternId)
clickPattern.Invoke
hoặc
Mã:
Application.SendKeys "{ESC}" 'Close Menu

Khác với Dialog , Code sẽ không dừng lại để chờ Menu đóng lại , nên việc gán kết quả không viết trong Sub Hello được
mà cũng không viết trực tiếp trong Sub HandleFocusChangedEvent được (treo máy)
Vậy phải dùng lệnh
Mã:
Application.OnTime Now + 0.05 / 24 / 60 / 60, "getResult"

Mã:
Public Sub getResult()
cUI.RemoveAllEventHandlers
Set cUI = Nothing
Application.ScreenUpdating = False
Sheet1.Range("H3:H100000").ClearContents
If IsArray(rsArr) Then
    Sheet1.Range("H3").Resize(UBound(rsArr)).Value = rsArr
End If
Application.ScreenUpdating = True
End Sub

Như vậy chúng ta đã biết cách truy cập vào Menu Autofilter và lấy nội dung ,ngoài ra các bạn nào thấy Dialog hoặc menu nào hấp dẫn , có thể chia sẻ ra đây , để chúng ta thử truy cập đến chúng .
Thư viện UIAutomation còn có thể giúp ta truy cập vào các chương trình khác đang mở trên Desktop nữa , như Chrome chẳng hạn
các bạn có thể tự động truyền nội dung vào ô Soạn bài trả lời , rồi tự động bấm nút Gửi bài vào trang Giaiphapexcel.com
Chỉ sợ bị Admin cho ra đảo hoang thôi --=0--=0
 

File đính kèm

  • autoFilter.xlsb
    52.7 KB · Đọc: 18
Upvote 0
Web KT
Back
Top Bottom