Jump to content
c.haslam

DllStructCreate not allocating memory for byte array?

Recommended Posts

c.haslam

In the code that follows, it appears that DllStructCreate() is not allocating memory in

$tag = 'byte val['&$iLength&']'
.
.
Static Local $tvalue = DllStructCreate($tag)

Running the code below, the problem does not show, but it does show in a much longer script: there _GDIPlus_ImageSaveToFile only writes about 30K bytes when it should write about 1MB, which it does when the code is

$tag = 'char val['&$iLength&']'
.
.
Static Local $tvalue = DllStructCreate($tag)

It should write about 1 MB.

I suggest caution in running the code below. On my PC, it caused a second instance of SciTE to appear at the top left of the Desktop, showing only the title bar, with a width of only approximately 200 pixels! Then rebooting the PC showed this at login. Further, double-clicking on the SciTE shortcut on the Desktop showed SciTE in the same way! (After running Regedit, and searching for SciTE, the shortcut behaves normally.)

I would appreciate help in determining whether or not there is a bug in DLLStructCreate, preferably a way which does not clobber Windows. Of course, It is possible that there is a bug in my code.

I have made $tvalue Static in the hope that this might make the code run properly. Doing this did not help.

My code is based on code written by Authenticity and ChrisL.

#include <GDIPlus.au3>
#include <Array.au3>
Opt('MustDeclareVars',1)

; Property Item structure
Global Const $tagGDIPPROPERTYITEM = _
    "uint id;" & _          ; ID of this property
    "ulong length;" & _     ; Length of the property value, in bytes
    "word type;" & _        ; Type of the value, as one of TAG_TYPE_XXX constants
    "ptr pvalue;"           ; pointer to 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:\temp\AP test data\DSC00824 - Copy.jpg')

    Local $ar = _GDIPlus_ImageGetAllPropertyItemsEx($hImage)
    Local $propsAr[UBound($ar,1)-1][5],$vec,$j=-1
    For $i = 1 To $ar[0][0]
        If $ar[$i][3]<>0 Then   ; pValue -- for Sony!
            $j += 1
            $propsAr[$j][0] = $ar[$i][0]    ; id
            $propsAr[$j][1] = $ar[$i][1]    ; length
            $propsAr[$j][2] =$ar[$i][2]; type
            $vec = _GDIPlus_ImageGetPropertyItemValue($ar[$i][1],$ar[$i][2],$ar[$i][3])
            $propsAr[$j][3] = $vec[0]   ; val1
            Switch $ar[$i][2]
                Case 5,10   ; $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL
                    $propsAr[$j][4] = $vec[1]
                Case Else
                    $propsAr[$j][4] = ''
            EndSwitch
        EndIf
    Next
    ReDim $propsAr[$j+1][5]

    For $i = 0 To UBound($propsAr,1)-1
        Switch $propsAr[$i][2]  ; type
            Case 5,10   ; $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL
                _GDIPlus_ImageSetPropertyItemEx($hImage,$propsAr[$i][0],$propsAr[$i][1], _
                    $propsAr[$i][2],$propsAr[$i][3],$propsAr[$i][4])
            Case Else
                _GDIPlus_ImageSetPropertyItemEx($hImage,$propsAr[$i][0],$propsAr[$i][1], _
                    $propsAr[$i][2],$propsAr[$i][3])
        EndSwitch
    Next
    _GDIPlus_ImageSaveToFile($hImage,'H:\b\1.jpg')
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
EndFunc

Func _GDIPlus_ImageGetAllPropertyItemsEx($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)

    $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)
    If $aResult[0] Then Return SetError(10, $aResult[0], False)

    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, "pvalue")
        $pBuffer += DllStructGetSize($tPropertyItem)
    Next

    Return $aPropertyItems
EndFunc

Func _GDIPlus_ImageGetPropertyItemValue($iLength, $iType, $pValue)
    Static Local $tvalue
    Switch $iType
        Case 1,6    ; $GDIP_PROPERTYTAGTYPEUBYTE,$GDIP_PROPERTYTAGTYPESBYTE
            $tvalue = DllStructCreate('byte val',$pValue)
        Case 2      ; $GDIP_PROPERTYTAGTYPEASCII
            $tvalue = DllStructCreate('char val['&$iLength&']',$pValue)
        Case 3      ; $GDIP_PROPERTYTAGTYPEUSHORT
            $tvalue = DllStructCreate('ushort val',$pValue)
        Case 4      ; $GDIP_PROPERTYTAGTYPEULONG
            $tvalue = DllStructCreate('ulong val',$pValue)
        Case 5      ; $GDIP_PROPERTYTAGTYPEURATIONAL
            $tvalue = DllStructCreate('ulong val1;ulong val2',$pValue)
        Case 7      ; $GDIP_PROPERTYTAGTYPEUNDEFINED
            ; undefined, per specification, but may be a long but is sometimes a string
            $tvalue = DllStructCreate('byte val['&$ilength&']',$pValue) ; see _GDIPlus_ImageSetPropertyItemEx
;~          $tvalue = DllStructCreate('char val['&$ilength&']',$pValue)
        Case 8      ; $GDIP_PROPERTYTAGTYPESSHORT
            $tvalue = DllStructCreate('short val',$pValue)
        Case 9      ; $GDIP_PROPERTYTAGTYPEULONG
            $tvalue = DllStructCreate('ulong val',$pValue)
        Case 10     ; $GDIP_PROPERTYTAGTYPESRATIONAL
            $tvalue = DllStructCreate('ulong val1;ulong val2',$pValue)
        Case 11     ; $GDIP_PROPERTYTAGTYPESFLOAT
            $tvalue = DllStructCreate('float val',$pValue)
        Case 12     ; $GDIP_PROPERTYTAGTYPEDFLOAT
            $tvalue = DllStructCreate('double val',$pValue)
    EndSwitch
    If @error Then Return SetError(@error,0,-1)
    Switch $iType
            Case 5,10   ; $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL
            Local $aRet[2]
            $aRet[0] = DllStructGetData($tvalue,'val1')
            $aRet[1] = DllStructGetData($tvalue,'val2')
        Case Else
            Local $aRet[1]
            $aRet[0] = DllStructGetData($tvalue,'val')
    EndSwitch
    Return $aRet
