BigDaddyO Posted March 27, 2020 Share Posted March 27, 2020 (edited) 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 expandcollapse popup#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 March 27, 2020 by BigDaddyO Link to comment Share on other sites More sharing options...
seadoggie01 Posted March 27, 2020 Share Posted March 27, 2020 (edited) 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 March 27, 2020 by seadoggie01 Hashim 1 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 functionsAcro.au3 UDF - Automating Acrobat ProToDo Finder - Find #ToDo: lines in your scriptsUI-SimpleWrappers UDF - Use UI Automation more Simply-erKeePass UDF - Automate KeePass, a password managerInputBoxes - Simple Input boxes for various variable types Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now