Jump to content
c.haslam

GDI+: Getting value of string Property fails ...

Recommended Posts

c.haslam

sometimes!

  • Running the script below and entering a for All seems to work every time
  • Running it and choosing 1 for One returns a gibberish string
  • However with the same functions, I have seen it succeed when 1 is chosen, i.e. show the value for the test property ID 0x0103 as OLYMPUS DIGITAL CAMERA

I have also seen GetOne() succeed when a diagnostic MsgBox() is added,  and when I include my debugging functions, so the problem appears to be a memory location being overwritten, probably in a DLLStruct.. call.

I know that value OLYMPUS DIGITAL CAMERA is correct from Irfanview and from running GetAll().

All but one of the _GDIPlus functions were written by ChrisL. I have modified those that returned a DLLStruct object such that they now return an array.

Both getting one and getting  all involve calling _GDIPlus_ImageGetPropertyItemValue() which I wrote, so perhaps the problem partly lies with ChrisL's functions as modified.

Suggestions?

#include <GDIPlus.au3>
#include <Array.au3>
Opt('MustDeclareVars',1)
; #VARIABLES# ===================================================================================================================
Global $GDIP_STATUS = 0
Global $GDIP_ERROR = 0
; ===============================================================================================================================
; Property Item structure
Global Const $tagGDIPPROPERTYITEM = _
    "uint id;" & _          ; ID of this property
    "uint length;" & _      ; Length of the property value, in bytes
    "ushort type;" & _      ; Type of the value, as one of TAG_TYPE_XXX constants
    "ptr value;"            ; property value

; Image property types constants
; Ref: https://www.media.mit.edu/pia/Research/deepview/exif.html
Global Const $GDIP_PROPERTYTAGTYPEUBYTE = 1
Global Const $GDIP_PROPERTYTAGTYPEASCII = 2
Global Const $GDIP_PROPERTYTAGTYPEUSHORT = 3
Global Const $GDIP_PROPERTYTAGTYPEULONG = 4
Global Const $GDIP_PROPERTYTAGTYPEURATIONAL = 5
Global Const $GDIP_PROPERTYTAGTYPESBYTE = 6
Global Const $GDIP_PROPERTYTAGTYPEUNDEFINED = 7
Global Const $GDIP_PROPERTYTAGTYPESSHORT = 8
Global Const $GDIP_PROPERTYTAGTYPESLONG = 9
Global Const $GDIP_PROPERTYTAGTYPESRATIONAL = 10
Global Const $GDIP_PROPERTYTAGTYPESFLOAT = 11
Global Const $GDIP_PROPERTYTAGTYPEDFLOAT = 12
main()

Func main()
    _GDIPlus_Startup()

    Local $hImage = _GDIPlus_ImageLoadFromFile('H:\b\PA160005 - Copy.JPG')

    Local $sAns = InputBox('','Enter 1 or a')
    If $sAns=1 Then
        GetOne($hImage)
    ElseIf $sAns='a' Then
        GetAll($hImage)
    EndIf
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
EndFunc

Func GetOne($hImage)
    Local $vecPrim = _GDIPlus_ImageGetPropertyItem($hImage,0x010e)
    Local $vecUser[3]
    $vecUser[0] = '0x'&StringRight(Hex($vecPrim[0]),4)
    $vecUser[1] = $vecPrim[2]
    Local $vecVals = _GDIPlus_ImageGetPropertyItemValue($vecPrim[1],$vecPrim[2],$vecPrim[3])
    $vecUser[2] = $vecVals[0]
    _ArrayDisplay($vecUser)
EndFunc


Func GetAll($hImage)
    Local $ar1 = _GDIPlus_ImageGetAllPropertyItems($hImage)
    Local $ar[UBound($ar1,1)][3]
    For $i = 1 To $ar1[0][0]
        $ar[$i][0] = '0x'&StringRight(Hex($ar1[$i][0]),4)
        $ar[$i][1] =$ar1[$i][2]
        $ar[$i][2] =  (_GDIPlus_ImageGetPropertyItemValue($ar1[$i][1],$ar1[$i][2],$ar1[$i][3]))[0]
    Next
    _ArrayDisplay($ar)
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _GDIPlus_ImageGetAllPropertyItems
; Description ...: Gets all the property items (metadata) stored in an Image object
; Syntax.........: _GDIPlus_ImageGetAllPropertyItems($hImage)
; Parameters ....: $hImage - Pointer to an Image object
; Return values .: Success      - Array containing the image property items:
;                  |[0][0] - Number of property items
;                  |[1][0] - Property item 1 identifier (see remarks)
;                  |[1][1] - Property item 1 value length, in bytes
;                  |[1][2] - Property item 1 value type
;                  |[1][1] - Property item 1 value pointer
;                  |.
;                  |.
;                  |[n][0] - Property item n identifier
;                  |[n][1] - Property item n value length, in bytes
;                  |[n][2] - Property item n value type
;                  |[n][1] - Property item n value pointer
;                  Possible property value types are:
;                  |1 - The value pointer points to an array of bytes
;                  |2 - The value pointer points to a null-terminated ASCII string
;                  |3 - The value pointer points to unsigned short
;                  |4 - The value pointer points to an unsigned long
;                  |5 - The value pointer points to an array of unsigned two longs (numerator, denominator)
;                  |7 - The value pointer points to an array of bytes of any type, or is unterminated string\
;                  |8 - The value pointer points to signed short
;                  |9 - The value pointer points to a signed long
;                  |10 - The value pointer points to an array of signed two longs (numerator, denominator)
;                  |11 - The value pointer points to a float
;                  |12 - The value pointer points to a double
;                  Failure      - -1 and either:
;                  |@error and @extended are set if DllCall failed
;                  |$GDIP_STATUS contains a non zero value specifying the error code
;                  |$GDIP_ERROR:
;                  |    1 - The _GDIPlus_ImageGetPropertySize function failed, $GDIP_STATUS contains the error code
;                  |    2 - The image contains no property items metadata
;                  |    3 - The _GDIPlus_ImageGetAllPropertyItems function failed, $GDIP_STATUS contains the error code
; Author.........: Authenticity
; Modified.......: c.haslam
; Remarks .......: The property item tag identifiers are declared in GDIPConstants.au3, those that start with $GDIP_PROPERTYTAG
;                  +The value size is given in bytes, divide this by the size of the data (4 for integers, 2 for shorts, etc..)
; Related .......: _GDIPlus_ImageGetPropertySize, _GDIPlus_ImageGetPropertyItemValue, _GDIPlus_ImageGetAllPropertyItems
; Link ..........; @@MsdnLink@@ GdipGetAllPropertyItems
; Example .......; No
; ===============================================================================================================================
Func _GDIPlus_ImageGetAllPropertyItems($hImage)
    Local $iI, $iCount, $tBuffer, $pBuffer, $iBuffer, $tPropertyItem, $aSize, $aPropertyItems[1][1], $aResult

    $aSize = _GDIPlus_ImageGetPropertySize($hImage)
    If @error Then Return SetError(@error, @extended, -1)

    If $GDIP_STATUS Then
        $GDIP_ERROR = 1
        Return -1
    ElseIf $aSize[1] = 0 Then
        $GDIP_ERROR = 2
        Return -1
    EndIf

    $iBuffer = $aSize[0]
    $tBuffer = DllStructCreate("byte[" & $iBuffer & "]")
    $pBuffer = DllStructGetPtr($tBuffer)
    $iCount = $aSize[1]

    $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetAllPropertyItems", "hwnd", $hImage, "uint", $iBuffer, "uint", $iCount, "ptr", $pBuffer)
    If @error Then Return SetError(@error, @extended, -1)

    $GDIP_STATUS = $aResult[0]
    If $GDIP_STATUS Then
        $GDIP_ERROR = 3
        Return -1
    EndIf

    ReDim $aPropertyItems[$iCount + 1][4]
    $aPropertyItems[0][0] = $iCount

    For $iI = 1 To $iCount
        $tPropertyItem = DllStructCreate($tagGDIPPROPERTYITEM, $pBuffer)
        $aPropertyItems[$iI][0] = DllStructGetData($tPropertyItem, "id")
        $aPropertyItems[$iI][1] = DllStructGetData($tPropertyItem, "length")
        $aPropertyItems[$iI][2] = DllStructGetData($tPropertyItem, "type")
        $aPropertyItems[$iI][3] = DllStructGetData($tPropertyItem, "value")
        $pBuffer += DllStructGetSize($tPropertyItem)
    Next

    Return $aPropertyItems