EndFunc

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)

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

Func _GDIPlus_ImageSetPropertyItemEx($hImage,$id,$iLength,$iType,$value1,$value2=-1)
    Local $tProp = DllStructCreate($tagGDIPPROPERTYITEM)
    DllStructSetData($tProp,'id',$id)
    DllStructSetData($tProp,'type',$itype)
    DllStructSetData($tProp,'length',$ilength)
    Local $tag
    Switch $iType
        Case $GDIP_PROPERTYTAGTYPEUBYTE,$GDIP_PROPERTYTAGTYPESBYTE
            $tag = 'byte val'
        Case $GDIP_PROPERTYTAGTYPEASCII
            $tag = 'char val['&$iLength&']'
        Case $GDIP_PROPERTYTAGTYPEUSHORT
            $tag = 'ushort val'
        Case $GDIP_PROPERTYTAGTYPEULONG
            $tag = 'ulong val'
        Case $GDIP_PROPERTYTAGTYPEURATIONAL
            $tag =  'ulong val1;ulong val2'
        Case $GDIP_PROPERTYTAGTYPEUNDEFINED
            ; undefined, per specification, but may be a long but is sometimes a string
            $tag = 'byte val['&$iLength&']' ; causes saving to jpeg to write junk
;~          $tag = 'char val['&$iLength&']'
        Case $GDIP_PROPERTYTAGTYPESSHORT
            $tag = 'short val'
        Case $GDIP_PROPERTYTAGTYPEULONG
            $tag = 'ulong val'
        Case $GDIP_PROPERTYTAGTYPESRATIONAL
            $tag =  'long val1;long val2'
        Case $GDIP_PROPERTYTAGTYPESFLOAT
            $tag = 'float val'
        Case $GDIP_PROPERTYTAGTYPEDFLOAT
            $tag = 'double val'
    EndSwitch
    Static Local $tvalue = DllStructCreate($tag)
    Switch $iType
        Case $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL
            DllStructSetData($tvalue,'val1',$value1)
            DllStructSetData($tvalue,'val2',$value2)
        Case Else
            DllStructSetData($tvalue,1,$value1)
    EndSwitch
    DllStructSetData($tProp,'pvalue',DllStructGetPtr($tvalue))

    Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipSetPropertyItem", "hwnd", $hImage, "ptr", _
    DllStructGetPtr($tProp))
    If @error Then Return SetError(@error, @extended, -1)
    If $aResult[0] Then Return SetError(10, $aResult[0], -1)

    Return $aResult[0] = 0
EndFunc

I have seen $iLength be as much as 37 KB for $GDIP_PROPERTYTAGTYPEUNDEFINED.

Is there is a bug, how can this be demonstrated to the developers in a few lines of code (without clobbering Windows)?

 

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 have now found, with code similar to that in the first post, that a script can produce different results when run several times. My new testing shows that there are inconsistent results in handling property types other than $GDIP_PROPERTYTAGTYPEUNDEFINED.

A result consists of:

  • ArrayDisplay .png file, showing the id, length, type and value(s) of each of the properties
  • Output file size reported by the script
  • @extended (GDIPLUS Status value) from _GDIPlus_ImageSaveToFile()

I know what val1 and val2 should be from Irfanview. The output file size should be 916K, it being a copy of the input file. The Status value should be zero.

I ran the script 7 times:

  • 3 displayed the values of the first 27 properties OK in _ArrayDisplay() and most of properties 30 to 63 as zeroes when they should be non-zero, output file size as 36K and GDIP Status as 7 (Win32 error)
  • 3 displayed the values of all properties correctly in _ArrayDisplay(), file size as 916K and GDIP status as 0 (OK)
  • 1 the values of the first 27 properties as zeros (which is wrong), file size as 916K and GDIP status as 0 (OK)

The PC is running AOK (except as noted in Post1, which happened once). I have an AutoIt script which runs automatically daily with no problems. So the cause of this odd behavior is either a subtle error in my code or a bug in AutoIt.

My thoughts turn to the idea that there is a memory leak somewhere, possibly caused by my code. The input file has not changed.

I am wondering how I can allocate memory to structs independent of DllStructCreate(). Doing so might identify the problem. Do I use _MemGlobalAlloc() to allocate memory and _MemGlobalFree() to release it in _GDIPlus_ImageGetPropertyItemValue()? If so, with what parameters?

The code follows, and the attached .png's show _ArrayDisplay() results.

 

#include <GDIPlus.au3>
#include <Array.au3>
Opt('MustDeclareVars',1)
;~ #include "..\cDebug.au3"

; Property Item structure
Global Const $tagGDIPPROPERTYITEM = _
    "uint id;" & _          ; ID of this property
    "ulong length;" & _     ; Length of the property value, in bytes
    "word type;" & _        ; Type of the value, as one of TAG_TYPE_XXX constants
    "ptr pvalue;"           ; pointer to 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

OnAutoItExitRegister(FinishUp)

main()

Func main()
    _GDIPlus_Startup()

    Local $hImage = _GDIPlus_ImageLoadFromFile('H:\temp\AP test data\DSC00824 - Copy.jpg')
    Local $propsAr = GetProperties($hImage)

Local $dAr = $propsAr
For $i = 0 To UBound($propsAr,1)-1
    $dAr[$i][0] = Hex($propsAr[$i][0],4)
Next
_ArrayDisplay($dAr,'At line '&@ScriptLineNumber,'',0,Default,'id|length|type|val1|val2')

    For $i = 0 To UBound($propsAr,1)-1
        Switch $propsAr[$i][2]  ; type
            Case 5,10   ; $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL
                _GDIPlus_ImageSetPropertyItemEx($hImage,$propsAr[$i][0],$propsAr[$i][1], _
                    $propsAr[$i][2],$propsAr[$i][3],$propsAr[$i][4])
            Case Else
                _GDIPlus_ImageSetPropertyItemEx($hImage,$propsAr[$i][0],$propsAr[$i][1], _
                    $propsAr[$i][2],$propsAr[$i][3])
        EndSwitch
    Next
    $propsAr = GetProperties($hImage)   ; causes save file to fail
