Jump to content

GDIPlus Dispose/Shutdown review


Recommended Posts

Hello,

I'm looking for some assistance with disposing of GDIPlus and what resources that are taken up if it's not done properly.

I've written a screencapture function that will allow me to append log file information directly into an error screenshot as I don't have the room in my log file for detailed info to troubleshoot properly.
I'm planning on using this with some very long running tests 15+ hrs and it's possible that this function will be called hundreds of times.
I'm wondering if someone could help me out with how to properly close out the GDIPlus stuff as i'm concerned this will become a resource hog.

Below is a simple example script with my function.

Implementing this into my tests will be incredibly time consuming so i'm hoping to make sure everything is perfect before I go down that road.

Thanks

#include <GDIPlus.au3>
#include <ScreenCapture.au3>
#include <WinAPIConv.au3>


;Highlight a control on a screen, Capture a screenshot, insert log/info into the screenshot


;For this test, ensure the AutoIt spy is open so I can grab a control off that
If WinExists("(Frozen) AutoIt v3 Window Info", "Basic Control Info") = 0 Then
    Run("C:\Program Files (x86)\AutoIt3\Au3Info.exe")
    winwait("(Frozen) AutoIt v3 Window Info", "Basic Control Info", 10)
EndIf

$sSaveAs =  @ScriptDir & "\LogImage.jpg"
$sString = "This is my additional log information that i'm attaching to this screenshot" & @CRLF & @CRLF & "It can handle @CRLF!" & @CRLF & @TAB & "But, it Can't handle @Tab"
$hWindow = WinGetHandle("(Frozen) AutoIt v3 Window Info", "Basic Control Info")
$hCtrl = "Edit3"

_ScreenCapture_Log($sSaveAs, $sString, $hWindow, $hCtrl, 300, 400)

;Launch the saved screenshot to view results
ShellExecute($sSaveAs)


; #FUNCTION# ====================================================================================================================
; Name...........:  _ScreenCapture_Log
; Description ...:  Captures a screenshot and append a section to include text/log information
; Syntax.........:  _ScreenCapture_Log($sSaveAs, $sString)
; Parameters ....:  $sFileName - Full path where to save the file.  "" to return the GDI image handle
;                   $sString - The full text to append to the image.  Accepts @CRLF but @TAB is not handled
;                   $hWindow - If you want to highlight a control, you must include the handle to the controls window.  Default = "" nothing highlighted
;                   $hCtrl - If you want to highligh a control, add the controlID or handle.  Default = "" nothing highlighted
;                   $iLogW - How wide do you want the appended string image to be.  may be extended automatically depending on position specified.
;                   $iLogH - How high do you want the appended string image to be.  may be extended automatically depending on position specified.
;                   $iLogPos - Where to place the string image.  0 = Left of capture, 1 = Above Capture, 2 = Right of Capture, 3 = Below Capture.  Default = 2 (Right of)
;                   $iCaptX - If you want to capture specific coordinates instead of the entire screen, enter the x coord here
;                   $iCaptY - If you want to capture specific coordinates instead of the entire screen, enter the y coord here
;                   $iCaptW - If you want to capture specific coordinates instead of the entire screen, enter the width here
;                   $iCaptH - If you want to capture specific coordinates instead of the entire screen, enter the height here
;                   $cursor - True = capture the mouse cursor, False = dont capture the cursor.  Default = False
; Return values .: Success - Returns the full path to the saved image, of Handle depending on options provided
;                  Failure - sets @error
; Author ........: BigDaddyO
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: _ScreenCapture_Log(@ScriptDir & "\LogImage.jpg", "This is my Log information")
; ===============================================================================================================================
Func _ScreenCapture_Log($sFileName = "", $sString = "", $hWindow = "", $hCtrl = "", $iLogW = 300, $iLogH = 300, $iLogPos = 2, $iCaptX = 0, $iCaptY = 0, $iCaptW = -1, $iCaptH = -1, $cursor = False)
    Local $hBitmap, $hImage, $aDim[2], $aLogPos[4], $aCaptPos[4], $hCanvas, $hGfx, $aCanvas[2], $aCtrlPos, $tPoint, $aRect[4]
    Local $hBrush, $hFormat, $hFamily, $hFont, $tLayout, $aInfo

    _GDIPlus_Startup()