EndFunc

; #FUNCTION# ====================================================================================================================
; Name ..........: _GDIPlus_ImageGetPropertyItemValue
; Description ...: Get property item values from fields in $tagGDIPPROPERTYITEM data
; Syntax ........: _GDIPlus_ImageGetPropertyItemValue($iLength, $iType, $pValue)
; Parameters ....: $iLength         Length of the property value, in bytes
;                  |$iType          Type of the value (a $GDIP_PROPERTYTAGTYPE* value - see GDIPConstants.au3)
;                  |$pValue         Pointer to value
; Return values .: Success      - An array
;                   |             [0] value 1
;                   |             [1] value 2 (only for properties that have numerator and denominator)
;                  Failure      - -1
; Author ........: c.haslam
; Modified ......:
; Remarks........:  If type is 7 ($GDIP_PROPERTYTAGTYPEUNDEFINED) value returned is an unsigned long.
;                   Depending on ID and originator of the image, value may actually be an unterminated string
; Related .......:  _GDIPlus_ImageGetPropertyItem,_GDIPlus_ImageGetAllPropertyItems
; Link ..........: http://www.cipa.jp/std/documents/e/DC-008-Translation-2016-E.pdf,
;                  https://www.media.mit.edu/pia/Research/deepview/exif.html
; Example .......: No
; ===============================================================================================================================
Func _GDIPlus_ImageGetPropertyItemValue($iLength, $iType, $pValue)
    Switch $iType
        Case $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL
            Local $aRet[2]
        Case Else
            Local $aRet[1]
    EndSwitch

    Switch $iType
        Case $GDIP_PROPERTYTAGTYPEUBYTE,$GDIP_PROPERTYTAGTYPESBYTE
            Local $tvalue = DllStructCreate('byte val',$pValue)
            $aRet[0] = $tvalue.val
        Case $GDIP_PROPERTYTAGTYPEASCII
            Local $tvalue = DllStructCreate('char val['&$iLength&']',$pValue)
If @error Then MsgBox(0,@ScriptLineNumber,'@error='&@error)
            $aRet[0] = DllStructGetData($tvalue,'val')