;~ _ArrayDisplay($propsAr,@ScriptLineNumber)
    Local $ouFilspc = 'H:\b\1.jpg'
    _GDIPlus_ImageSaveToFile($hImage,$ouFilspc)
    If @error Then MsgBox(0,'_GDIPlus_ImageSaveToFile','@error '&@error&' @extended '&@extended)
    _GDIPlus_ImageDispose($hImage)
    Local $vec = FileGetTime($ouFilspc)
    MsgBox(0,@ScriptLineNumber,'Output: file size '&FileGetSize($ouFilspc)& _
        ' bytes at '&StringFormat('%s-%02s-%02s %02s:%02s',$vec[0],$vec[1],$vec[2],$vec[3],$vec[4]))
EndFunc

Func GetProperties($hImage)
    Local $ar = _GDIPlus_ImageGetAllPropertyItemsEx($hImage)
    Local $propsAr[UBound($ar,1)-1][5],$vec,$j=-1
    For $i = 1 To $ar[0][0]
        If Not ($ar[$i][3]=0 Or ($ar[$i][2]=2 And $ar[$i][1]=0)) Then   ; pValue, type, length -- for Sony!
            $j += 1
            $propsAr[$j][0] = $ar[$i][0]    ; id
            $propsAr[$j][1] = $ar[$i][1]    ; length
            $propsAr[$j][2] =$ar[$i][2]; type
            $vec = _GDIPlus_ImageGetPropertyItemValue($ar[$i][1],$ar[$i][2],$ar[$i][3])
            $propsAr[$j][3] = $vec[0]   ; val1
            Switch $ar[$i][2]
                Case 5,10   ; $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL
                    $propsAr[$j][4] = $vec[1]
                Case Else
                    $propsAr[$j][4] = ''
            EndSwitch
        EndIf
    Next
    ReDim $propsAr[$j+1][5]
    Return $propsAr
EndFunc

Func _GDIPlus_ImageGetAllPropertyItemsEx($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)

    $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)
    If $aResult[0] Then Return SetError(10, $aResult[0], False)

    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, "pvalue")
        $pBuffer += DllStructGetSize($tPropertyItem)
    Next

    Return $aPropertyItems
EndFunc

Func _GDIPlus_ImageGetPropertyItemValue($iLength, $iType, $pValue)
    Static Local $tvalue
    Switch $iType
        Case 1,6    ; $GDIP_PROPERTYTAGTYPEUBYTE,$GDIP_PROPERTYTAGTYPESBYTE
            $tvalue = DllStructCreate('byte val',$pValue)
        Case 2      ; $GDIP_PROPERTYTAGTYPEASCII
            $tvalue = DllStructCreate('char val['&$iLength&']',$pValue)
        Case 3      ; $GDIP_PROPERTYTAGTYPEUSHORT
            $tvalue = DllStructCreate('ushort val',$pValue)
        Case 4      ; $GDIP_PROPERTYTAGTYPEULONG
            $tvalue = DllStructCreate('ulong val',$pValue)
        Case 5      ; $GDIP_PROPERTYTAGTYPEURATIONAL
            $tvalue = DllStructCreate('ulong val1;ulong val2',$pValue)
        Case 7      ; $GDIP_PROPERTYTAGTYPEUNDEFINED
            ; undefined, per specification, but may be a long but is sometimes a string
            $tvalue = DllStructCreate('byte val['&$ilength&']',$pValue) ; see _GDIPlus_ImageSetPropertyItemEx
;~          $tvalue = DllStructCreate('char val['&$ilength&']',$pValue)
        Case 8      ; $GDIP_PROPERTYTAGTYPESSHORT
            $tvalue = DllStructCreate('short val',$pValue)
        Case 9      ; $GDIP_PROPERTYTAGTYPEULONG
            $tvalue = DllStructCreate('ulong val',$pValue)
        Case 10     ; $GDIP_PROPERTYTAGTYPESRATIONAL
            $tvalue = DllStructCreate('ulong val1;ulong val2',$pValue)
        Case 11     ; $GDIP_PROPERTYTAGTYPESFLOAT
            $tvalue = DllStructCreate('float val',$pValue)
        Case 12     ; $GDIP_PROPERTYTAGTYPEDFLOAT
            $tvalue = DllStructCreate('double val',$pValue)
    EndSwitch
    If @error Then Return SetError(@error,0,-1)
    Switch $iType
            Case 5,10   ; $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL
            Local $aRet[2]
            $aRet[0] = DllStructGetData($tvalue,'val1')
            $aRet[1] = DllStructGetData($tvalue,'val2')
        Case Else
            Local $aRet[1]
            $aRet[0] = DllStructGetData($tvalue,'val')
    EndSwitch
    Return $aRet
EndFunc

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)

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

Func _GDIPlus_ImageSetPropertyItemEx($hImage,$id,$iLength,$iType,$value1,$value2=-1)
    Local $tProp = DllStructCreate($tagGDIPPROPERTYITEM)
    DllStructSetData($tProp,'id',$id)
    DllStructSetData($tProp,'type',$itype)
    DllStructSetData($tProp,'length',$ilength)
    Local $tag,$tvalue
    Switch $iType
        Case $GDIP_PROPERTYTAGTYPEUBYTE,$GDIP_PROPERTYTAGTYPESBYTE
            $tvalue = DllStructCreate('byte val;')
        Case $GDIP_PROPERTYTAGTYPEASCII
            $tvalue = DllStructCreate('char val['&$iLength&'];')
        Case $GDIP_PROPERTYTAGTYPEUSHORT
            $tvalue = DllStructCreate('ushort val;')
        Case $GDIP_PROPERTYTAGTYPEULONG
            $tvalue = DllStructCreate('ulong val;')
        Case $GDIP_PROPERTYTAGTYPEURATIONAL
            $tvalue = DllStructCreate('ulong val1;ulong val2;')
        Case $GDIP_PROPERTYTAGTYPEUNDEFINED
            ; undefined, per specification, but may be a long but is sometimes a string