; Capture screen
    $hBitmap = _ScreenCapture_Capture("", $iCaptX, $iCaptY, $iCaptW, $iCaptH, $cursor)
    $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)


;Build a new Bitmap and Graphic to hold the Screenshot and Log Info
;~  Local $aLogPos[4], $aCaptPos[4], $aCanvas[2]
    $aDim = _GDIPlus_ImageGetDimension($hImage)                     ;Size of our screenshot

    ;Where do we want the log to be located
    Switch $iLogPos
        Case 0  ;Log goes to the left of screenshot
            ;Identify the new size of the image
                If $iLogH > $aDim[1] Then
                    $aCanvas[0] = $aDim[0] + $iLogW
                    $aCanvas[1] = $iLogH
                Else
                    $aCanvas[0] = $aDim[0] + $iLogW
                    $aCanvas[1] = $aDim[1]
                    $iLogH = $aDim[1]
                EndIf
            ;Identify the Size and position of the screenshot in the new image
                $aCaptPos[0] = $iLogW
                $aCaptPos[1] = 0
                $aCaptPos[2] = $aDim[0]
                $aCaptPos[3] = $aDim[1]
            ;Identify the Size and position of the Log text in the new image
                $aLogPos[0] = 5
                $aLogPos[1] = 5
                $aLogPos[2] = $iLogW - 10   ;Width will be specified log width - 10 for a 5px border on both sides
                $aLogPos[3] = $iLogH - 10   ;Log Height - 10 for a 5px border on both sides
            ;Identify the location for the Control Highlight if requested
                If $hWindow <> "" and $hCtrl <> "" Then
                    $aCtrlPos = ControlGetPos($hWindow, "", $hCtrl)             ;Get the location of the control within the window
                    $tPoint = DllStructCreate("int X;int Y")
                    DllStructSetData($tPoint, "X", $aCtrlPos[0])
                    DllStructSetData($tPoint, "Y", $aCtrlPos[1])
                    _WinAPI_ClientToScreen($hWindow, $tPoint)                   ;Translate the position to the position on screen
                    $aRect[0] = DllStructGetData($tPoint, "X") + $iLogW
                    $aRect[1] = DllStructGetData($tPoint, "Y")
                    $aRect[2] = $aCtrlPos[2]
                    $aRect[3] = $aCtrlPos[3]
                EndIf

        Case 1  ;Log goes Above the screenshot
            ;Identify the new size of the image
                If $iLogW > $aDim[0] Then
                    $aCanvas[0] = $iLogW
                    $aCanvas[1] = $aDim[1] + $iLogH
                Else
                    $aCanvas[0] = $aDim[0]
                    $aCanvas[1] = $aDim[1] + $iLogH
                    $iLogW = $aDim[0]
                EndIf
            ;Identify the Size and position of the screenshot in the new image
                $aCaptPos[0] = 0
                $aCaptPos[1] = $iLogH
                $aCaptPos[2] = $aDim[0]
                $aCaptPos[3] = $aDim[1]
            ;Identify the Size and position of the Log text in the new image
                $aLogPos[0] = 5
                $aLogPos[1] = 5
                $aLogPos[2] = $aDim[0] - 10
                $aLogPos[3] = $iLogH - 10
            ;Identify the location for the Control Highlight if requested
                If $hWindow <> "" and $hCtrl <> "" Then
                    $aCtrlPos = ControlGetPos($hWindow, "", $hCtrl)             ;Get the location of the control within the window
                    $tPoint = DllStructCreate("int X;int Y")
                    DllStructSetData($tPoint, "X", $aCtrlPos[0])
                    DllStructSetData($tPoint, "Y", $aCtrlPos[1])
                    _WinAPI_ClientToScreen($hWindow, $tPoint)                   ;Translate the position to the position on screen
                    $aRect[0] = DllStructGetData($tPoint, "X")
                    $aRect[1] = DllStructGetData($tPoint, "Y") + $iLogH
                    $aRect[2] = $aCtrlPos[2]
                    $aRect[3] = $aCtrlPos[3]
                EndIf

        Case 2  ;Default, Log goes to the right of the screenshot
            ;Identify the new size of the image
                If $iLogH > $aDim[1] Then
                    $aCanvas[0] = $aDim[0] + $iLogW
                    $aCanvas[1] = $iLogH
                Else
                    $aCanvas[0] = $aDim[0] + $iLogW
                    $aCanvas[1] = $aDim[1]
                    $iLogH = $aDim[1]
                EndIf
            ;Identify the Size and position of the screenshot in the new image
                $aCaptPos[0] = 0
                $aCaptPos[1] = 0
                $aCaptPos[2] = $aDim[0]
                $aCaptPos[3] = $aDim[1]
            ;Identify the Size and position of the Log text in the new image
                $aLogPos[0] = $aDim[0] + 5  ;Start log text after screenshot width + 5 for border
                $aLogPos[1] = 5             ;Start log text at the top of the screenshot with a +5 border
                $aLogPos[2] = $iLogW - 10   ;Width will be specified log width - 10 for a 5px border on both sides
                $aLogPos[3] = $iLogH - 10   ;Width will be specified log height - 10 for a 5px border on both sides
            ;Identify the location for the Control Highlight if requested
                If $hWindow <> "" and $hCtrl <> "" Then
                    $aCtrlPos = ControlGetPos($hWindow, "", $hCtrl)             ;Get the location of the control within the window
                    $tPoint = DllStructCreate("int X;int Y")
                    DllStructSetData($tPoint, "X", $aCtrlPos[0])
                    DllStructSetData($tPoint, "Y", $aCtrlPos[1])
                    _WinAPI_ClientToScreen($hWindow, $tPoint)                   ;Translate the position to the position on screen
                    $aRect[0] = DllStructGetData($tPoint, "X")
                    $aRect[1] = DllStructGetData($tPoint, "Y")
                    $aRect[2] = $aCtrlPos[2]
                    $aRect[3] = $aCtrlPos[3]
                EndIf

        Case 3  ;Log goes below the screenshot
            ;Identify the new size of the image
                If $iLogW > $aDim[0] Then
                    $aCanvas[0] = $iLogW
                    $aCanvas[1] = $aDim[1] + $iLogH
                Else
                    $aCanvas[0] = $aDim[0]
                    $aCanvas[1] = $aDim[1] + $iLogH
                    $iLogW = $aDim[0]
                EndIf
            ;Identify the Size and position of the screenshot in the new image
                $aCaptPos[0] = 0
                $aCaptPos[1] = 0
                $aCaptPos[2] = $aDim[0]
                $aCaptPos[3] = $aDim[1]
            ;Identify the Size and position of the Log text in the new image
                $aLogPos[0] = 5
                $aLogPos[1] = $aDim[1] + 5
                $aLogPos[2] = $aDim[0] - 10
                $aLogPos[3] = $iLogH - 10
            ;Identify the location for the Control Highlight if requested
                If $hWindow <> "" and $hCtrl <> "" Then
                    $aCtrlPos = ControlGetPos($hWindow, "", $hCtrl)             ;Get the location of the control within the window
                    $tPoint = DllStructCreate("int X;int Y")
                    DllStructSetData($tPoint, "X", $aCtrlPos[0])
                    DllStructSetData($tPoint, "Y", $aCtrlPos[1])
                    _WinAPI_ClientToScreen($hWindow, $tPoint)                   ;Translate the position to the position on screen
                    $aRect[0] = DllStructGetData($tPoint, "X")
                    $aRect[1] = DllStructGetData($tPoint, "Y")
                    $aRect[2] = $aCtrlPos[2]
                    $aRect[3] = $aCtrlPos[3]
                EndIf

        Case Else
            Return SetError(1, "Invalid position value")
    EndSwitch

    $hCanvas = _GDIPlus_BitmapCreateFromScan0($aCanvas[0], $aCanvas[1])     ;The entire size of the newly widened image
    $hGfx = _GDIPlus_ImageGetGraphicsContext($hCanvas)
    _GDIPlus_GraphicsDrawImageRect($hGfx, $hImage, $aCaptPos[0], $aCaptPos[1], $aCaptPos[2], $aCaptPos[3])  ;Draw the captured screen in the proper location for the log