If @error Then MsgBox(0,@ScriptLineNumber,'@error='&@error)
            $aRet[0] = $tvalue.val
        Case $GDIP_PROPERTYTAGTYPEUSHORT
            Local $tvalue = DllStructCreate('ushort val',$pValue)
            $aRet[0] = $tvalue.val
        Case $GDIP_PROPERTYTAGTYPEULONG
            Local $tvalue = DllStructCreate('ulong val',$pValue)
            $aRet[0] = $tvalue.val
        Case $GDIP_PROPERTYTAGTYPEURATIONAL
            Local $tvalue = DllStructCreate('ulong val1;ulong val2',$pValue)
            $aRet[0] = $tvalue.val1
            $aRet[1] = $tvalue.val2
        Case $GDIP_PROPERTYTAGTYPESBYTE
            Local $tvalue = DllStructCreate('byte val',$pValue)
            $aRet[0] = $tvalue.val
        Case $GDIP_PROPERTYTAGTYPEUNDEFINED
            ; undefined, per specification, but may be a long but is sometimes a string
            Local $tvalue = DllStructCreate('ulong val',$pValue)
            $aRet[0] = $tvalue.val
        Case $GDIP_PROPERTYTAGTYPESSHORT
            Local $tvalue = DllStructCreate('short val',$pValue)
            $aRet[0] = $tvalue.val
        Case $GDIP_PROPERTYTAGTYPEULONG
            Local $tvalue = DllStructCreate('ulong val',$pValue)
            $aRet[0] = $tvalue.val
        Case $GDIP_PROPERTYTAGTYPESRATIONAL
            Local $tvalue = DllStructCreate('long val1;long val2',$pValue)
            $aRet[0] = $tvalue.val1
            $aRet[1] = $tvalue.val2
        Case $GDIP_PROPERTYTAGTYPESFLOAT
            Local $tvalue = DllStructCreate('float val',$pValue)
            $aRet[0] = $tvalue.val
        Case $GDIP_PROPERTYTAGTYPEDFLOAT
            Local $tvalue = DllStructCreate('double val',$pValue)
            $aRet[0] = $tvalue.val
    EndSwitch
    $tvalue = 0
    Return $aRet
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _GDIPlus_ImageGetPropertyItem
; Description ...: Gets a specified property item (piece of metadata) from an Image object
; Syntax.........: _GDIPlus_ImageGetPropertyItem($hImage, $iPropID)
; Parameters ....: $hImage  - Pointer to an Image object
;                  $iPropID - Identifier of the property item to be retrieved
; Return values .: Success      - Array
;                   |   [0] Property ID
;                   |   [1] Property length
;                   |   [2] Property type
;                   |   [3] pointer to Property value
;                  Possible values of type are:
;                  |1 - The value pointer points to an array of bytes
;                  |2 - The value pointer points to a null-terminated ASCII string
;                  |3 - The value pointer points to unsigned short
;                  |4 - The value pointer points to an unsigned long
;                  |5 - The value pointer points to an array of unsigned two longs (numerator, denominator)
;                  |7 - The value pointer points to an array of bytes of any type, or is unterminated string\
;                  |8 - The value pointer points to signed short
;                  |9 - The value pointer points to a signed long
;                  |10 - The value pointer points to an array of signed two longs (numerator, denominator)
;                  |11 - The value pointer points to a float
;                  |12 - The value pointer points to a double
;                  Failure      - -1 and either:
;                  |@error and @extended are set if DllCall failed
;                  |$GDIP_STATUS contains a non-zero value specifying the error code
;                  |$GDIP_ERROR:
;                  |    1 - The _GDIPlus_ImageGetPropertyItemSize function failed, $GDIP_STATUS contains the error code
;                  |    2 - The specified property identifier does not exist in the image
;                  |    3 - The _GDIPlus_ImageGetPropertyItem function failed, $GDIP_STATUS contains the error code
; Author.........: Authenticity
; Modified.......: c.haslam
; Remarks .......: None
; Related .......: _GDIPlus_ImageGetPropertyIdList, _GDIPlus_ImageGetPropertyItemSize, _GDIPlus_ImageGetPropertyItemValue,
;                  $tagGDIPPROPERTYITEM
; Link ..........; @@MsdnLink@@ GdipGetPropertyItem http://www.cipa.jp/std/documents/e/DC-008-Translation-2016-E.pdf,
;                  https://www.media.mit.edu/pia/Research/deepview/exif.html
; Example .......; No
; ===============================================================================================================================
Func _GDIPlus_ImageGetPropertyItem($hImage, $iPropID)
    Local $iBuffer, $tBuffer, $pBuffer, $tPropertyItem, $aResult

    $iBuffer = _GDIPlus_ImageGetPropertyItemSize($hImage, $iPropID)
    If @error Then Return SetError(@error, @extended, -1)

    If $GDIP_STATUS Then
        $GDIP_ERROR = 1
        Return -1
    ElseIf $iBuffer = 0 Then
        $GDIP_ERROR = 2
        Return -1
    EndIf

    $tBuffer = DllStructCreate("byte[" & $iBuffer & "]")
    $pBuffer = DllStructGetPtr($tBuffer)
    $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetPropertyItem", "hwnd", $hImage, "uint", $iPropID, "uint", $iBuffer, "ptr", $pBuffer)
    If @error Then Return SetError(@error, @extended, -1)

    $GDIP_STATUS = $aResult[0]
    If $GDIP_STATUS Then
        $GDIP_ERROR = 3
        Return -1
    EndIf

    Local $tPropertyItem = DllStructCreate($tagGDIPPROPERTYITEM, $pBuffer)
    Local $aRet = [$tPropertyItem.id, $tPropertyItem.length,$tPropertyItem.type, $tPropertyItem.value]
    Return $aRet
EndFunc   ;==>_GDIPlus_ImageGetPropertyItem

; #FUNCTION# ====================================================================================================================
; Name...........: _GDIPlus_ImageGetPropertySize
; Description ...: Gets the total size, in bytes, and the number of all the property items stored in an Image object
; Syntax.........: _GDIPlus_ImageGetPropertySize($hImage)
; Parameters ....: $hImage  - Pointer to an Image object
; Return values .: Success      - Array containing the total size and the number of property items:
;                  |[0] - Total size, in bytes, of the property items
;                  |[1] - Number of the property items
;                  Failure      - -1 and either:
;                  |@error and @extended are set if DllCall failed
;                  |$GDIP_STATUS contains a non zero value specifying the error code
; Author.........: Authenticity
; Remarks .......: None
; Related .......: _GDIPlus_ImageGetPropertyIdList, _GDIPlus_ImageGetPropertyItem
; Link ..........; @@MsdnLink@@ GdipGetPropertyItemSize
; Example .......; No
; ===============================================================================================================================
Func _GDIPlus_ImageGetPropertySize($hImage)
    Local $aSize[2], $aResult

    $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetPropertySize", "hwnd", $hImage, "uint*", 0, "uint*", 0)
    If @error Then Return SetError(@error, @extended, -1)

    $GDIP_STATUS = $aResult[0]
    If $GDIP_STATUS Then Return -1

    $aSize[0] = $aResult[2]
    $aSize[1] = $aResult[3]
    Return $aSize
EndFunc   ;==>_GDIPlus_ImageGetPropertySize


; #FUNCTION# ====================================================================================================================
; Name...........: _GDIPlus_ImageGetPropertyItemSize
; Description ...: Gets the size, in bytes, of a specified property item of an Image object
; Syntax.........: _GDIPlus_ImageGetPropertyItemSize($hImage, $iPropID)
; Parameters ....: $hImage  - Pointer to an Image object
;                  $iPropID - Identifier of the property item to be retrieved
; Return values .: Success      - $tagGDIPPROPERTYITEM structure containing the property size, type and value pointer
;                  Failure      - -1 and either:
;                  |@error and @extended are set if DllCall failed
;                  |$GDIP_STATUS contains a non zero value specifying the error code
; Author.........: Authenticity
; Remarks .......: None
; Related .......: _GDIPlus_ImageGetPropertyIdList, _GDIPlus_ImageGetPropertyItem
; Link ..........; @@MsdnLink@@ GdipGetPropertyItemSize
; Example .......; No
; ===============================================================================================================================
Func _GDIPlus_ImageGetPropertyItemSize($hImage, $iPropID)
    Local $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetPropertyItemSize", "hwnd", $hImage, "uint", $iPropID, _
        "uint*", 0)

    If @error Then Return SetError(@error, @extended, -1)

    $GDIP_STATUS = $aResult[0]
    If $GDIP_STATUS Then Return -1
    Return $aResult[3]
EndFunc   ;==>_GDIPlus_ImageGetPropertyItemSize

 

Edited by c.haslam
corrected 0x9003 to 010e: both are string values

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites
c.haslam

After many hours of searching and trying, I seem to have a solution, which I found on the French AutoIt forum: for GetOne(), in which calls _GDIPlus_ImageGetPropertyItem, $tbuffer must be Static. UEZ is the author of the code there, but the difference (for me) is that the guy (orax) is retrieving a string. UEZ wrote that the reason is "because otherwise it would crash when running it as x64 exe" but I am running it from Scite on Win7 SP1 32 bit, so nothing is 84 bit about what I am doing. Any way: good news!

I look forward to someone writing a Wicki on the DLLStruct* functions. I might then understand.

I haven't figured out why GetAll(), that calls GDIPlus_ImageGetAllPropertyItems(), does not seem to need this variable to be a Static.

Edited by c.haslam

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites
UEZ