;~          $tag = 'byte val['&$iLength&']' ; causes saving to jpeg to write junk
            $tvalue = DllStructCreate('char val['&$iLength&'];')
        Case $GDIP_PROPERTYTAGTYPESSHORT
            $tvalue = DllStructCreate('short val;')
        Case $GDIP_PROPERTYTAGTYPEULONG
            $tvalue = DllStructCreate('ulong val;')
        Case $GDIP_PROPERTYTAGTYPESRATIONAL
            $tvalue = DllStructCreate('long val1;long val2;')
        Case $GDIP_PROPERTYTAGTYPESFLOAT
            $tvalue = DllStructCreate('float val;')
        Case $GDIP_PROPERTYTAGTYPEDFLOAT
            $tvalue = DllStructCreate('double val;')
    EndSwitch
;~ If @error Then _Msgdebug(@ScriptLineNumber&' create','@error,$id,$ilength,$iType,$value1,$value2',@error,Hex($id,4),$ilength,$iType,$value1,$value2)
    Switch $iType
        Case $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL
            DllStructSetData($tvalue,1,$value1)
;~ If @error Then _Msgdebug(@ScriptLineNumber&' val1','@error,$id,$ilength,$iType,$value1,$value2',@error,Hex($id,4),$ilength,$iType,$value1,$value2)
            DllStructSetData($tvalue,2,$value2)
;~ If @error Then _Msgdebug(@ScriptLineNumber&' val2','@error,$id,$ilength,$iType,$value1,$value2',@error,Hex($id,4),$ilength,$iType,$value1,$value2)
        Case Else
            DllStructSetData($tvalue,1,$value1)
;~ If @error Then _Msgdebug(@ScriptLineNumber&' val','@error,$id,$ilength,$iType,$value1,$value2',@error,Hex($id,4),$ilength,$iType,$value1,$value2)
    EndSwitch
    DllStructSetData($tProp,'pvalue',DllStructGetPtr($tvalue))
;~ If @error Then _Msgdebug(@ScriptLineNumber&' pvalue','@error,$id,$ilength,$iType,$value1,$value2',@error,Hex($id,4),$ilength,$iType,$value1,$value2)

    Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipSetPropertyItem", "hwnd", $hImage, "ptr", _
    DllStructGetPtr($tProp))
    If @error Then Return SetError(@error, @extended, -1)
    If $aResult[0] Then Return SetError(10, $aResult[0], -1)

    Return $aResult[0] = 0
EndFunc

Func FinishUp()
    _GDIPlus_Shutdown()
EndFunc

cDebug.au3 (which is commented out) is my variable-dump library, which can be found here .

The screenshot below shows the values of the first 27 properties as zeros (which is wrong). _GDIPlus_ImageSaveToFile() worked as expected.

Display 1st 27 0, 30 up OK File save 916K, GDIP status 0.png

The screenshot below shows the values of all properties correctly in _ArrayDisplay(). _GDIPlus_ImageSaveToFile() worked as expected.

Display OK File size 916K GDIP status 0.png

The screenshot below shows the values of the first 27 properties OK in _ArrayDisplay() and most of properties 30 to 63 as zeroes when they should be non-zero. The output file size as 36K (which is wrong) and GDIP Status as 7 (Win32 error).

Display first 27 OK 30 up 0 file save 36K GDIP status Win32 error.png

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 have found an error in my understanding of how EXIF data is stored: for example, type $GDIP_PROPERTYTAGTYPEUSHORT (3) indicates that pValue points to an array of unsigned shorts. So there may not be an error in memory allocation by DllStructCreate().


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 have modified the script, recognizing that most of the metadata is stored in a jpeg as arrays. This version abends at run-time with Variable used without being declared on $ouFilspc despite Au3Check not finding any errors, and $oufilspc being declared as Local a few lines before.

Suggestions are most welcome.

#include <GDIPlus.au3>
#include <Array.au3>
Opt('MustDeclareVars',1)
;~ #include "..\cDebug.au3"

; Property Item structure
Global Const $tagGDIPPROPERTYITEM = _
    "uint id;" & _          ; ID of this property
    "ulong length;" & _     ; Length of the property value, in bytes
    "word type;" & _        ; Type of the value, as one of TAG_TYPE_XXX constants
    "ptr pvalue;"           ; pointer to 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

Global $gId

OnAutoItExitRegister(FinishUp)

main()

Func main()
    _GDIPlus_Startup()

;~  Local $hImage = _GDIPlus_ImageLoadFromFile('H:\b\1.jpg')
    Local $hImage = _GDIPlus_ImageLoadFromFile('H:\temp\AP test data\DSC00824 - Copy.jpg')
;~  Local $hImage = _GDIPlus_ImageLoadFromFile('H:\temp\AP test data\pergola photo - Copy.JPG')
    Local $propsAr = GetProperties($hImage)

Local $dAr = $propsAr
For $i = 0 To UBound($propsAr,1)-1
    $dAr[$i][0] = Hex($propsAr[$i][0],4)
    Switch True
        Case IsArray($propsAr[$i][3])
            Local $t='',$vec = $propsAr[$i][3]
            For $j = 0 To UBound($vec)-1
                $t &= '|'&$vec[$j]
            Next
            $t = StringMid($t,2)
            $dAr[$i][3] = $t
    EndSwitch
Next
_ArrayDisplay($dAr,'At line '&@ScriptLineNumber,'',0,Default,'id|length|type|value')

    For $i = 0 To UBound($propsAr,1)-1
        If Not _GDIPlus_ImageSetPropertyItemEx($hImage,$propsAr[$i][0],$propsAr[$i][1], _
            $propsAr[$i][2],$propsAr[$i][3]) Then
            ConsoleWrite('_GDIPlus_ImageSetPropertyItemEx failed'&@CRLF)
        EndIf
    Next
    Local $date = '2017:12:09 14:01:23'
    If Not _GDIPlus_ImageSetPropertyItemEx($hImage,0x9003,20,2,$date) Then

    Local $ouFilspc = 'H:\b\2.jpg'
    _GDIPlus_ImageSaveToFile($hImage,$ouFilspc)
    If @error Then MsgBox(0,'_GDIPlus_ImageSaveToFile','@error '&@error&' @extended '&@extended)
        ConsoleWrite('_GDIPlus_ImageSetPropertyItemEx failed'&@CRLF)
    EndIf

    _GDIPlus_ImageDispose($hImage)
    Local $vec = FileGetTime($ouFilspc) ; at run time:  $ouFilspc "Variable used without being declared"
    MsgBox(0,@ScriptLineNumber,'Output: file size '&FileGetSize($ouFilspc)& _
        ' bytes at '&StringFormat('%s-%02s-%02s %02s:%02s',$vec[0],$vec[1],$vec[2],$vec[3],$vec[4]))