;Draw a frame around the control if that option is selected
    If $hWindow <> "" and $hCtrl <> "" Then
        $hPen = _GDIPlus_PenCreate(0xFFFF0000, 2)                                           ;Create a red pen
        _GDIPlus_GraphicsDrawRect($hGfx, $aRect[0], $aRect[1], $aRect[2], $aRect[3], $hPen) ;Draw our rectangle around the control
    EndIf

;Now to insert some text into the canvas
    If $sString <> "" Then
        $hBrush = _GDIPlus_BrushCreateSolid(0xFFFFFF99)
        $hFormat = _GDIPlus_StringFormatCreate()
        $hFamily = _GDIPlus_FontFamilyCreate("Arial")
        $hFont = _GDIPlus_FontCreate($hFamily, 8, 2)
        $tLayout = _GDIPlus_RectFCreate($aLogPos[0], $aLogPos[1], $aLogPos[2], $aLogPos[3])
        $aInfo = _GDIPlus_GraphicsMeasureString($hGfx, $sString, $hFont, $tLayout, $hFormat)
        _GDIPlus_GraphicsDrawStringEx($hGfx, $sString, $hFont, $aInfo[0], $hFormat, $hBrush)
        _GDIPlus_FontDispose($hFont)
        _GDIPlus_FontFamilyDispose($hFamily)
        _GDIPlus_StringFormatDispose($hFormat)
        _GDIPlus_BrushDispose($hBrush)
    EndIf


    If $sFileName <> "" Then
        ;Save the image
        _GDIPlus_ImageSaveToFile($hCanvas, $sFileName)
        If @error Then
            ConsoleWrite("Failed to save the updated canvas" & @CRLF)
            ;Time for cleanup
                _GDIPlus_ImageDispose($hCanvas)
                _WinAPI_DeleteObject($hImage)
                _GDIPlus_Shutdown()
            Return SetError(1)
        Else
            ConsoleWrite("sucessfully saved the updated canvas" & @CRLF)
            ;Time for cleanup
            _GDIPlus_ImageDispose($hCanvas)
            _WinAPI_DeleteObject($hImage)
            _GDIPlus_Shutdown()
            Return $sFileName
        EndIf
    Else
        ;Return the handle to the canvas, can I shutdown GDIPlus now?
        Return $hCanvas
    EndIf