You can have a look here, too (German): https://autoit.de/index.php?thread/85607-gdiplus-imagegetpropertyitems/

9 hours ago, c.haslam said:

I haven't figured out why GetAll(), that calls GDIPlus_ImageGetAllPropertyItems(), does not seem to need this variable to be a Static.

As far as I remember it was a problem running that function as x64 which cause a crash when the variable is not declared as static. Might be an Autoit bug...


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
c.haslam

The script on the German website runs AOK for me. There are 2 differences that I see between his code and mine:

  • His code does not make $tbuffer Static; mine (and yours) do
  • He (and you) have DllStructCreate('byte[' & $iSize & ']', $pValue) and BinaryToString(DllStructGetData($tBuffer, 1); I have char[' & $iSize & ']' and no BinaryToString call

At the risk of being offensive, I suspect a bug in AutoIt. (When I suspect a bug in AutoIt, it almost always turns out to be a bug in my code.) Perhaps only DLLCall() was in the author's mind when he designed the DLLStruct* functions.

Further, a few weeks back, before I generalized _GDIPlus_ImageGetPropertyItemValue(), I was able to do both One and All AOK. After that, adding in a diagnostic MsgBox call would cause the script to fail.  I do not remember the precise sequence of events, nor can I find the code! Perhaps I should have been more systematic in naming my file versions.

Edited by c.haslam

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites
c.haslam

I am looking at your  code in https://www.autoitscript.com/forum/topic/179451-solved-preserve-ascpect-ratio-_gdiplus/#comment-1287715 Post 12.

From _GDIPlus_ImageGetPropertyItem you return $tPropertyItem, a variable containing GDIPPROPERTYITEM data.

In Example(), you set $tPropItem to this.

But Example() presumably does not know that $tPropertyItem contains GDIPPROPERTYITEM data.

So does AutoIt know about $tPropItem.Value? How does it know that $tPropItem contains GDIPPROPERTYITEM data?

I had assumed that you had solved part of this problem by making $tBuffer Static: if you did not make it Static, it would be destroyed when _GDIPlus_ImageGetPropertyItem returned, then in Example(), $tPropItem could not be assured to contain GDIPPROPERTYITEM data.

How does Example know the structure of the data?

From your code, it does appear that Valik was wrong in cautioning against returning structures.

Am I making sense?

BUT in my code I am returning an array from _GDIPlus_ImageGetPropertyItem, in which none of the elements are structured data. It does not assume that the calling function knows about a structure. BUT it causes  failure until I made $tBuffer a Static. I did so as a last resort: anything to get the code working! So perhaps there is a bug in AutoIt. If there is one, it will not be easy to find!

As an aside, I wonder whether AutoIt releases memory used by structures when execution of a function ends.

Decades back, I took German 100. At that time, I could visit West Germany and be understood. I still remember a bit of German.

Edited by c.haslam
added a few paragraphs

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites
c.haslam

Having got the property functions working in my test script, I copied them to my 6000-line project, which had been working well.

Reading a few or all properties worked OK as shown by calling _ArrayDIsplay(). Then calling it again a few lines later either showed 0 for the values of string properties or AutoIt crashed, depending on which line the call was.

Two snippets:

$Dsk_ghImage = _GDIPlus_ImageLoadFromFile($filspc)
    Local $idsVec = [0x9003,0x9004] ; ; DateTimeOriginal, DateTimeDigitzed
    Local $propsAr[UBound($idsVec)][5]
    Local $vecPrim,$valsVec
    For $i = 0 To UBound($idsVec)-1
        Local $vecPrim = _GDIPlus_ImageGetPropertyItemEx($Dsk_ghImage,$idsVec[$i])
        $propsAr[$i][0] = $vecPrim[0]   ; id
        $propsAr[$i][1] = $vecPrim[1]       ; length
        $propsAr[$i][2] = $vecPrim[2]       ; type
        $propsAr[$i][3] = $vecPrim[3]       ; val1
        Local $valsVec = _GDIPlus_ImageGetPropertyItemValue($vecPrim[1],$vecPrim[2],$vecPrim[3])
        $propsAr[$i][3] = $valsVec[0]       ; val1
        If $vecPrim[2]=5 Or $vecPrim[2]=10 Then     ; $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL
            $propsAr[$i][4] = $valsVec[1]       ; val2
        EndIf
    Next

and

Case $btnOK
_ArrayDisplay($propsAr,@ScriptLineNumber)   ; OK here
                    ; These 2 lines un-double-lock the file
                    _GDIPlus_GraphicsDispose($hGfxClone)
_ArrayDisplay($propsAr,@ScriptLineNumber)   ; OK here
                    _GDIPlus_ImageDispose($Dsk_ghImage)
_ArrayDisplay($propsAr,@ScriptLineNumber)   ;  crashes atfer showing GUI  title, before showing data

 

Ideas?

Later

I have compared the version that did not crash (and worked well) [call it v. W] and the version that crashed [call it v. C].

I then carefully commented out all of the Properties code. v. C still crashed.

I then removed the commented-out code from v. C to make comparison easier. v. C still crashed.

I used TextPad to compare v. W and v. W. There was one difference:

Local Const $kPrId=0,$kPrLength=1,$kPrType=2,$kPrVal1=3,$kPrVal2=4

None of these constants were used. I commented out this line.

I ran v. C again. It did not crash.

I do use global constants often, but this was the first time I had used local constants.

I realize that I had been running with v. 3.3.14.2, which was not my intention.

I un-commented this line.

I pressed Alt_F5 to run with v. 3.3.15.0.

v. C did not crash.

So it appears that there was a bug 3.3.14.2 (but the Change log for 3.3.15.0 does not list it as fixed.)

I ran Toggle AU3 beta. It said "Now using RELEASE 3.3.14.2". So, to me, pressing F5 should have run the beta.

I then ran Toggle AU3 beta again. It said "Now using BETA 3.3.15.0". So I should be back to F5 running the beta. But looking at the Console, I see that F5 runs the Release, not the Beta. Strange!

Am I missing something?

It is likely that my crashing problem was entirely due to Local Const, not Properties functions.

Edited by c.haslam

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
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

  • Similar Content

    • JoeWagner
      By JoeWagner
      I'm building a tool to remotely monitor CPU usage on my server.
      I have a working tool but I have a few issues I'd like some help with.
      1. The app uses more system memory on a continual growth rate...  It eventually starts displaying strange artifacts and the background flashes between black and and white behind the GDI+ elements.  I determined this couldn't be left to run for any amount of time (greater than 15-20 minutes) - Very frustrating.
      I suspect it's because it keeps drawing new GDI+ elements to replace the previous cycle ... the $bar1 = "" is enough to remove the image and allow the new image to be drawn there, but I don't have a handle for the original GDI+ element to throw it away... Not sure where they go...
      I also suspect there could be a better way to do what I'm doing here, but from a problem solving perspective - this is what I came up with - I will accept suggestions for how better to accomplish the same / better or acceptable results  
      I will not however accept corrections on grammar, punctuation or commenting - I didn't comment this as I was going, I use the variables that make sense to me (or as they were when I lifted them from the scraps I found on the internet) and you can never be too careful with punctuation.
      2. I have a WMI query that is used to remotely pull the CPU data from the server - if I supply the wrong credentials the app crashes... I tried to make it show an error and go back to allow me to try again ... doesn't work. Any help with catching that error and preventing the crash would be super helpful. (works great if the credentials are correct; domain or local)
       
      The whole thing below... 
      #include <Date.au3> #include <WindowsConstants.au3> #include <GuiConstantsEX.au3> #include <EditConstants.au3> #include <ButtonConstants.au3> #include <GDIPlus.au3> Global $__g_hGDIPDll Global $graph[21] Global $timer, $timeout = 500 Global $hFlag = 0 $timer = TimerInit() $main = GUICreate("CPU Graph", 125, 220, Default, Default, Default, BitOR($WS_EX_TOOLWINDOW, $WS_EX_TOPMOST)) $bar1 = GUICtrlCreatePic("", 10, 10, 5, 100) $bar2 = GUICtrlCreatePic("", 15, 10, 5, 100) $bar3 = GUICtrlCreatePic("", 20, 10, 5, 100) $bar4 = GUICtrlCreatePic("", 25, 10, 5, 100) $bar5 = GUICtrlCreatePic("", 30, 10, 5, 100) $bar6 = GUICtrlCreatePic("", 35, 10, 5, 100) $bar7 = GUICtrlCreatePic("", 40, 10, 5, 100) $bar8 = GUICtrlCreatePic("", 45, 10, 5, 100) $bar9 = GUICtrlCreatePic("", 50, 10, 5, 100) $bar10 = GUICtrlCreatePic("", 55, 10, 5, 100) $bar11 = GUICtrlCreatePic("", 60, 10, 5, 100) $bar12 = GUICtrlCreatePic("", 65, 10, 5, 100) $bar13 = GUICtrlCreatePic("", 70, 10, 5, 100) $bar14 = GUICtrlCreatePic("", 75, 10, 5, 100) $bar15 = GUICtrlCreatePic("", 80, 10, 5, 100) $bar16 = GUICtrlCreatePic("", 85, 10, 5, 100) $bar17 = GUICtrlCreatePic("", 90, 10, 5, 100) $bar18 = GUICtrlCreatePic("", 95, 10, 5, 100) $bar19 = GUICtrlCreatePic("", 100, 10, 5, 100) $bar20 = GUICtrlCreatePic("", 105, 10, 5, 100) $host = GUICtrlCreateInput("Host", 10, 115, 100, 20, $ES_AUTOHSCROLL) $user = GUICtrlCreateInput("User", 10, 140, 100, 20, $ES_AUTOHSCROLL) GUICtrlSetFont(-1, 8, 400) $pass = GUICtrlCreateInput("Pass", 10, 165, 100, 20, BitOR($ES_PASSWORD,$ES_AUTOHSCROLL)) GUICtrlSetFont(-1, 8, 400) $start = GUICtrlCreateButton("Start", 10, 190, 100, 20, $BS_DEFPUSHBUTTON) GUISetState() While 1 $msg = GUIGetMsg() If $msg = $GUI_EVENT_CLOSE Then ExitLoop If $msg = $start Then ConnectWMI() If $hFlag = 1 Then If TimerDiff($timer) > $timeout Then UpdateGraph() EndIf WEnd Func ConnectWMI() Global $hostname = GUICtrlRead($host) If Ping($hostname, 2000) = 0 Then Msgbox(0, "Error", "Unable to reach specified host") Return 0 EndIf Local $usr = GUICtrlRead($user) Local $pwd = GUICtrlRead($pass) Global $objSWbemLocator = ObjCreate("WbemScripting.SWbemLocator") Global $objWMIService = $objSWbemLocator.ConnectServer($hostname, "root\cimv2", $usr, $pwd) If @error Then Msgbox(0, "Error", "Unable to connect to the Host with the supplied credentials") Return 0 EndIf $hFlag = 1 UpdateGraph() EndFunc Func UpdateGraph() $usage = _Processor_Usage() For $i = 1 to 19 $graph[$i] = $graph[$i+1] Next $graph[20] = $usage GUICtrlSetImage($bar1, "") CreateBar($bar1, $graph[1]) GUICtrlSetImage($bar2, "") CreateBar($bar2, $graph[2]) GUICtrlSetImage($bar3, "") CreateBar($bar3, $graph[3]) GUICtrlSetImage($bar4, "") CreateBar($bar4, $graph[4]) GUICtrlSetImage($bar5, "") CreateBar($bar5, $graph[5]) GUICtrlSetImage($bar6, "") CreateBar($bar6, $graph[6]) GUICtrlSetImage($bar7, "") CreateBar($bar7, $graph[7]) GUICtrlSetImage($bar8, "") CreateBar($bar8, $graph[8]) GUICtrlSetImage($bar9, "") CreateBar($bar9, $graph[9]) GUICtrlSetImage($bar10, "") CreateBar($bar10, $graph[10]) GUICtrlSetImage($bar11, "") CreateBar($bar11, $graph[11]) GUICtrlSetImage($bar12, "") CreateBar($bar12, $graph[12]) GUICtrlSetImage($bar13, "") CreateBar($bar13, $graph[13]) GUICtrlSetImage($bar14, "") CreateBar($bar14, $graph[14]) GUICtrlSetImage($bar15, "") CreateBar($bar15, $graph[15]) GUICtrlSetImage($bar16, "") CreateBar($bar16, $graph[16]) GUICtrlSetImage($bar17, "") CreateBar($bar17, $graph[17]) GUICtrlSetImage($bar18, "") CreateBar($bar18, $graph[18]) GUICtrlSetImage($bar19, "") CreateBar($bar19, $graph[19]) GUICtrlSetImage($bar20, "") CreateBar($bar20, $graph[20]) $timer = TimerInit() EndFunc Func _Processor_Usage() Dim $Col_Items = $objWMIService.ExecQuery('SELECT * FROM Win32_PerfFormattedData_PerfOS_Processor', 'WQL') Local $Obj_Item For $Obj_Item In $Col_Items Return $Obj_Item.PercentProcessorTime Next EndFunc Func CreateBar($target, $value) Local $width=5, $height=2 _GDIPlus_Startup() $hImage = DLL_BitmapCreate($width, $height*50) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage) _GDIPlus_GraphicsSetSmoothingMode($hGraphic, 2) ;100 If $value > 98 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF00F2F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 0, $width, $height, $hBrush) EndIf ;98 If $value > 96 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF0182C") _GDIPlus_GraphicsFillRect($hGraphic, 0, 2, $width, $height, $hBrush) EndIf ;96 If $value > 94 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF0212A") _GDIPlus_GraphicsFillRect($hGraphic, 0, 4, $width, $height, $hBrush) EndIf ;94 If $value > 92 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF02B28") _GDIPlus_GraphicsFillRect($hGraphic, 0, 6, $width, $height, $hBrush) EndIf ;92 If $value > 90 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF03426") _GDIPlus_GraphicsFillRect($hGraphic, 0, 8, $width, $height, $hBrush) EndIf ;90 If $value > 88 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF03E24") _GDIPlus_GraphicsFillRect($hGraphic, 0, 10, $width, $height, $hBrush) EndIf ;88 If $value > 86 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF04722") _GDIPlus_GraphicsFillRect($hGraphic, 0, 12, $width, $height, $hBrush) EndIf ;86 If $value > 84 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF05120") _GDIPlus_GraphicsFillRect($hGraphic, 0, 14, $width, $height, $hBrush) EndIf ;84 If $value > 82 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF05A1D") _GDIPlus_GraphicsFillRect($hGraphic, 0, 16, $width, $height, $hBrush) EndIf ;82 If $value > 80 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF0641B") _GDIPlus_GraphicsFillRect($hGraphic, 0, 18, $width, $height, $hBrush) EndIf ;80 If $value > 78 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF06D19") _GDIPlus_GraphicsFillRect($hGraphic, 0, 20, $width, $height, $hBrush) EndIf ;78 If $value > 76 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF07717") _GDIPlus_GraphicsFillRect($hGraphic, 0, 22, $width, $height, $hBrush) EndIf ;76 If $value > 74 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF08015") _GDIPlus_GraphicsFillRect($hGraphic, 0, 24, $width, $height, $hBrush) EndIf ;74 If $value > 72 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF08A13") _GDIPlus_GraphicsFillRect($hGraphic, 0, 26, $width, $height, $hBrush) EndIf ;72 If $value > 70 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF09311") _GDIPlus_GraphicsFillRect($hGraphic, 0, 28, $width, $height, $hBrush) EndIf ;70 If $value > 68 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF09311") _GDIPlus_GraphicsFillRect($hGraphic, 0, 30, $width, $height, $hBrush) EndIf ;68 If $value > 66 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF09D0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 32, $width, $height, $hBrush) EndIf ;66 If $value > 64 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFECA20F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 34, $width, $height, $hBrush) EndIf ;64 If $value > 62 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFE8A80F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 36, $width, $height, $hBrush) EndIf ;62 If $value > 60 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFE5AD0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 38, $width, $height, $hBrush) EndIf ;60 If $value > 58 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFE1B30F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 40, $width, $height, $hBrush) EndIf ;58 If $value > 56 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFDEB80F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 42, $width, $height, $hBrush) EndIf ;56 If $value > 54 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFDABE0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 44, $width, $height, $hBrush) EndIf ;54 If $value > 52 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFD6C30F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 46, $width, $height, $hBrush) EndIf ;52 If $value > 50 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFCFCE0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 48, $width, $height, $hBrush) EndIf ;50 If $value > 48 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFCCD40F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 50, $width, $height, $hBrush) EndIf ;48 If $value > 46 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFC8D90F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 52, $width, $height, $hBrush) EndIf ;46 If $value > 44 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFC4DF0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 54, $width, $height, $hBrush) EndIf ;44 If $value > 42 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFC1E40F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 56, $width, $height, $hBrush) EndIf ;42 If $value > 40 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFBDEA0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 58, $width, $height, $hBrush) EndIf ;40 If $value > 38 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFBAF00F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 60, $width, $height, $hBrush) EndIf ;38 If $value > 36 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFBAF00F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 62, $width, $height, $hBrush) EndIf ;36 If $value > 34 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFADEF0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 64, $width, $height, $hBrush) EndIf ;34 If $value > 32 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFA1EE0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 66, $width, $height, $hBrush) EndIf ;32 If $value > 30 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF94ED0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 68, $width, $height, $hBrush) EndIf ;30 If $value > 28 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF88ED0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 70, $width, $height, $hBrush) EndIf ;28 If $value > 26 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF7CEC0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 72, $width, $height, $hBrush) EndIf ;26 If $value > 24 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF6FEB0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 74, $width, $height, $hBrush) EndIf ;24 If $value > 22 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF63EA0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 76, $width, $height, $hBrush) EndIf ;22 If $value > 20 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF56EA0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 78, $width, $height, $hBrush) EndIf ;20 If $value > 18 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF56EA0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 80, $width, $height, $hBrush) EndIf ;18 If $value > 16 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF4AE90F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 82, $width, $height, $hBrush) EndIf ;16 If $value > 14 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF3EE80F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 84, $width, $height, $hBrush) EndIf ;14 If $value > 12 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF31E70F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 86, $width, $height, $hBrush) EndIf ;12 If $value > 10 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF25E70F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 88, $width, $height, $hBrush) EndIf ;10 If $value > 8 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF18E60F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 90, $width, $height, $hBrush) EndIf ;8 If $value > 6 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF0CE50F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 92, $width, $height, $hBrush) EndIf ;6 If $value > 4 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF00E510") _GDIPlus_GraphicsFillRect($hGraphic, 0, 94, $width, $height, $hBrush) EndIf ;4 If $value > 2 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF00E509") _GDIPlus_GraphicsFillRect($hGraphic, 0, 96, $width, $height, $hBrush) EndIf ;2 $hBrush = _GDIPlus_BrushCreateSolid("0xFF00E509") _GDIPlus_GraphicsFillRect($hGraphic, 0, 98, $width, $height, $hBrush) $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage) GUICtrlSendMsg($target, 0x172, 0, $hBitmap) _WinAPI_DeleteObject($hBitmap) _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_ImageDispose($hImage) _GDIPlus_Shutdown() EndFunc ;==>_CreateBar Func DLL_BitmapCreate($width, $height) Local $aResult = DllCall($__g_hGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $width, "int", $height, "int", 0, "int", 0x0026200A, "ptr", 0, "int*", 0) Return $aResult[6] EndFunc ;==>DLL_BitmapCreate  
       
    • Pricehacker
      By Pricehacker
      Hello,
      I am making a program where the button is an image that "changes" when specific conditions are fullfilled. Problem is that these images have different dimensions and when a smaller picture is displayed over a bigger one both will be seen, therefore i would like the images to be hidden, invincible or, alternatively, deleted.
      I have tried using _GDIPlus_GraphicsClear() with no luck
      However that might just be me not using it right as im quite new to autoit
      Here is the code if you want to test run it:
      Thanks to everyone helping!
    • UEZ
      By UEZ
      AutoIt Windows Screenshooter
      Key Features:
      takes easily a screenshot from any visible window capture any region of the desktop incl. freehand capturing capture GUI controls and GUI menus separately capture a marked area every x seconds for a duration of y seconds create a GIF animation from saved frames (Vista or higher os required) capture to AVI file (without audio!) takes a screenshot from web sites (available only on Win7+ os and when Aero is enabled) put images to clipboard to paste to other applications easily color picker save image in different formats and also to PDF! add timestamp to saved images simple image editing options: greyscale, b&w, invert, rotate +-90° send image to printer and default email client preview of captured screens incl. zoom option multi monitor support display pixel color under mouse ruler basic image editor (paint, highlight, ellipse, rectangle, text and some graphic FX) watermark captured image no 3rd party tools or DLLs used - pure AutoIt! fully portable - no installation is needed multi language feature (Eng, Ger, Tur, Fra and Rus only) To do:
      capture content of scrollable window/control capture cascaded menus Due to DllCall("User32.dll", "int", "PrintWindow", "hwnd", $hWnd, "handle", $hMemDC, "int", 0) limitation some windows cannot be captured properly (GDI+, ProgDVB, etc.) but can take screenshots of hidden windows. One workaround is to use full screen capturing (F11/F12) or "Grab Screen" function! Or try double click with rmb on listview items (beta).
      Download source code (6295 downloads previously):  AutoIt Windows Screenshooter v1.81 Build 2018-08-12.7z (version 3.3.12.0+ needed!)
      You are not allowed to sell this code or just parts of it in a commercial project or modify it and distribute it with a different name!
      Download compiled Exe only: 4shared / Media Fire / Softpedia (1.54mb)
      Distributing copies of the program in compiled format (exe) must be free of any fee!
      -----> click here to Donate!  
       
      (Current donators: 1. Cuong N.) 
      It is designed for Win7+ operating systems with AERO enabled! E.g. on WinXP machines some functions are not working properly and might crash the application!
      AV scanners may have a negative impact the execution of compiled exe and might report any malware. I guarantee that there is no malicious code in the source code / exe!!! 
      Main GUI:

       
       
      About Intro:

       
       
      Basic Image Editor:

       
       
      Watermark:

       
       
      Click link for an enhanced version of Watermark Image.
      Credits:
      main code by UEZ additional code (alphabetical order) by Authenticity, AutoItObject Team, Eemuli, Eukalyptus, funkey, _Kurt, martin, monoceres, ProgAndy, taietel, trancexx, Ward, wolf9228 and Yashied! mesale0077 for turkish translation wakillon for french translation AZJIO for russian translation Keys:
      Main GUI:
      User your mouse to scroll preview window or
      Numpad 8: Scroll preview window up
      Numpad 2: Scroll preview window down
      Numpad 4: Scroll preview window left
      Numpad 6: Scroll preview window right
      Numpad +: zoom in preview window or mousewheel down
      Numpad -: zoom out preview window or mousewheel up
      F1: capture again on last position
      F5: refresh Windows Name list
      PRINTSCREEN: take screenshot from whole screen
      ALT+PRINTSCR: take a screenshot from active window
      F10: Undo made changes with Image Editing function
      F11: take screenshot from whole screen incl mouse cursor
      F12: take screenshot from whole screen
      Ctrl+Alt+F9 start "Grab Screen" mode
      Ctrl+Alt+F12: take a screenshot from active window using alternative screenshot functionality (beta)!
      Ctrl+r: call ruler
      Ctrl+s: save current displayed image
      Ctrl+x: exit program
      ctrl+w: call web grab input field (availabe only when Aero is enabled)
      Ctrl+i: call image editor
      Ctrl+m: call watermark editor
      Ctrl+z: undo
      Only available on Vista+ os: double click with rmb on list items to use alternative screenshot functionality (beta)!
      When 'Grab Screen' is clicked you can hold down the ctrl key to switch to 'grab controls' mode. Control under mouse will be framed red.
      ctrl + shift will take the screenshot of appropriate control. To capture GUI menues you can press rmb which simulates the lmb. When a menu is opened press shift additionaly to capture it.
      Press and hold only the shift key to capture any region on the desktop using freehand capturing - release it so capture marked regions!
      Or just mark resizeable area which you want to grab. Press CTRL key to grab marked area or right mouse button to capture the marked area every x seconds for a duration of y seconds.
      When saving the image just enter the extension you whish to use (*.jpg;*.png;*.bmp;*.gif;*.tif;*.pdf). Big thanks to taietel for his PDF UDF!
      Image Editor:
      s: save
      c: copy
      n: send
      h: highlighter
      p: pen
      r: rectangle
      e: ellipse
      a: arrow
      o: color
      t: text
      g: text config
      Ctrl+z: undo
      Watermark editor:
      Ctrl+z: undo
       
      To start the app minimized just call it "Windows Screenshooter.exe /min"
      Maybe it is useful for someone...
      Any kind of comment is welcome.
      Br,
      UEZ
      Change log:
       
    • c.haslam
      By c.haslam
      I think that _GDIPlus_ImageGetPropertyItem should return a Property Item that can readily be set as a property of another image. Why would one want to do this? A script might (as one of mine does) edit an image of a .jpg file then write the result to a .jpg file. In editing it, in my case, the number of horizontal and vertical pixels change, and the date/time edited should be set as a property. All other property items remain the same. Other GDI+ users may change other properties.
      So an approach is to copy all the property items from image1 to image2, then update a few properties.
      M$ provides a Property Item class (id, length, pointer to an array of values) but _GDIPlus_ImageGetPropertyItem returns something different.
      I think that, wherever reasonable, UDFs that are wrappers for M$ methods should work like M$'s methods. _GDIPlus_ImageGetPropertyItem does not do this:
      While M$ returns 2 values for a value that is a ratio of 2 numbers,  _GDIPlus_ImageGetPropertyItem returns numerator/denominator as a single value (often a Double). _GDIPlus_ImageSetPropertyItem (when included in GDIPlus.au3) will be unable to set ratio property items properly because it cannot know what the numerator and denominator are. So copying such property items will not work properly. M$ has a Void* buffer where the buffer is an array of values but _GDIPlus_ImageGetPropertyItem() returns the values in the same 1-d array as id, length and type. M$'s approach produces a 1-d array with the same number of elements for all property items while _GDIPlus_ImageGetPropertyItem produces a 1-d array with various numbers of elements. To me, this is not good programming practice. For a photo from a Sony camera, the worst case has 1-d array with 67 elements. When combined into a 2-d array with the property items of all properties, there are 66 rows and 67 columns, with many elements not used. So I suggest that _GDIPlus_ImageGetPropertyItem look like this:
      ; #FUNCTION# ==================================================================================================================== ; Name ..........: cGDIPlus_ImageGetPropertyItem ; Description ...: Gets a specified property item (piece of meta data) from an Image object ; Syntax ........: cGDIPlus_ImageGetPropertyItem($hImage, $iPropID) ; Parameters ....: $hImage - Pointer to an image object ; $iPropID - Identifier of the property item to be retrieved ; Return values .: Success: Array containing the values of the property item ; [0] - identifier ; [1] - size, in bytes, of the value array ; [2] - type of value(s) in the value array ; [3] - value array ; Failure: Sets the @error flag to non-zero, @extended may contain GPSTATUS error code ($GPID_ERR*). ; Author ........: Eukalyptus ; Modified ......: c.haslam ; Remarks .......: types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4, ; unsinged rational = 5, undefined = 7, signed long = 9, signed rational = 10 ; Related .......: _GDIPlus_ImageGetPropertyIdList ; Link ..........: https://msdn.microsoft.com/en-us/library/windows/desktop/ms535390(v=vs.85).aspx, ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms534493(v=vs.85).aspx, ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms534414(v=vs.85).aspx ; Example .......: Yes ; =============================================================================================================================== Func cGDIPlus_ImageGetPropertyItem($hImage, $iPropID) Local $iSize = __GDIPlus_ImageGetPropertyItemSize($hImage, $iPropID) If @error Then Return SetError(@error, @extended, -1) Local $tBuffer = DllStructCreate("byte[" & $iSize & "];") Local $pBuffer = DllStructGetPtr($tBuffer) Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipGetPropertyItem", "handle", $hImage, "uint", _ $iPropID, "uint", $iSize, "struct*", $tBuffer) If @error Then Return SetError(@error, @extended, -1) If $aResult[0] Then Return SetError(10, $aResult[0], False) Local $tPropertyItem = DllStructCreate("int id; int length; short type; ptr pvalue;", $pBuffer) Local $iBytes = DllStructGetData($tPropertyItem, "length") Local $pValue = DllStructGetData($tPropertyItem, "pvalue") Local $aRet[4] Local $type = DllStructGetData($tPropertyItem,'type') Local $tValues, $iValues Switch $type Case 2 ;ASCII String $iValues = 1 $tValues = DllStructCreate("char[" & $iBytes & "];", $pValue) Case 3 ;Array of UShort $iValues = Int($iBytes / 2) $tValues = DllStructCreate("ushort[" & $iValues & "];", $pValue) Case 4, 5 ;Array of UInt / Fraction $iValues = Int($iBytes / 4) $tValues = DllStructCreate("uint[" & $iValues & "];", $pValue) Case 9, 10 ;Array of Int / Fraction $iValues = Int($iBytes / 4) $tValues = DllStructCreate("int[" & $iValues & "];", $pValue) Case Else ;Array of Bytes $iValues = 1 $tValues = DllStructCreate("byte[" & $iBytes & "];", $pValue) EndSwitch $aRet[0] = DllStructGetData($tPropertyItem,'id') $aRet[1] = $iBytes $aRet[2] = $type Local $aVals[$iValues] If $type=2 Or $type=7 Then ; ASCII string or undefined $aVals[0] = DllStructGetData($tValues,1) Else For $i = 0 To $iValues-1 $aVals[$i] = DllStructGetData($tValues,1,$i+1) Next EndIf $aRet[3] = $aVals Return $aRet EndFunc And here is an example:
      #include <GDIPlus.au3> #include <Array.au3> Example() Func Example() _GDIPlus_Startup() Local $hImage = _GDIPlus_ImageLoadFromFile(RegRead((@AutoItX64 = True ? "HKLM\SOFTWARE\Wow6432Node\AutoIt v3\AutoIt" : "HKLM\SOFTWARE\AutoIt v3\AutoIt"), "InstallDir") & "\Examples\GUI\Torus.png") If @error Then _GDIPlus_Shutdown() MsgBox(16, "", "An error has occured - unable to load image!", 30) Return False EndIf Local $ar = _GDIPlus_ImageGetPropertyIdList($hImage) Local $vPropNbrs[UBound($ar,1)-1] ; Extract ID numbers For $i = 1 To UBound($ar,1)-1 $vPropNbrs[$i-1] = $ar[$i][0] Next ; Get all property items Local $aPropItems[UBound($vPropNbrs)][4],$vPropItem For $i = 0 To UBound($vPropNbrs)-1 $vPropItem = cGDIPlus_ImageGetPropertyItem($hImage,$vPropNbrs[$i]) For $j = 0 To 3 $aPropItems[$i][$j] = $vPropItem[$j] Next Next ; Collapse values arrays so _ArrayDisplay can display them Local $ar = $aPropItems For $i = 0 To UBound($aPropItems,1)-1 $ar[$i][0] = '0x'&Hex($ar[$i][0],4) $ar[$i][3] = '' For $j = 0 To UBound($aPropItems[$i][3])-1 $ar[$i][3] &= ($aPropItems[$i][3])[$j]&'|' Next $ar[$i][3] = StringTrimRight($ar[$i][3],1) Next _ArrayDisplay($ar) _GDIPlus_Shutdown() EndFunc Unfortunately this example (based on one now in the Help) does not exercise most of the item types, but I do not know of a file with EXIF metadata that is on most PCs. I have tested this code by updating and adding property items to torus.jpg and to a photo taken by a Sony camera. The code for implementing and calling _GDIPlus_ImageSetPropertyItem will be fairly simple [see below].
       
      Your thoughts?
       
    • c.haslam
      By c.haslam
      I have a strange symptom of a problem somewhere in my code, or in a UDF: when I add code to get all properties of a GDI+ image to a 6000-line script,  the variable type of a parameter is reported as a pointer when the caller clearly has this argument as a string. If I comment out my code that gets the properties, the function properly sees the parameter as a string.
      [Edit: The reporting as a pointer and getting image properties are miles apart, both in where they are in the script code and in where they are run.]
      At this point, I am looking for clues as to why this is happening, so the hunt is on!
      I have noticed one odd thing, in _GDIPlus_ImageGetPropertyIdList() I see a line that begins Local $sPropertyTagInfo = . This "line" is split into 2 lines. SCiTE shows that the first line is 2454 characters and the second 2400. Adding these numbers I get 4854 characters.
      But the Help for AutoIt3 Limits/defaults says that MAXLINESIZE, Maximum size for a line of script, is 4096 characters.
      The line would exceed the limit if AutoIt considers the subject line to be 1 line and not 2 lines.
      My question: is this line legal? Is buffer overun possible?
×