Microsoft Active Accessibility (MSAA) can be used in GUI test automation or for accessibility. For test automation purposes, IAccessible::get_accName can be used to retrieve name of an edit box. To make this to work for MFC based applications, the tab order sequence should be modified such that the static label at the left of the edit box is one number lower. For example, if the edit box's tab order number is 5, the static label on the left should have tab order of 4. For MFC based application created using VS2010, menu Format | Tab Order (Ctrl + D) should show the order sequence graphically.
Note that this is applicable to the following test automation tools/frameworks:
- Test Partner
- Rational Robot
- UI Automation
Just to stress this out again, you need to have a static label to the left of the edit box for this work.
Enjoy!
References:
http://msdn.microsoft.com/en-us/library/dd373597(v=VS.85).aspx
http://msdn.microsoft.com/en-us/library/dd318483(VS.85).aspx
~ts
Showing posts with label Test Automation. Show all posts
Showing posts with label Test Automation. Show all posts
Sunday, November 21, 2010
Tuesday, December 02, 2008
Sunday, November 23, 2008
COM hooking research
This post is gonna be a work in progress. What I am trying to embark on is the possibility of inserting hooks to a running COM server to perform automated testing. I have seen applications tried to do this, like TestPartner, but it is crashing my application under test.
Summary of available tools that may have a working COM server hooks:
TestPartner - they have ComSpy but this is crashing my application under test.
COMslicer - from the help file. COMslicer is a utility that displays information about COM/DCOM components’ activity. It reports all methods and properties called by a client of a COM component and shows values for input/output parameters. COMslicer also reports creation and destroying of COM objects as well as raising events by COM objects. It keeps track of reference counting and interfaces queried by a client. COMslicer works on Windows 98/Me/ NT4/2K. But it seems to me that the development of this tools has halted. A quick visit to their website does not event mention about COMslicer software, rather it shows topics about food stuff. I tried installing the software in Vista and it chokes up, so this one is no good for me as my target applications need to run in Vista and Windows Server 2008
Below are some of the information I have scoured over in the internet that may help in COM spying. DLL injection, Detours and Deviare looks interesting.
GUI Hooking
Below are some of the information I have scoured over in the internet that may help in COM spying. DLL injection, Detours and Deviare looks interesting.
Component Object Model (link ) - This wikipedia article discussed the history of COM and some high level details.
What are test hooks? link
The use of P/Invoke in Automation (.net link )
How to set a Windows hook in Visual C# .NET (link )
Windows Automation API 3.0 Overview (link )
GUI Automation with pyAA (link )Advanced
Automating Windows Applications - http://www.codeproject.com/KB/COM/automatingwindowsapps.aspx?fid=13658&df=90&mpp=25&noise=3&sort=Position&view=Quick&fr=26
SpyStuio - http://www.nektra.com/products/spystudio
Remote Library Loading - http://www.codeguru.com/Cpp/W-P/dll/article.php/c3651
Discusses about advanced hooking/spying techniques
API hooking revealed - http://www.codeproject.com/KB/system/hooksys.aspx
Monday, November 10, 2008
InstallShield crashing when run from a remote machine using STAF
I have been using STAF/STAX for a while now as a framework on top of software test automation. When we started moving some of our tests in Windows Vista noticed that there have been cases where uninstallation of the software under test is crashing. I thought it was some component not playing well with Windows Vista but I when I tried to perform the uninstallation sequence manually everything was fine and dandy. So I started digging around and I found out that in Windows Vista, the following command may fail.
Poking around even more and I finally found a workaround, to get the above command working in Vista, do:
Notice the use of shell to make this command to work. I would have loved to know why this is causing problem in Windows Vista and not in XP/W2k3.
~ts
C:\>staf remotemachine process start command "C:\PROGRA~1\COMMON~1\INSTAL~1\Driver\1150\INTEL3~1\IDriver.exe /M^{1CD6500F-DE1E-44AC-A279-4C85247A9A85^}"
Poking around even more and I finally found a workaround, to get the above command working in Vista, do:
C:\>staf remotemachine process start shell command "C:\PROGRA~1\COMMON~1\INSTAL~1\Driver\1150\INTEL3~1\IDriver.exe /M^{1CD6500F-DE1E-44AC-A279-4C85247A9A85^}"
~ts
Sunday, October 26, 2008
Controlling Popup menu using Accessibility API
In my previous post I discussed about using Accessibility API to control Windows Start Menu. For this blogpost exercise we will control a popup menu using AA.
For those who are familiar with VBA, they would know outright that class modules cannot use AddressOf operator within the class definition. In the spirit of Object Oriented programming, it would have been better to use solely class module for this but due to AddressOf requirements that it should be in a module then we will try to mix and match using both Class module and a module. The code is not a elegant as I hope it would be but this is the way VBA was designed.
Now let us get our hands dirty, first we will create a class module named CPopupMenuController. This is a very simple class module, in the initialization section we set a hook to receive focus events coming from the system and remove the hook once the object is destroyed. See below for the code:
MPopupMenuController does the workhorse for this implementation, basically it houses the function when we set a hook to focus events. The module is also responsible for sending key sequences. See below for the code, save this as MPopupMenuController:
Notice that we use custom error constant to raise an error to the system. The constants are defined in a module named CustomErrorConstants, see below for the code.
Now the fun part, how to use? See below for a sample code.
Note that the above code is geared towards TestPartner 6.1.x. It is a functional test automation and a VBA host. This should work with minor modification to any VBA hosts like Excel, MSAcess ..etc.
Enjoy!
TS
For those who are familiar with VBA, they would know outright that class modules cannot use AddressOf operator within the class definition. In the spirit of Object Oriented programming, it would have been better to use solely class module for this but due to AddressOf requirements that it should be in a module then we will try to mix and match using both Class module and a module. The code is not a elegant as I hope it would be but this is the way VBA was designed.
Now let us get our hands dirty, first we will create a class module named CPopupMenuController. This is a very simple class module, in the initialization section we set a hook to receive focus events coming from the system and remove the hook once the object is destroyed. See below for the code:
'------------------------------------------------------------------------------ ' Developed by : Techno.Scavenger ' Licensed to : Mankind ' Date : 26Oct2008 @ 3:06 PM + 8 GMT (Sunday @home) ' Warranty ' THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ' “Techno.Scavenger” OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY CLAIM, ' DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ' OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ' USE OR OTHER DEALINGS IN THE SOFTWARE. ' Note: ' You can do whatever with this code '------------------------------------------------------------------------------ 'References: 'http://msdn.microsoft.com/en-us/library/ms697639(VS.85).aspx 'http://www.microsoft.com/downloads/details.aspx?familyid=3755582A-A707-460A-BF21-1373316E13F0&displaylang=en 'http://support.microsoft.com/kb/315519 'http://blogs.msdn.com/oldnewthing/archive/2004/04/23/118893.aspx 'http://www.eggheadcafe.com/software/aspnet/32676356/toolbarwindow32-button-in.aspx 'http://msdn.microsoft.com/en-us/library/ms696152(VS.85).aspx 'http://msdn.microsoft.com/en-us/library/ms971323.aspx 'Caret Tracking 'http://www.geocities.com/krishnapg/EventTracking.html '------------------------------------------------------- 'Visual Basic Related 'http://www.brainbell.com/tutors/Visual_Basic/Retrieving_Accessibility_Information.htm 'sample code with hooks to AA 'http://www.eggheadcafe.com/software/aspnet/31694003/please-help-ie-window-do.aspx 'http://www.jsware.net/jsware/vbcode.php5#acc 'Notes: 'Seems like in VB, there is no need to call VariantClear for variants defined as [out] in API. Option Explicit 'references 'Accessibility - oleacc.dll Private Declare Function AccessibleObjectFromEvent Lib "oleacc" (ByVal hwnd As Long, ByVal dwId As Long, ByVal dwChildId As Long, ppacc As IAccessible, pvarChild As Variant) As Long Private Declare Sub OutputDebugString Lib "kernel32" Alias "OutputDebugStringA" (ByVal lpOutputString As String) Private Declare Function SetWinEventHook Lib "user32.dll" (ByVal eventMin As Long, ByVal eventMax As Long, ByVal hmodWinEventProc As Long, ByVal pfnWinEventProc As Long, ByVal idProcess As Long, ByVal idThread As Long, ByVal dwFlags As Long) As Long Private Declare Function UnhookWinEvent Lib "user32.dll" (ByVal lHandle As Long) As Long 'event constants Private Const EVENT_OBJECT_CREATE = &H8000& ' // hwnd + ID + idChild is created item Private Const EVENT_OBJECT_DESTROY = &H8001& '// hwnd + ID + idChild is destroyed item Private Const EVENT_OBJECT_SHOW = &H8002& '// hwnd + ID + idChild is shown item Private Const EVENT_OBJECT_HIDE = &H8003& '// hwnd + ID + idChild is hidden item Private Const EVENT_OBJECT_FOCUS = &H8005& '// hwnd + ID + idChild is focused item Private Const EVENT_OBJECT_LOCATIONCHANGE = &H800B& '// hwnd + ID + idChild is moved/sized item Private Const WINEVENT_OUTOFCONTEXT = &H0& '// Events are ASYNC Private Const WINEVENT_SKIPOWNPROCESS = &H2& '// Don't call back for events on installer's process 'class private stuff Private m_hHook As Long Private m_sMenuPath As String Private Sub Class_Initialize() Include "Common.MPopupMenuController" m_hHook = SetWinEventHook(EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, 0&, AddressOf MPopupMenuController.WinEventFunc, 0, 0, WINEVENT_SKIPOWNPROCESS) End Sub Private Sub Class_Terminate() Dim lRet As Long If m_hHook <> 0 Then lRet = UnhookWinEvent(m_hHook) End If End Sub Public Sub SelectMenu(sMenuPath As String) MPopupMenuController.SelectMenu sMenuPath End Sub
MPopupMenuController does the workhorse for this implementation, basically it houses the function when we set a hook to focus events. The module is also responsible for sending key sequences. See below for the code, save this as MPopupMenuController:
'------------------------------------------------------------------------------
' Developed by : Techno.Scavenger
' Licensed to : Mankind
' Date : 26Oct2008 @ 3:06 PM + 8 GMT (Sunday @home)
' Warranty
' THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
' “Techno.Scavenger” OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY CLAIM,
' DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
' OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
' USE OR OTHER DEALINGS IN THE SOFTWARE.
' Note:
' You can do whatever with this code
'------------------------------------------------------------------------------
'references
'Accessibility - oleacc.dll
Option Explicit
Private Declare Function AccessibleObjectFromEvent Lib "oleacc" (ByVal hwnd As Long, ByVal dwId As Long, ByVal dwChildId As Long, ppacc As IAccessible, pvarChild As Variant) As Long
Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Private Declare Sub OutputDebugString Lib "kernel32" Alias "OutputDebugStringA" (ByVal lpOutputString As String)
Private Declare Sub SleepEx Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
'key constants
Private Const KEYEVENTF_KEYUP = 2
Private Const vbKeyControl = 17
Private Const vbKeyEscape = 27
'event constants
Private Const EVENT_OBJECT_CREATE = &H8000& '// hwnd + ID + idChild is created item
Private Const EVENT_OBJECT_DESTROY = &H8001& '// hwnd + ID + idChild is destroyed item
Private Const EVENT_OBJECT_SHOW = &H8002& '// hwnd + ID + idChild is shown item
Private Const EVENT_OBJECT_HIDE = &H8003& '// hwnd + ID + idChild is hidden item
Private Const EVENT_OBJECT_FOCUS = &H8005& '// hwnd + ID + idChild is focused item
Private Const EVENT_OBJECT_LOCATIONCHANGE = &H800B& '// hwnd + ID + idChild is moved/sized item
'private data
Private m_sMenuPath As String
Private m_sActiveItem As String
Public Function WinEventFunc(ByVal hHook As Long, ByVal lEvent As Long, ByVal hwnd As Long, ByVal idObject As Long, ByVal idChild As Long, ByVal idEventThread As Long, ByVal dwmsEventTime As Long) As Long
Dim ObA As IAccessible
Dim lRet As Long
Dim v As Variant
Dim s As String, s1 As String, sName As String
Dim sTmp As String
On Error Resume Next
sTmp = "TS"
Select Case lEvent
'Case EVENT_OBJECT_CREATE, EVENT_OBJECT_DESTROY, EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE, EVENT_OBJECT_FOCUS, EVENT_OBJECT_LOCATIONCHANGE
Case EVENT_OBJECT_FOCUS
lRet = AccessibleObjectFromEvent(hwnd, idObject, idChild, ObA, v)
If lRet = 0 Then
sTmp = sTmp & ":Name:<" & ObA.accName(v)
sTmp = sTmp & ">:Description:< " & ObA.accDescription(v)
sTmp = sTmp & ">:Role<: " & ObA.accRole(v)
sTmp = sTmp & ">:State<: " & ObA.accState(v)
sTmp = sTmp & ">:menu<: " & m_sMenuPath
m_sActiveItem = ObA.accName(v)
End If
OutputDebugString sTmp
End Select
WinEventFunc = 0
End Function
Public Sub SelectMenu(sMenuPath As String)
m_sMenuPath = sMenuPath
PopupMenuEx sMenuPath
End Sub
Private Sub PopupMenuEx(sMenuPath As String)
Const MAX_LOOPS = 50
Dim vMenu As Variant
Dim iDx As Integer
Dim sMenuBookMark As String
Dim iTerminateCounter
vMenu = Split(sMenuPath, "~")
Call keybd_event(vbKeyControl, 0, 0, 0)
Call keybd_event(vbKeyEscape, 0, 0, 0)
' Release the two keys
Call keybd_event(vbKeyControl, 0, KEYEVENTF_KEYUP, 0)
Call keybd_event(vbKeyEscape, 0, KEYEVENTF_KEYUP, 0)
SleepEx 1000
For iDx = 0 To UBound(vMenu)
Do While m_sActiveItem <> vMenu(iDx)
OutputDebugString "TS: Sending DOWN key"
SendKeys "{DOWN}", True
SleepEx 1000
'set book on first loop thru menu indexes
If sMenuBookMark = "" Then
sMenuBookMark = m_sActiveItem
Else
'if we are here, then this must have been after one round
'we have come full circle, need to raise an error
If m_sActiveItem = sMenuBookMark Then
OutputDebugString "TS: We have come full circle, raising an error"
Include "Common.CustomErrorConstants"
Err.Raise CustomErrorConstants.vbErrMenuNotFound, "MPopupMenuController", "Menu was not found"
End If
End If
'another check if we have gone wild
iTerminateCounter = iTerminateCounter + 1
If iTerminateCounter >= MAX_LOOPS Then
OutputDebugString "TS:Max loops detected, raising an error"
Err.Raise CustomErrorConstants.vbErrMenuNotFound, "MPopupMenuController", "Menu was not found"
End If
Loop
'clear bookmark
sMenuBookMark = ""
'reset terminate marker
iTerminateCounter = 0
'move to next menu
OutputDebugString "TS:Sending RIGHT key"
SendKeys "{RIGHT}", True
Next
'assume we found the item, then hit on enter key
If vMenu(UBound(vMenu)) = m_sActiveItem Then
OutputDebugString "TS: We are about to run " & m_sActiveItem
SendKeys "~", True
Else
MsgBox "nah, not found"
End If
End Sub
Notice that we use custom error constant to raise an error to the system. The constants are defined in a module named CustomErrorConstants, see below for the code.
'------------------------------------------------------------------------------ ' Developed by : Techno.Scavenger ' Licensed to : Mankind ' Date : 26Oct2008 @ 1:39 AM + 8 GMT (Sunday @home) ' Warranty ' THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ' “Techno.Scavenger” OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY CLAIM, ' DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ' OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ' USE OR OTHER DEALINGS IN THE SOFTWARE. ' Note: ' You can do whatever with this code '------------------------------------------------------------------------------ Option Explicit 'Menu not found Public Const vbErrMenuNotFound = vbObjectError + 4
Now the fun part, how to use? See below for a sample code.
'------------------------------------------------------------------------------
' Developed by : Techno.Scavenger
' Licensed to : Mankind
' Date : 26Oct2008 @ 3:06 PM + 8 GMT (Sunday @home)
' Warranty
' THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
' “Techno.Scavenger” OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY CLAIM,
' DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
' OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
' USE OR OTHER DEALINGS IN THE SOFTWARE.
' Note:
' You can do whatever with this code
'------------------------------------------------------------------------------
Option Explicit
Sub Main()
Window("Application=EXPLORER.EXE Caption=NewFolder").Attach
ListView("Index=1").Click 16, 295, tpMouseRight
Include "Common.CPopupMenuController"
Dim sm As CPopupMenuController
Set sm = New CPopupMenuController
sm.SelectMenu "New~Folder"
Set sm = Nothing
End Sub
Note that the above code is geared towards TestPartner 6.1.x. It is a functional test automation and a VBA host. This should work with minor modification to any VBA hosts like Excel, MSAcess ..etc.
Enjoy!
TS
Saturday, October 25, 2008
Start Menu handler using Accessibility API
The code below demonstrates how to run an application from Start menu using accessibility API in TestPartner making use of VBA.
For this exercise, we will use Test Script, Class Module and Module. The original intent was to have the functionality built into class module and instantiate it in Test Script. But AddressOf operator does not work inside a class module in VBA hence using Module.
Anyway, first let us define the class module. For this exercise name it CStartMenuController. See below for the code (save this as CStartMenuController):
'------------------------------------------------------------------------------
' Develop by : Techno.Scavenger
' Licensed to : Mankind
' Date : 26Oct2008 @ 1:39 AM + 8 GMT (Sunday @home)
' Warranty
' THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
' “Techno.Scavenger” OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY CLAIM,
' DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
' OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
' USE OR OTHER DEALINGS IN THE SOFTWARE.
' Note:
' You can do whatever with this code
'------------------------------------------------------------------------------
'References:
'http://msdn.microsoft.com/en-us/library/ms697639(VS.85).aspx
'http://www.microsoft.com/downloads/details.aspx?familyid=3755582A-A707-460A-BF21-1373316E13F0&displaylang=en
'http://support.microsoft.com/kb/315519
'http://blogs.msdn.com/oldnewthing/archive/2004/04/23/118893.aspx
'http://www.eggheadcafe.com/software/aspnet/32676356/toolbarwindow32-button-in.aspx
'http://msdn.microsoft.com/en-us/library/ms696152(VS.85).aspx
'http://msdn.microsoft.com/en-us/library/ms971323.aspx
'Caret Tracking
'http://www.geocities.com/krishnapg/EventTracking.html
'-------------------------------------------------------
'Visual Basic Related
'http://www.brainbell.com/tutors/Visual_Basic/Retrieving_Accessibility_Information.htm
'sample code with hooks to AA
'http://www.eggheadcafe.com/software/aspnet/31694003/please-help-ie-window-do.aspx
'http://www.jsware.net/jsware/vbcode.php5#acc
'Notes:
'Seems like in VB, there is no need to call VariantClear for variants defined as [out] in API.
Option Explicit
'references
'Accessibility - oleacc.dll
Private Declare Function AccessibleObjectFromEvent Lib "oleacc" (ByVal hwnd As Long, ByVal dwId As Long, ByVal dwChildId As Long, ppacc As IAccessible, pvarChild As Variant) As Long
Private Declare Sub OutputDebugString Lib "kernel32" Alias "OutputDebugStringA" (ByVal lpOutputString As String)
Private Declare Function SetWinEventHook Lib "user32.dll" (ByVal eventMin As Long, ByVal eventMax As Long, ByVal hmodWinEventProc As Long, ByVal pfnWinEventProc As Long, ByVal idProcess As Long, ByVal idThread As Long, ByVal dwFlags As Long) As Long
Private Declare Function UnhookWinEvent Lib "user32.dll" (ByVal lHandle As Long) As Long
'event constants
Private Const EVENT_OBJECT_CREATE = &H8000& ' // hwnd + ID + idChild is created item
Private Const EVENT_OBJECT_DESTROY = &H8001& '// hwnd + ID + idChild is destroyed item
Private Const EVENT_OBJECT_SHOW = &H8002& '// hwnd + ID + idChild is shown item
Private Const EVENT_OBJECT_HIDE = &H8003& '// hwnd + ID + idChild is hidden item
Private Const EVENT_OBJECT_FOCUS = &H8005& '// hwnd + ID + idChild is focused item
Private Const EVENT_OBJECT_LOCATIONCHANGE = &H800B& '// hwnd + ID + idChild is moved/sized item
Private Const WINEVENT_OUTOFCONTEXT = &H0& '// Events are ASYNC
Private Const WINEVENT_SKIPOWNPROCESS = &H2& '// Don't call back for events on installer's process
'class private stuff
Private m_hHook As Long
Private m_sMenuPath As String
Private Sub Class_Initialize()
Include "Common.MStartMenuController"
m_hHook = SetWinEventHook(EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, 0&, AddressOf MStartMenuController.WinEventFunc, 0, 0, WINEVENT_SKIPOWNPROCESS)
End Sub
Private Sub Class_Terminate()
Dim lRet As Long
If m_hHook <> 0 Then
lRet = UnhookWinEvent(m_hHook)
End If
End Sub
Public Sub SelectMenu(sMenuPath As String)
MStartMenuController.SelectMenu sMenuPath
End Sub
As mentioned above, we need a module to house the function we supply to SetWinEventHook. And this is also where most of the action happens. See below for the code, save this as MStartMenuController:
'------------------------------------------------------------------------------
' Develop by : Techno.Scavenger
' Licensed to : Mankind
' Date : 26Oct2008 @ 1:39 AM + 8 GMT (Sunday @home)
' Warranty
' THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
' “Techno.Scavenger” OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY CLAIM,
' DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
' OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
' USE OR OTHER DEALINGS IN THE SOFTWARE.
' Note:
' You can do whatever with this code
'------------------------------------------------------------------------------
'references
'Accessibility - oleacc.dll
Option Explicit
Private Declare Function AccessibleObjectFromEvent Lib "oleacc" (ByVal hwnd As Long, ByVal dwId As Long, ByVal dwChildId As Long, ppacc As IAccessible, pvarChild As Variant) As Long
Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Private Declare Sub OutputDebugString Lib "kernel32" Alias "OutputDebugStringA" (ByVal lpOutputString As String)
Private Declare Sub SleepEx Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
'key constants
Private Const KEYEVENTF_KEYUP = 2
Private Const vbKeyControl = 17
Private Const vbKeyEscape = 27
'event constants
Private Const EVENT_OBJECT_CREATE = &H8000& '// hwnd + ID + idChild is created item
Private Const EVENT_OBJECT_DESTROY = &H8001& '// hwnd + ID + idChild is destroyed item
Private Const EVENT_OBJECT_SHOW = &H8002& '// hwnd + ID + idChild is shown item
Private Const EVENT_OBJECT_HIDE = &H8003& '// hwnd + ID + idChild is hidden item
Private Const EVENT_OBJECT_FOCUS = &H8005& '// hwnd + ID + idChild is focused item
Private Const EVENT_OBJECT_LOCATIONCHANGE = &H800B& '// hwnd + ID + idChild is moved/sized item
'private data
Private m_sMenuPath As String
Private m_sActiveItem As String
Public Function WinEventFunc(ByVal hHook As Long, ByVal lEvent As Long, ByVal hwnd As Long, ByVal idObject As Long, ByVal idChild As Long, ByVal idEventThread As Long, ByVal dwmsEventTime As Long) As Long
Dim ObA As IAccessible
Dim lRet As Long
Dim v As Variant
Dim s As String, s1 As String, sName As String
Dim sTmp As String
On Error Resume Next
sTmp = "YH"
Select Case lEvent
'Case EVENT_OBJECT_CREATE, EVENT_OBJECT_DESTROY, EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE, EVENT_OBJECT_FOCUS, EVENT_OBJECT_LOCATIONCHANGE
Case EVENT_OBJECT_FOCUS
lRet = AccessibleObjectFromEvent(hwnd, idObject, idChild, ObA, v)
If lRet = 0 Then
sTmp = sTmp & ":Name:<" & ObA.accName(v) sTmp = sTmp & ">:Description:< " & ObA.accDescription(v) sTmp = sTmp & ">:Role<: " & ObA.accRole(v) sTmp = sTmp & ">:State<: " & ObA.accState(v) sTmp = sTmp & ">:menu<: " & m_sMenuPath m_sActiveItem = ObA.accName(v) End If OutputDebugString sTmp End Select WinEventFunc = 0 End Function Public Function SetMenuPath(sMenuPath As String) As Boolean m_sMenuPath = sMenuPath End Function Public Sub SelectMenu(sMenuPath As String) m_sMenuPath = sMenuPath StartMenuEx sMenuPath End Sub Private Sub StartMenuEx(sMenuPath As String) Const MAX_LOOPS = 50 Dim vMenu As Variant Dim iDx As Integer Dim sMenuBookMark As String Dim iTerminateCounter vMenu = Split(sMenuPath, "~") Call keybd_event(vbKeyControl, 0, 0, 0) Call keybd_event(vbKeyEscape, 0, 0, 0) ' Release the two keys Call keybd_event(vbKeyControl, 0, KEYEVENTF_KEYUP, 0) Call keybd_event(vbKeyEscape, 0, KEYEVENTF_KEYUP, 0) SleepEx 1000 For iDx = 0 To UBound(vMenu) Do While m_sActiveItem <> vMenu(iDx)
OutputDebugString "YH: Sending DOWN key"
SendKeys "{DOWN}", True
SleepEx 1000
'set book on first loop thru menu indexes
If sMenuBookMark = "" Then
sMenuBookMark = m_sActiveItem
Else
'if we are here, then this must have been after one round
'we have come full circle, need to raise an error
If m_sActiveItem = sMenuBookMark Then
OutputDebugString "YH: We have come full circle, raising an error"
Include "Common.CustomErrorConstants"
Err.Raise CustomErrorConstants.vbErrMenuNotFound, "MStartMenuController", "Menu was not found"
End If
End If
'another check if we have gone wild
iTerminateCounter = iTerminateCounter + 1
If iTerminateCounter >= MAX_LOOPS Then
OutputDebugString "YH:Max loops detected, raising an error"
Err.Raise CustomErrorConstants.vbErrMenuNotFound, "MStartMenuController", "Menu was not found"
End If
Loop
'clear bookmark
sMenuBookMark = ""
'reset terminate marker
iTerminateCounter = 0
'move to next menu
OutputDebugString "YH:Sending RIGHT key"
SendKeys "{RIGHT}", True
Next
'assume we found the item, then hit on enter key
If vMenu(UBound(vMenu)) = m_sActiveItem Then
OutputDebugString "YH: We are about to run " & m_sActiveItem
SendKeys "~", True
Else
MsgBox "nah, not found"
End If
End Sub
To make the code a little modular, we have separated custom error constants for use when raising our custom Error. See below for constant definitions and save this as CustomErrorConstants.
'------------------------------------------------------------------------------ ' Developed by : Techno.Scavenger ' Licensed to : Mankind ' Date : 26Oct2008 @ 1:39 AM + 8 GMT (Sunday @home) ' Warranty ' THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ' “Techno.Scavenger” OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY CLAIM, ' DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ' OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ' USE OR OTHER DEALINGS IN THE SOFTWARE. ' Note: ' You can do whatever with this code '------------------------------------------------------------------------------ Option Explicit 'Menu not found Public Const vbErrMenuNotFound = vbObjectError + 4Now, how do we use it? We it is quite easy actually. See below for a sample code that runs HyperTerminal. Save it as scratch or whatever suites you best.
'------------------------------------------------------------------------------ ' Develop by : Techno.Scavenger ' Licensed to : Mankind ' Date : 26Oct2008 @ 1:39 AM + 8 GMT (Sunday @home) ' Warranty ' THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ' “Techno.Scavenger” OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY CLAIM, ' DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ' OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ' USE OR OTHER DEALINGS IN THE SOFTWARE. ' Note: ' You can do whatever with this code '------------------------------------------------------------------------------ Option Explicit Sub Main() Include "Common.CStartMenuController" Dim sm As CStartMenuController Set sm = New CStartMenuController sm.SelectMenu "All Programs~Accessories~Communications~HyperTerminal" Set sm = Nothing End SubNotes: This code is targeted for TestPartner 6.1.x. This should work with any VBA host but you need to adjust a few things. This is also inteneded to work only with Start Menu set to Windows XP style. It should be easy to adapt this for both classic and XP start menu. Enjoy! TS
Saturday, August 16, 2008
Print active application and title using pywinauto
Code snippet below shows how to get the window title and application name of the active application. That is the application on top of the z-order. Need to install pywinauto to get this to work.
~ts
import pywinauto.application import pywinauto.handleprops as _handleprops import pywinauto.win32functions as _win32functions import time while 1: hwnd = _win32functions.GetForegroundWindow() print "Active Window title is %s"%(_handleprops.text(hwnd)) print "Application name is %s"%(pywinauto.application.process_module(_handleprops.processid(hwnd))) time.sleep(2)
~ts
Subscribe to:
Posts (Atom)
CPP Quick Guide
Basics Hello world User input While loop If statement For loop Switch statement Read file using ifstream Write to a file using ofstr...
-
Minimal OPC UA client that auto generates self signed certificate on startup in C# This is minimal OPC UA client in C# that demonstrates se...
-
Install Winget on Windows 2022 or Windows 10 LTSC Install Pre-reqs Install Microsoft.UI.Xaml/2.8.6 Navigate to https://www.nuget.org/pa...
-
Installing MonoDevelop in OpenSUSE 12.2 from its repository was very easy. When running it for the first time though I got the message: Th...