EndFunc

Func GetProperties($hImage)
    Local $ar = _GDIPlus_ImageGetAllPropertyItemsEx($hImage)
    Local $j=-1,$id,$length,$type,$value
    For $i = 1 To $ar[0][0]
        $length = $ar[$i][1]
        $type = $ar[$i][2]
        $value = $ar[$i][3]
        If Not ($value=0 Or ($type=2 And $length=0)) Then
            $j += 1
            $ar[$j][0] = $ar[$i][0]
            $ar[$j][1] = $length
            $ar[$j][2] = $type
            $ar[$j][3] = $value
        EndIf
    Next
    ReDim $ar[$j+1][4]

    Local $propsAr[$j+1][4]
    For $i = 0 To UBound($ar,1)-1
        $propsAr[$i][0] = $ar[$i][0]    ; id
        $propsAr[$i][1] = $ar[$i][1]    ; length
        $propsAr[$i][2] = $ar[$i][2]    ; type
$gId = $propsAr[$i][0]
        $propsAr[$i][3] = _GDIPlus_ImageGetPropertyItemValue($ar[$i][1],$ar[$i][2],$ar[$i][3])
    Next
    Return $propsAr
EndFunc

Func _GDIPlus_ImageGetAllPropertyItemsEx($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)

    $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)
    If $aResult[0] Then Return SetError(10, $aResult[0], False)

    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, "pvalue")
        $pBuffer += DllStructGetSize($tPropertyItem)
    Next

    Return $aPropertyItems
EndFunc

; Returns:
;   byte and undefined: binary
;   string              string
;   rational            vector: [n] numerator, [n=1] denominator
;   else                vector
; Vectors are ref 0
Func _GDIPlus_ImageGetPropertyItemValue($iLength, $iType, $pValue)
    Static Local $tvalue
    Local $qels

    Switch $iType
        Case 1,6,7  ; UBYTE,SBYTE,UNDEFINED
            $tvalue = DllStructCreate('byte binary['&$ilength&']',$pValue)
        Case 2      ; ASCII
            $tvalue = DllStructCreate('char str['&$iLength&']',$pValue)
        Case 3      ; USHORT
            $qels = $iLength/2
            $tvalue = DllStructCreate('ushort valVec['&$qels&']',$pValue)
        Case 4,5    ; ULONG,URATIONAL
            $qels = $iLength/4
            $tvalue = DllStructCreate('ulong valVec['&$qels&']',$pValue)
        Case 8      ; SSHORT
            $qels = $iLength/4
            $tvalue = DllStructCreate('short valVec['&$qels&']',$pValue)
        Case 9,10   ; SLONG,SRATIONAL
            $qels = $iLength/4
            $tvalue = DllStructCreate('long valVec['&$qels&']',$pValue)
        $tvalue = DllStructCreate('double val',$pValue)
    EndSwitch
