Login   /   Register

Highlighting the .Net active control in screen-captures

Rate this article
     1 votes, average: 5 out of 51 votes, average: 5 out of 51 votes, average: 5 out of 51 votes, average: 5 out of 51 votes, average: 5 out of 5
Loading ... Loading ...
July 14th, 2009 by Yaron Assa

Whether you’re using your own reporting framework, or QTP’s native reporter, your report is probably filled with a lot of full-desktop screen-captures, which are supposed to make the report more comprehensible, but usually just confuse the average reader. An effective screen-capture should highlight the relevant area in the application, and not leave the reader with the daunting task of scanning every pixel for the relevant information for the report step.

Unfortunately, highlighting the relevant area only occurs when QTP encounters a control specific error (e.g. when a control is disabled or partially hidden). Other times highlighting the relevant control is left up to you, which can be very tedious (you must highlight each object before calling the report command), and something just flat-out impossible to do.

If you happen to work on a .Net application, the following reporting solution would work well most of the time, generically and automatically.

The solution uses the .Net runtime property .ActiveControl, which usually holds the focused child-control of the current .Net object. By drilling down though the .ActiveControl property, you could potentially reach the most inner-focused control, and highlight it.

In order to highlight the object, the code uses external Windows DLL functions, so you must include the following statements once, at the top of your action / external library file:

'Needed for the screen capture mechanism:
Extern.Declare micHwnd, "GetDesktopWindow", "user32", "GetDesktopWindow"
Extern.Declare micULong, "GetWindowDC", "user32", "GetWindowDC", micHwnd
Extern.Declare micInteger, "ReleaseDC", "user32", "ReleaseDC", micHwnd, micULong
Extern.Declare micULong, "CreatePen", "gdi32", "CreatePen", micInteger, micInteger, micDword
Extern.Declare micInteger, "SetROP2", "gdi32", "SetROP2", micULong, micInteger
Extern.Declare micULong, "SelectObject", "gdi32", "SelectObject", micULong, micULong
Extern.Declare micULong, "DeleteObject", "gdi32", "DeleteObject", micULong
Extern.Declare micULong, "GetStockObject", "gdi32", "GetStockObject", micInteger
Extern.Declare micULong, "Rectangle", "gdi32", "Rectangle", micULong, micInteger, micInteger, micInteger, micInteger

And here’s the actual screen-capture functions: ScreenCapture is a helper function which takes the actual capture and saves it to a unique file, and CaptureActiveControl (the function you should call) tries to highlight the active object and snap it.

'This funciton takes the actual capture
'Assume the control is highlighted
'Has a built in mechanim for generating unique file names
Private Function ScreenCapture 'As string = filename
         Dim sImageFile
         
         sImageFile =  "C:\" & Replace(Replace(Now, ":", ""), "/", "") & ".png"
         On Error Resume Next
                'Try the original file name
              desktop.CaptureBitmap(sImageFile)
              While Err.Number <> 0
                    'While the name we generated already exists
                    Err.Clear
                    wait 1
                   sImageFile = "C:\" & Replace(Replace(Now, ":", ""), "/", "") & ".png"
                    desktop.CaptureBitmap(sImageFile)
              Wend
        On Error Goto 0
        
        'Return the file name
        ScreenCapture = sImageFile
End Function      
 
'Catches the active control and captures it
Public Function CaptureActiveControl
   Dim oControl
   Dim iHwnd
        'The foloowing constants and variables are required for the highlight mechanism
        Const PS_SOLID = 1 : Const PS_INSIDEFRAME = 6 : Const R2_NOT = 6
        Const NULL_BRUSH = 5 : Const PEN_WIDTH = 5:
        Dim hDC, hPen
        Dim nX, nY, nH, nW, i
        Dim Sender
 
   On Error Resume Next
        'Check if the main application window exists
        If Not SwfWindow("Your App Main Window Here").Exist(0) Then
            'Just take an image of the desktop and get out
            CaptureActiveControl = ScreenCapture
            Exit Function
        End If
   
    'Get active control - start by attaching to the top main window
   Set oControl = SwfWindow("Your App Main Window Here").Object
 
   Do
        'Keep drilling down until you can now longer find an active child control
        Set oControl = oControl.ActiveControl
   Loop Until oControl.ActiveControl is Nothing
 
   iHwnd = ""
    'Get the inner control’s handle for identification purpose.
   iHwnd = oControl.Handle
 
   If iHwnd = "" Then
       'No .Net active control - get out
        CaptureActiveControl = ScreenCapture
       Exit Function
   End If
 
    'The focused object
   Set Sender = SwfWindow("Your App Main Window Here").SwfObject("hwnd:=" & iHwnd)
 
        ' ** Retieve The sender information…
        With sender
            nX = .GetROProperty( "abs_x" )
            nY = .GetROProperty( "abs_y" )
            nW = .GetROProperty( "width" )
            nH = .GetROProperty( "height" )
        End With
        ' ** Get the Desktop DC
        hDC = Extern.GetWindowDC( Extern.GetDesktopWindow() )
        ' ** Create a three pixel wide pen
        hPen = Extern.CreatePen( PS_INSIDEFRAME, PEN_WIDTH, RGB( 255, 0, 0 ) )
        Extern.SetROP2 hDC, R2_NOT
        Extern.SelectObject hDC, hPen
        ' ** Use an empty fill
        Extern.SelectObject hDC, Extern.GetStockObject( NULL_BRUSH )
        ' ** Do the highlight
            Extern.Rectangle hDC, nX, nY, nX + nW, nY + nH
            'Take the screen capture and save the file name
            CaptureActiveControl = ScreenCapture
            wait 0, 50
        
        ' ** Release Resources '
        Extern.ReleaseDC Extern.GetDesktopWindow, hDC
        Extern.DeleteObject hPen
End Function

CaptureActiveControl returns the file name of the captured screenshot, so you could use it in your reporting framework, or with the Reporter.ReportEvent command in QTP 10.

 

Similar methods can be used for Java, web, and other environments.

I hope you’ve found this article helpful in creating useful and effective automation reports.

Posted in .Net, Reports

One Response to “Highlighting the .Net active control in screen-captures”

  1. barak3d Says:

    [+]

    Nice tip, it works on web applications as well, I just tested it. I just created the same function but it receives an object and ... ...

Leave a Reply

You must be logged in to post a comment.

This article was viewed 315 times