EndFunc

edit:  made everything Local, update the Rectangle to use array of data.  Found and using dispose for the String stuff

Edited by BigDaddyO
Link to comment
Share on other sites

I'm not sure if this is what you mean, but here goes:

  • Create a UDF that is _GDIPlusEx
  • Wrap each GDIPlus function that creates something in a _GDIPlusEx_* function
  • Store each created object in a global array in the UDF
  • _GDIPlusEx_ShutDown walks through each object and destroys it before calling _GDIPlus_ShutDown

I did this once, but of course I can't find it now :(

Edit: After re-reading your question, I think I misunderstood, you want to know which functions need to be deleted, don't you? Sorry.

Edit 2: I used the help file to determine the destructive counterpart to each function (that you used only, this list isn't complete)

_GDIPlus_Startup

_GDIPlus_Shutdown

_GDIPlus_BitmapCreateFromHBITMAP

_GDIPlus_BitmapDispose

_GDIPlus_ImageGetDimension

 

_GDIPlus_BitmapCreateFromScan0

_GDIPlus_BitmapDispose

_GDIPlus_ImageGetGraphicsContext

_GDIPlus_GraphicsDispose

_GDIPlus_GraphicsDrawImageRect

 

_GDIPlus_PenCreate

_GDIPlus_PenDispose

_GDIPlus_GraphicsDrawRect

 

_GDIPlus_BrushCreateSolid

_GDIPlus_BrushDispose

_GDIPlus_StringFormatCreate

_GDIPlus_StringFormatDispose

_GDIPlus_FontFamilyCreate

_GDIPlus_FontFamilyDispose

_GDIPlus_FontCreate

_GDIPlus_FontDispose

_GDIPlus_RectFCreate

 

_GDIPlus_GraphicsMeasureString

 

_GDIPlus_GraphicsDrawStringEx

 

_GDIPlus_ImageSaveToFile

 

_GDIPlus_ImageDispose

 

_GDIPlus_Shutdown

 
Edited by seadoggie01

All my code provided is Public Domain... but it may not work. ;) Use it, change it, break it, whatever you want.

Spoiler

My Humble Contributions:
Personal Function Documentation - A personal HelpFile for your functions
Acro.au3 UDF - Automating Acrobat Pro
ToDo Finder - Find #ToDo: lines in your scripts
UI-SimpleWrappers UDF - Use UI Automation more Simply-er
KeePass UDF - Automate KeePass, a password manager
InputBoxes - Simple Input boxes for various variable types

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...