Local $err = @error
If $err Then
    ConsoleWrite('@error '&$err&@CRLF)
    ConsoleWrite('id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype&@CRLF)
    MsgBox(0,@ScriptLineNumber,'id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype)
EndIf
    If $err Then Return SetError($err,0,-1)
    Local $ret
    Switch $itype
        Case 1,6,7  ; UBYTE,SBYTE,UNDEFINED
            Local $ret =  DllStructGetData($tvalue,'binary')
        Case 2 ; ASCII
            Local $ret = DllStructGetData($tvalue,'str')
        Case Else
            Local $ret[$qels]
            For $i = 0 To $qels-1
                $ret[$i] = DllStructGetData($tvalue,'valVec',$i+1)
            Next
    EndSwitch
If $err Then
    ConsoleWrite('@error '&$err&@CRLF)
    ConsoleWrite('GetData: id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype&@CRLF)
    MsgBox(0,@ScriptLineNumber,'id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype)
EndIf
    Return $ret
EndFunc

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)

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

Func _GDIPlus_ImageSetPropertyItemEx($hImage,$id,$iLength,$iType,$value)
    Local $tProp = DllStructCreate($tagGDIPPROPERTYITEM)
    DllStructSetData($tProp,'id',$id)
    DllStructSetData($tProp,'type',$itype)
    DllStructSetData($tProp,'length',$ilength)
    Local $tag,$tvalue,$qels
    Switch $iType
        Case 1,6,7  ; UBYTE,SBYTE,UNDEFINED
            $tvalue = DllStructCreate('byte binary['&$ilength&']')
        Case 2      ; ASCII
            $tvalue = DllStructCreate('char str['&$iLength&']')
        Case 3      ; USHORT
            $qels = $iLength/2
            $tvalue = DllStructCreate('ushort valVec['&$qels&']')
        Case 4,5    ; ULONG,URATIONAL
            $qels = $iLength/4
            $tvalue = DllStructCreate('ulong valVec['&$qels&']')
        Case 8      ; SSHORT
            $qels = $iLength/2
            $tvalue = DllStructCreate('short valVec['&$qels&']')
        Case 9,10   ; SLONG,SRATIONAL
            $qels = $iLength/4
            $tvalue = DllStructCreate('long valVec['&($iLength/4)&']')
    EndSwitch
Local $err = @error
If $err Then
    ConsoleWrite('@error '&$err&@CRLF)
    ConsoleWrite('SetData: id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype&@CRLF)
    MsgBox(0,@ScriptLineNumber,'id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype)
EndIf
    If $err Then Return SetError($err,0,-1)
    Switch $itype
        Case 1,6,7  ; UBYTE,SBYTE,UNDEFINED
            DllStructSetData($tvalue,'binary',$value)
        Case 2  ; ASCII
            DllStructSetData($tvalue,'str',$value)
        Case Else
            For $i = 0 To $qels-1
                DllStructSetData($tvalue,'valVec',$value[$i],$i+1)
            Next
    EndSwitch
    DllStructSetData($tProp,'pvalue',DllStructGetPtr($tvalue))
Local $err = @error
If $err Then
    ConsoleWrite('@error '&$err&@CRLF)
    ConsoleWrite('SetData: id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype&@CRLF)
    MsgBox(0,@ScriptLineNumber,'id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype)
EndIf

Local $ptr = DllStructGetPtr($tProp)
Local $err = @error
If $err Then
    ConsoleWrite('@error '&$err&@CRLF)
    ConsoleWrite('GetPtr: id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype&@CRLF)
    MsgBox(0,@ScriptLineNumber,'id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype)
EndIf
    Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipSetPropertyItem", "hwnd", $hImage, "ptr", _
    $ptr)
    If @error Then Return SetError(@error, @extended, -1)
    If $aResult[0] Then Return SetError(10, $aResult[0], -1)
    Return $aResult[0] = 0
EndFunc
Func FinishUp()
    _GDIPlus_Shutdown()
EndFunc

 


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
BrewManNH

The problem is that $outFilSpc is only declared if this If statement evaluates to true. If it's undeclared, then the If statement failed.

If Not _GDIPlus_ImageSetPropertyItemEx($hImage, 0x9003, 20, 2, $date) Then

        Local $ouFilspc = 'H:\b\2.jpg'
        _GDIPlus_ImageSaveToFile($hImage, $ouFilspc)
        If @error Then MsgBox(0, '_GDIPlus_ImageSaveToFile', '@error ' & @error & ' @extended ' & @extended)
        ConsoleWrite('_GDIPlus_ImageSetPropertyItemEx failed' & @CRLF)
    EndIf

 


If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites
c.haslam

Many thanks. My really stupid error which I created when I added in diagnostic code.


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
Earthshine
3 hours ago, c.haslam said:

Many thanks. My really stupid error which I created when I added in diagnostic code.

yep, I have done that a few times myself. i always chuckle when it happens


My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
c.haslam

I use single-line Ifs very seldom, because I often get them wrong, as I did above!

There are many alligators in my coding swamp right now, so it is not too surprising that I didn't seem that baby one!


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 have found a curious situation. Snippet:

Func _GDIPlus_ImageGetAllPropertyItemsEx($hImage)
    Local $iI, $iCount, $tBuffer, $pBuffer, $iBuffer, $tPropertyItem, $aPropertyItems[1][1], $aResult
;~  Local $iI, $iCount, $tBuffer, $pBuffer, $iBuffer, $tPropertyItem, $aSize, $aPropertyItems[1][1], $aResult

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

    $iBuffer = $ar[0]
    $tBuffer = DllStructCreate("byte[" & $iBuffer & "]")
    $pBuffer = DllStructGetPtr($tBuffer)
    $iCount = $ar[1]
    $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetAllPropertyItems", "hwnd", $hImage, _
        "uint", $iBuffer, "uint", $iCount, "ptr", $pBuffer)
    If @error Then Return SetError(@error, @extended, -1)
    If $aResult[0] Then Return SetError(10, $aResult[0], False)
    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, "pvalue")
        $pBuffer += DllStructGetSize($tPropertyItem)
    Next

    Return $aPropertyItems
EndFunc

Func _GDIPlus_ImageGetPropertySize($hImage)
    Local $aRet[2], $aResult

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

    $aRet[0] = $aResult[2]  ; size in bytes
    $aRet[1] = $aResult[3]  ; number of property items
    Return $aRet
EndFunc   ;==>_GDIPlus_ImageGetPropertySize

When I run the script of which this is a part, $iBuffer is 43763 bytes long and $iCount is 66. The code above, which is from GDIP.7z, assumes that GdipGetAllProperty Items sets pBuffer to point to PropertyItem1, PropertyItem2, ... PropertyItemN. The property item struct is

$tagGDIPPROPERTYITEM = _
    "uint id;" & _          ; ID of this property
    "ulong length;" & _     ; Length of the property value, in bytes
    "word type;" & _        ; Type of the value, as one of TAG_TYPE_XXX constants
    "ptr pvalue;"           ; pointer to property value

Note the pointer. The length of this struct is 16 bytes. So if the data is arranged in this way, $iBuffer would be 66 x 16 = 1056 bytes! So the data cannot be arranged linearly, with one property item after another.

Scenario 2

What if the tag should be like

$tagGDIPPROPERTYITEM = _
    "uint id;" & _          ; ID of this property
    "ulong length;" & _     ; Length of the property value, in bytes
    "word type;" & _        ; Type of the value, as one of TAG_TYPE_XXX constants
    "byte valueVec["&$iLength&"];"

?

I know that one of the property items is about 37K long, and another 1.1K long. The lengths of id, length and type add up to 12 bytes. The lengths of the other values probably average 5.

37K + 1.1K + (12 + 5)*66 = 39222. This is fairly close to 43763 -- but not close enough to convince me that Scenario 2 is correct.

Also,it is strange that the buffer needs to be an odd number of bytes long, because the length of the struct in Scenario1 above (the one I am using) is an even number of bytes.

So what goes?

Early in my trials, I thought that the data is arranged as in Scenario 2. I don't remember where I got this idea.

If the data is arranged per Scenario 2, why does getting property items work as well as it does?

After a night's sleep, I realized that $iBuffer may be the total size occupied by property items. My script now adds up the lengths. They add up to 42707 bytes. 43763 - 42707 = 1056. 1056 / 16 = 66 which is the number of property items! So $iBuffer is the space occupied by values! It is time to do some more thinking.

This does mean that $tBuffer is larger than it needs to be. It also implies that $tagGDIPPROPERTYITEM is correct.

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
RTFC
5 hours ago, c.haslam said:

There are many alligators in my coding swamp

:lol: You're lucky your swamp is in your code; mine is between my ears!:D

Not sure whether you've considered this (if so, just ignore this), but be aware of potential member alignment issues within your structs; unless you explicitly align, AutoIt may adjust alignment (implicit align 8) and apply padding. Note in particular (from the Help for DllstructCreate):

Quote

The alignment of a member will be on a boundary that is either a multiple of n or a multiple of the size of the member, whichever is smaller.  (...)

If a change of alignment is needed "align" can be use[d] before the first element which that needs to be changed (...)

The alignment of the beginning of a structure is the maximum alignment of any individual member.
Each member within the structure is be placed at its proper alignment as defined in the previous table, which require implicit internal padding, depending on the previous member.

The interplay of these "rules" may yield some unexpected results (which is why I tend to align 1 explicitly). Just my two cents.

;)

Edited by RTFC

Share this post


Link to post
Share on other sites
c.haslam

RTFC,

I found a bug in GDIPlus_ImageGetPropertyItemValue(): for Case 9,10 I had accidentally left in

$tvalue = DllStructCreate('double val',$pValue)

I have removed it.

I tried adding align 1; at the start of all tags in GDIPlus_ImageGetPropertyItemValue() . This did not change the results in _ArrayDisplay().

I tried adding align 1; at the start of $tagGDIPPROPERTYITEM. This crashed with rc:-1073741819

I was had been hopeful that your suggestion would solve the problem.

GDIPlus_ImageGetPropertyItemValue() now looks like this:

; Returns:
;   byte array and undefined:   binary
;   byte scalar                 scalar
;   string                      string
;   rational                    vector: [n] numerator, [n=1] denominator
;   else                        vector
; Vectors are ref 0
Func _GDIPlus_ImageGetPropertyItemValue($iLength, $iType, $pValue)
    Static Local $tvalue
    Local $qels
If $pValue=0 Then
Return 0
EndIf
    Switch $iType
        Case 1,6,7  ; UBYTE,SBYTE,UNDEFINED
            $qels = $ilength
If $qels=1 Then
$tvalue = DllStructCreate('align 1;byte binary',$pValue)
Else
            $tvalue = DllStructCreate('align 1;byte binary['&$ilength&']',$pValue)
EndIf
        Case 2      ; ASCII
If $ilength=0 Then
Return ''
EndIf
            $qels = $ilength
            $tvalue = DllStructCreate('align 1;char str['&$iLength&']',$pValue)
        Case 3      ; USHORT
            $qels = $iLength/2
            $tvalue = DllStructCreate('align 1;ushort valVec['&$qels&']',$pValue)
        Case 4,5    ; ULONG,URATIONAL
            $qels = $iLength/4
            $tvalue = DllStructCreate('align 1;ulong valVec['&$qels&']',$pValue)
        Case 8      ; SSHORT
            $qels = $iLength/4
            $tvalue = DllStructCreate('align 1;short valVec['&$qels&']',$pValue)
        Case 9,10   ; SLONG,SRATIONAL
            $qels = $iLength/4
            $tvalue = DllStructCreate('align 1;long valVec['&$qels&']',$pValue)
        Case Else
            MsgBox(0,@ScriptLineNumber,'_GDIPlus_ImageGetPropertyItemValue(): type '&$itype& ' found')
    EndSwitch
Local $err = @error
If $err Then
    ConsoleWrite('@error '&$err&@CRLF)
    ConsoleWrite('id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype&@CRLF)
    MsgBox(0,@ScriptLineNumber,'id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype)
EndIf
    If $err Then Return SetError($err,0,-1)
    Local $ret
    Switch $itype
        Case 1,6,7  ; UBYTE,SBYTE,UNDEFINED
            Local $ret =  DllStructGetData($tvalue,'binary')
        Case 2 ; ASCII
            Local $ret = DllStructGetData($tvalue,'str')
        Case Else
            Local $ret[$qels]
            For $i = 0 To $qels-1
                $ret[$i] = DllStructGetData($tvalue,'valVec',$i+1)
            Next
    EndSwitch
If $err Then
    ConsoleWrite('@error '&$err&@CRLF)
    ConsoleWrite('GetData: id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype&@CRLF)
    MsgBox(0,@ScriptLineNumber,'id '&Hex($gId,4)&' ilength ' &$ilength&' type '&$itype)
EndIf
    Return $ret
EndFunc

Diagnostic code and most of the new code is outdented, for now.

I had been excluding property items for which the value is zero and ASCII property items for which the length is zero in the caller. These cases are now handled in this function.

For now, I am only working on the script through to the array display.

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

There are 3 possibilities for bugs:

  • In my code
  • In a DLLStruct* function
  • In Microsoft's gdip* functions

I have been working on the third possibility.

I have run the script that follows several times. Desk-checking the output to the console has convinced me, at least for now, that Microsoft's GdipGetAllPropertyItems() works consistently. Its return is as advertised, i.e. it is my Scenario 1. This does not rule out the possibility of a memory leak.

That leaves the other two possibilities. A memory leak is possible in both.

It is beyond me as to how the second script below sometimes reports an ASCII string, and sometimes doesn't.

The script used to check GdipGetAllPropertyItems() is below. It reports in the odd format because I needed to be able to find Id's if the alignment was other than 2.

#include <GDIPlus.au3>
#include <Array.au3>
Opt('MustDeclareVars',1)
#include "..\cDebug.au3"

OnAutoItExitRegister(FinishUp)

main()

Func main()
    _GDIPlus_Startup()
    Local $hImage = _GDIPlus_ImageLoadFromFile('H:\temp\AP test data\DSC00824 - Copy.jpg')
    Local $ar = _GDIPlus_ImageGetAllPropertyItemsEx($hImage)
EndFunc

Func _GDIPlus_ImageGetAllPropertyItemsEx($hImage)
    Local $iI, $iCount, $tBuffer, $pBuffer, $iBuffer, $tPropertyItem, $aPropertyItems[1][1], $aResult

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

    $iBuffer = $ar[0]
    $tBuffer = DllStructCreate("byte[" & $iBuffer & "]")
    $pBuffer = DllStructGetPtr($tBuffer)
    $iCount = $ar[1]
    $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetAllPropertyItems", "hwnd", $hImage, _
        "uint", $iBuffer, "uint", $iCount, "ptr", $pBuffer)
    If @error Then Return SetError(@error, @extended, -1)
    If $aResult[0] Then Return SetError(10, $aResult[0], False)
    ReDim $aPropertyItems[$iCount + 1][4]
    $aPropertyItems[0][0] = $iCount

    Local $byAr[$iCount*16]
    For $j = 0 To ($iCount-1)*16
        Local $t = DllStructCreate('byte;',$pBuffer+$j)
        $byAr[$j] = DllStructGetData($t,1)
    Next
    For $j = 0 To ($iCount-1)*16
        _consdebug(@ScriptLineNumber,'j,val',($j+1)&'-'&$j,Hex($byAr[$j+1],2)&Hex($byAr[$j],2))
    Next
EndFunc

Func _GDIPlus_ImageGetPropertySize($hImage)
    Local $aRet[2], $aResult

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

    $aRet[0] = $aResult[2]  ; size in bytes
    $aRet[1] = $aResult[3]  ; number of property items
    Return $aRet
EndFunc   ;==>_GDIPlus_ImageGetPropertySize

Func FinishUp()
    _GDIPlus_Shutdown()
EndFunc

There is one strange finding: as mentioned in an earlier post, $tBuffer only needs to be large enough for the 66 property items, so I tried a buffer of 66*16 bytes.  GdipGetAllPropertyItems() returned an error code!

 


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:
       
    • Sven-Seyfert
      By Sven-Seyfert
      Hi Community,

      I'm looking for a way to do a Video Overlay GUI or something like that. The idea is to create a GUI which plays a video loop (with transparency/alpha channel) in front of an other GUI. Before you asking why - because I don't believe that GDIPlus can do it out of the box. My skillset for that kind of graphical things isn't good enough to do that, but here are some specialist like @UEZ maybe who can help.

      Example alpha channel video (visualized as animated *.gif):

      I tried to do the light rays effect directly with GDIPlus, but honestly that's a bit too difficult for me. I would be very glad and grateful if there are some suggestions, ideas or recommendations.

      Code for the Video play:
       
      Example video "End.mpeg":
       
      The next challenge is that the overlay GUI should be not clickable. If I hover over the overlay area, I want to have the possibility to control the GUI or what ever, in the background. But if there is any chance to make it with GDIPlus as a Video Overlay for light rays, I would prefer that approach instead of my crazy work-around idea.

      Thanks for any suggestion - I'm grateful!
      Sven
    • tukangusil7
      By tukangusil7
      Overview
      _Security__GetTokenInformation() returns a struct containing raw bytes that represents the requested token information.
      Take for example, if _Security__GetTokenInformation()  called with  $iClass parameter is set to $TokenUser, the function returns raw bytes that represents a TOKEN_USER struct, which is defined as follows:
      typedef struct _TOKEN_USER { SID_AND_ATTRIBUTES User; } TOKEN_USER, *PTOKEN_USER; Subsequently, the SID_AND_ATTRIBUTES struct is defined as follows:
      typedef struct _SID_AND_ATTRIBUTES {   PSID  Sid;   DWORD Attributes; } SID_AND_ATTRIBUTES, *PSID_AND_ATTRIBUTES; Problems
      Since SID has variable length, I suppose that interpreting the returned bytes as SID_AND_ATTRIBUTES struct won't be easy as usual.
      Questions
      Please inspect my GetTokenInfoUser function below.
      Have I got a correct value of Attributes member of SID_AND_ATTRIBUTES struct? If I have got the correct value, is my approach efficient? #include <Security.au3> #include <WinAPIHObj.au3> #include <Array.au3> Opt("MustDeclareVars", 1) Func GetTokenInfoUser($hToken) Do ; _Security__GetTokenInformation() returns a struct containing bytes that represents the ; requested token information. Local $tRawTokenInfo = _Security__GetTokenInformation($hToken, $TokenUser) If @error Then MsgBox($MB_SYSTEMMODAL, _WinAPI_GetLastError(), "_Security__GetTokenInformation() fails.") ExitLoop EndIf Local $pRawTokenInfo = DllStructGetPtr($tRawTokenInfo) ; Since SID has variable length, I do not know how to interpret the raw bytes as SID_AND_ATTRIBUTES ; struct unless the SID length is known. Local $tagPtrSid = "align 4; PTR Sid" Local $tPtrSid = DllStructCreate($tagPtrSid, $pRawTokenInfo) Local $pSid = DllStructGetData($tPtrSid, 1) If Not _Security__IsValidSid($pSid) Then ; Just to make sure $pSid is a pointer to a valid SID MsgBox($MB_SYSTEMMODAL, "", "The SID is invalid.") ExitLoop EndIf Local $iSidBytesLen = _Security__GetLengthSid($pSid) ; The length of the binary SID, in bytes ; After the SID length is known, the raw bytes are interpreted as SID_AND_ATTRIBUTES struct Local $tagSID_AND_ATTRIBUTES = "align 4; PTR Sid; BYTE[" & $iSidBytesLen & "]; ULONG Attributes" Local $tSID_AND_ATTRIBUTES = DllStructCreate($tagSID_AND_ATTRIBUTES, $pRawTokenInfo) ; Return the results Local $avResults[2] $avResults[0] = $pSid $avResults[1] = DllStructGetData($tSID_AND_ATTRIBUTES, "Attributes") Return $avResults Until False Return SetError(1, 0, 0) EndFunc ; GetTokenInfoUser Func Main() Do Local $hToken = _Security__OpenProcessToken(_WinAPI_GetCurrentProcess(), $TOKEN_QUERY) If Not $hToken Then MsgBox($MB_SYSTEMMODAL, _WinAPI_GetLastError(), "_Security__OpenProcessToken() fails.") ExitLoop EndIf Local $avResults = GetTokenInfoUser($hToken) If @error Then ExitLoop _ArrayDisplay($avResults) ; Display the results of GetTokenInfoUser() If $hToken Then _WinAPI_CloseHandle($hToken) Return Until False If $hToken Then _WinAPI_CloseHandle($hToken) EndFunc ; Main Main() Thanks in advance.
×