Jump to content
Sign in to follow this  
c.haslam

DllStructCreate not allocating memory for byte array?

Recommended Posts

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

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

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

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

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

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
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

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

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
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

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

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
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By UEZ
      This project has been discontinued!
       
      Here a small tool I wrote to update my Sysinternal tools collection without the need to download always the whole package or visiting the site to check for updates. I know that there are several tools available (also some tools written in AutoIt) but here another one for the collection. It was good exercise for me to code it.
       
       
        
       
       
      Some files from the live web site cannot be downloaded although they are visible!
       
      Here the download link of the source code only: AutoIt Sysinternal Tools Synchronizer v0.99.6 build 2020-09-23 beta.7z  (1557 downloads previously)
      -=> Requires AutoIt version 3.3.13.20 or higher / tested on Win8.1 real machine and some VMs: Win7 / Vista / Win10
       
      Compiled exe only: @MediaFire
       
      Just select the Sysinternal Tools folder or create one and press the synchronize button to download the selected items. Click on AutoIt label (near to left upper corner) to open menu.
       
      Special thanks to LarsJ, Melba23 and mesale0077 for their help. 
       
      I've still some ideas to implement which are more gimmick related, so it is not finished yet...
      If you want to add your language please check out #Region Language. Thanks. 
       
      Please report any bug or if you have any suggestions.
       
      The language of the tool tip from each of the executable in the left list view were automatically created using Google translator and weren't checked for correctness.
       
      Br,
      UEZ
    • By UEZ
      Here another example to mark the desktop to get the marked region for capturing. This example is not perfect and not very fast (room for improvements).
      ;Coded by UEZ build 2020-08-07 beta ;Code cleanup up mLipok ; ;Short instruction: mark area on your desktop and press return key to capture. #include <APISysConstants.au3> #include <Array.au3> ;#include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <ScreenCapture.au3> #include <WinAPIGdi.au3> #include <WinAPISysWin.au3> #include <WindowsConstants.au3> ; enum _PROCESS_DPI_AWARENESS -> https://msdn.microsoft.com/en-us/library/windows/desktop/dn280512(v=vs.85).aspx Global Enum $DPI_AWARENESS_INVALID = -1, $PROCESS_DPI_UNAWARE = 0, $PROCESS_SYSTEM_DPI_AWARE, $PROCESS_PER_MONITOR_DPI_AWARE ;https://docs.microsoft.com/en-us/windows/desktop/hidpi/dpi-awareness-context Global Enum $Context_UnawareGdiScaled = -5, $Context_PerMonitorAwareV2, $Context_PerMonitorAware, $Context_SystemAware, $Context_Unaware _WinAPI_SetProcessDpiAwarenessContext($Context_PerMonitorAware) Global $__g_hGUI_MarkArea, $__g_hGUI_Bg, $__g_iLabel_TL, $__g_iLabel_TM, $__g_iLabel_TR, $__g_iLabel_LM, $__g_iLabel_RM, $__g_iLabel_BL, $__g_iLabel_BM, _ $__g_iLabel_BR, $__g_iOldCursor, $__g_iW, $__g_iH, $__g_iColor_ResizeDots = 0xFFFFFF, $__g_iBorder = 4, $__g_bSelectionDone = False Global $aRect = _GDIPlus_MarkScreenRegionAnimated() Global $hImage_Capture = _ScreenCapture_Capture(@TempDir & "\Test.png", $aRect[0], $aRect[1], $aRect[0] + $aRect[2] - 1, $aRect[1] + $aRect[3] - 1, False) ShellExecute(@TempDir & "\Test.png") ;_ArrayDisplay($aRect, "Marked area coordinates") Func _GDIPlus_MarkScreenRegionAnimated($bAnim = True) _GDIPlus_Startup() Local Const $hFullScreen = WinGetHandle("[TITLE:Program Manager;CLASS:Progman]") Local Const $aFullScreen = WinGetPos($hFullScreen) $__g_hGUI_Bg = GUICreate("", $aFullScreen[2], $aFullScreen[3], $aFullScreen[0], $aFullScreen[1], BitOR($WS_CLIPCHILDREN, $WS_POPUP), $WS_EX_TOPMOST) ;to avoid cursor flickering and for proper control read WinSetTrans($__g_hGUI_Bg, "", 0x01) $__g_hGUI_MarkArea = GUICreate("", 1, 1, -1, -1, $bAnim ? $WS_POPUP : BitOR($WS_POPUP, $WS_BORDER), BitOR($WS_EX_TOPMOST, $WS_EX_LAYERED), $__g_hGUI_Bg) GUISetBkColor(0xABCDEF, $__g_hGUI_MarkArea) If Not $bAnim Then $__g_iColor_ResizeDots = 0xFF0000 $__g_iLabel_TL = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;top left GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_TM = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;top mid GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_TR = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;top right GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_LM = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;left mid GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_RM = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;right mid GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_BL = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;bottom left GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_BM = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;bottom mid GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_BR = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;bottom right GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) GUISetState(@SW_SHOWNA, $__g_hGUI_Bg) GUISetState(@SW_SHOW, $__g_hGUI_MarkArea) $__g_iOldCursor = MouseGetCursor() GUISetCursor(3, 1, $__g_hGUI_Bg) GUISetCursor(3, 1, $__g_hGUI_MarkArea) _WinAPI_SetLayeredWindowAttributes($__g_hGUI_MarkArea, 0xABCDEF, 0xF0) Local $aMPos, $aPrevMPos[2] = [MouseGetPos(0) + 1, MouseGetPos(1) + 1], $iID, $aCI, $iX, $iY, $aOldWinPos, $aOldMPos, $bMoved Local $aGUIStartPos, $iKey_Exit = GUICtrlCreateButton("", $aFullScreen[0] - 10, $aFullScreen[1] - 10, 1, 1), $aAccelKeys[1][2] = [["{ENTER}", $iKey_Exit]] GUISetAccelerators($aAccelKeys, $__g_hGUI_Bg) GUISetAccelerators($aAccelKeys, $__g_hGUI_MarkArea) #forceref $bMoved Do Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $iKey_Exit If $bAnim Then GUIRegisterMsg($WM_TIMER, "") DllCall("user32.dll", "bool", "KillTimer", "hwnd", $__g_hGUI_MarkArea, "uint_ptr", $iID) GUIRegisterMsg($WM_ERASEBKGND, "") EndIf _GDIPlus_Shutdown() Local $aResult = WinGetPos($__g_hGUI_MarkArea) $aResult[2] = WinGetClientSize($__g_hGUI_MarkArea)[0] $aResult[3] = WinGetClientSize($__g_hGUI_MarkArea)[1] GUIDelete($__g_hGUI_MarkArea) GUIDelete($__g_hGUI_Bg) If Not $__g_bSelectionDone Then $aResult = 0 Return $aResult EndSwitch $aMPos = MouseGetPos() If ($aMPos[0] <> $aPrevMPos[0] Or $aMPos[1] <> $aPrevMPos[1]) And (Not $__g_bSelectionDone) Then WinMove($__g_hGUI_MarkArea, "", $aMPos[0], $aMPos[1]) $aPrevMPos = $aMPos EndIf $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) If $aCI[2] And (Not $__g_bSelectionDone) Then $aGUIStartPos = WinGetPos($__g_hGUI_MarkArea) If $bAnim Then GUIRegisterMsg($WM_ERASEBKGND, "WM_ERASEBKGND") GUIRegisterMsg($WM_TIMER, "PlayBorderAnim") $iID = DllCall("User32.dll", "uint_ptr", "SetTimer", "hwnd", $__g_hGUI_MarkArea, "uint_ptr", 1, "uint", 50, "ptr", 0)[0] EndIf While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) $aMPos = MouseGetPos() $__g_iW = Abs($aMPos[0] - $aGUIStartPos[0]) + 1 $__g_iH = Abs($aMPos[1] - $aGUIStartPos[1]) + 1 If $aMPos[0] < $aGUIStartPos[0] Then $iX = $aMPos[0] Else $iX = $aGUIStartPos[0] EndIf If $aMPos[1] < $aGUIStartPos[1] Then $iY = $aMPos[1] Else $iY = $aGUIStartPos[1] EndIf WinMove($__g_hGUI_MarkArea, "", $iX, $iY, $__g_iW, $__g_iH) UpdateCtrlPos($bAnim) WEnd $__g_bSelectionDone = True GUISetCursor(3, 1, $__g_hGUI_MarkArea) ElseIf $aCI[3] And $__g_bSelectionDone Then $aGUIStartPos = WinGetPos($__g_hGUI_MarkArea) If _WinAPI_PtInRectEx(MouseGetPos(0), MouseGetPos(1), $aGUIStartPos[0], $aGUIStartPos[1], $aGUIStartPos[0] + $aGUIStartPos[2], $aGUIStartPos[1] + $aGUIStartPos[3]) Then $aMPos = MouseGetPos() $aGUIStartPos = WinGetPos($__g_hGUI_MarkArea) While $aCI[3] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aGUIStartPos[0] - ($aMPos[0] - MouseGetPos(0)), $aGUIStartPos[1] - ($aMPos[1] - MouseGetPos(1)), $__g_iW, $__g_iH) GUISetCursor(0, 1, $__g_hGUI_Bg) GUISetCursor(0, 1, $__g_hGUI_MarkArea) WEnd GUISetCursor(3, 1, $__g_hGUI_Bg) GUISetCursor(3, 1, $__g_hGUI_MarkArea) EndIf EndIf If $__g_bSelectionDone Then $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) If @error Then ContinueLoop Switch $aCI[4] Case $__g_iLabel_TL GUISetCursor(12, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", MouseGetPos(0), MouseGetPos(1), $aOldWinPos[2] + ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3] + ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_BR GUISetCursor(12, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], $aOldWinPos[1], $aOldWinPos[2] - ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3] - ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_TR GUISetCursor(10, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], MouseGetPos(1), $aOldWinPos[2] - ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3] + ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_BL GUISetCursor(10, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", MouseGetPos(0), $aOldWinPos[1], $aOldWinPos[2] + ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3] - ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_LM GUISetCursor(13, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", MouseGetPos(0), $aOldWinPos[1], $aOldWinPos[2] + ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3]) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_RM GUISetCursor(13, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], $aOldWinPos[1], $aOldWinPos[2] - ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3]) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_TM GUISetCursor(11, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], MouseGetPos(1), $aOldWinPos[2], $aOldWinPos[3] + ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_BM GUISetCursor(11, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], $aOldWinPos[1], $aOldWinPos[2], $aOldWinPos[3] - ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case Else GUISetCursor(3, 1, $__g_hGUI_MarkArea) EndSwitch EndIf Until False EndFunc ;==>_GDIPlus_MarkScreenRegionAnimated Func UpdateCtrlPos($bAnim = True) Local Const $aGUIStartPos = WinGetPos($__g_hGUI_MarkArea) If $__g_bSelectionDone And $bAnim Then GUIRegisterMsg($WM_TIMER, "") $__g_iW = $aGUIStartPos[2] $__g_iH = $aGUIStartPos[3] ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_TL, 0, 0, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_TM, ($__g_iW - $__g_iBorder) / 2, 0, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_TR, ($__g_iW - $__g_iBorder - $__g_iBorder / 2), 0, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_LM, 0, ($__g_iH - $__g_iBorder) / 2, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_RM, ($__g_iW - $__g_iBorder - $__g_iBorder / 2), ($__g_iH - $__g_iBorder) / 2, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_BL, 0, ($__g_iH - $__g_iBorder - $__g_iBorder / 2), $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_BM, ($__g_iW - $__g_iBorder) / 2, ($__g_iH - $__g_iBorder - $__g_iBorder / 2), $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_BR, ($__g_iW - $__g_iBorder - $__g_iBorder / 2), ($__g_iH - $__g_iBorder - $__g_iBorder / 2), $__g_iBorder, $__g_iBorder) If $__g_bSelectionDone And $bAnim Then GUIRegisterMsg($WM_TIMER, "PlayBorderAnim") EndFunc ;==>UpdateCtrlPos Func PlayBorderAnim() Local $aWinPos = WinGetClientSize($__g_hGUI_MarkArea), $iW = $aWinPos[0], $iH = $aWinPos[1] Local Static $fOffset = 0 Local Const $iSize = $__g_iBorder / 2 Local Const $hDC = _WinAPI_GetDC($__g_hGUI_MarkArea) Local Const $hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local Const $hDC_backbuffer = _WinAPI_CreateCompatibleDC($hDC) Local Const $DC_obj = _WinAPI_SelectObject($hDC_backbuffer, $hHBitmap) Local Const $hCanvas = _GDIPlus_GraphicsCreateFromHDC($hDC_backbuffer) Local Const $hPen = _GDIPlus_PenCreate(0xFF0178D7, $iSize), $hPen2 = _GDIPlus_PenCreate(0xFFFFFFFF, $iSize), _ $hBrush = _GDIPlus_BrushCreateSolid(0xFF000000 + $__g_iColor_ResizeDots), $hPen3 = _GDIPlus_PenCreate(0xFF000000) _GDIPlus_PenSetDashStyle($hPen, $GDIP_DASHSTYLEDASHDOT) _GDIPlus_GraphicsClear($hCanvas, 0xFFABCDEF) ;for faster performance direct dll calls DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen2, "float", 1 + $iSize, "float", 1 + $iSize, "float", $iW - 2 * $iSize - 2, "float", $iH - 2 * $iSize - 2) DllCall($__g_hGDIPDll, "int", "GdipSetPenDashOffset", "handle", $hPen, "float", $fOffset) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen, "float", 1 + $iSize, "float", 1 + $iSize, "float", $iW - 2 * $iSize - 2, "float", $iH - 2 * $iSize - 2) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", 0, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", 0, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) / 2, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) / 2, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) - 2, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) - 2, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", 0, "float", ($iH - $__g_iBorder) / 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", 0, "float", ($iH - $__g_iBorder) / 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) - 2, "float", ($iH - $__g_iBorder) / 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) - 2, "float", ($iH - $__g_iBorder) / 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", 0, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", 0, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) / 2, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) / 2, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) - 2, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) - 2, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hDC_backbuffer, 0, 0, $SRCCOPY) $fOffset += 0.5 _GDIPlus_GraphicsDispose($hCanvas) _WinAPI_SelectObject($hDC_backbuffer, $DC_obj) _WinAPI_DeleteDC($hDC_backbuffer) _WinAPI_DeleteObject($hHBitmap) _WinAPI_ReleaseDC($__g_hGUI_MarkArea, $hDC) _GDIPlus_PenDispose($hPen) _GDIPlus_PenDispose($hPen2) _GDIPlus_PenDispose($hPen3) _GDIPlus_BrushDispose($hBrush) EndFunc ;==>PlayBorderAnim Func WM_ERASEBKGND($hWnd, $iMsgm, $wParam, $lParam) ;suppress repainting to avoid flickering but causes some other side effects #forceref $iMsgm, $wParam, $lParam, $hWnd Local Const $hBrush = _WinAPI_CreateSolidBrush(0xEFCDAB) ;BGR format ;~ _WinAPI_RedrawWindow($__g_hGUI_MarkArea, 0, 0, BitOR($RDW_NOERASE, $RDW_NOCHILDREN, $RDW_NOFRAME, $RDW_VALIDATE)) _WinAPI_SetClassLongEx($__g_hGUI_MarkArea, $GCL_HBRBACKGROUND, $hBrush) _WinAPI_DeleteObject($hBrush) Return 0 EndFunc ;==>WM_ERASEBKGND ;https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setprocessdpiawarenesscontext Func _WinAPI_SetProcessDpiAwarenessContext($DPIAwareContext = $Context_PerMonitorAware, $hGUI = 0, $iMode = 3) ;https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setprocessdpiawarenesscontext $DPIAwareContext = ($DPIAwareContext < -5) ? -5 : ($DPIAwareContext > -1) ? -1 : $DPIAwareContext $iMode = ($iMode < 1) ? 1 : ($iMode > 3) ? 3 : $iMode Switch $iMode Case 1 Local $hDC = _WinAPI_GetDC($hGUI) Local $aResult1 = DllCall("user32.dll", "ptr", "GetDpiFromDpiAwarenessContext", "ptr", $hDC) If @error Or Not IsArray($aResult1) Then Return SetError(11, 0, 0) _WinAPI_ReleaseDC(0, $hDC) Local $aResult = DllCall("user32.dll", "Bool", "SetProcessDpiAwarenessContext", "int", $aResult1[0] + $DPIAwareContext) If @error Or Not IsArray($aResult) Then Return SetError(12, 0, 0) Case 2 ;~ If Not $hGUI Then $hGUI = WinGetHandle(AutoItWinGetTitle()) Local $aResult2 = DllCall("user32.dll", "int", "GetWindowDpiAwarenessContext", "ptr", $hGUI) If @error Or Not IsArray($aResult2) Then Return SetError(21, 0, 0) Local $aResult = DllCall("user32.dll", "Bool", "SetProcessDpiAwarenessContext", "int", $aResult2[0] + $DPIAwareContext) If @error Or Not IsArray($aResult) Then Return SetError(22, 0, 0) Case 3 Local $aResult31 = DllCall("user32.dll", "ptr", "GetThreadDpiAwarenessContext") If @error Or Not IsArray($aResult31) Then Return SetError(31, 0, 0) Local $aResult32 = DllCall("user32.dll", "ptr", "GetAwarenessFromDpiAwarenessContext", "ptr", $aResult31[0]) If @error Or Not IsArray($aResult32) Then Return SetError(32, 0, 0) Local $aResult = DllCall("user32.dll", "Bool", "SetThreadDpiAwarenessContext", "int", $aResult32[0] + $DPIAwareContext) If @error Or Not IsArray($aResult) Then Return SetError(33, 0, 0) EndSwitch Return 1 EndFunc ;==>_WinAPI_SetProcessDpiAwarenessContext  
      Just press the lmb and move your mouse. When lmb is released you can adjust the size of the window by dragging the white rectangle to any direction. Rmb will move the marked area.
      Press ESC to get the coordinates of the marked region.
      If you have any improvements, please post it here.
       
      Tested on Win10 x64 only.
       
    • By ripdad
      This is a project that I have been working on for several months off and on.
      It's a simple "What You Hear" MP3 @ 320Kbps and WAV audio recorder.
      Features:
      - LoudMax, a Gain Controller and Look-Ahead Limiter
      - Auto Shut-Off after one minute of silence
      - Side-by-Side Simulated LED Meter
      - Running Time Counter
      It started off being a large project, but I eventually stripped it down to its
      bare essentials because I came to realize that it would be very difficult to
      deal with every sound card and every way a PC is set up for audio. It would
      have been a nightmare that I was not willing to go through.
      This project contains the most up-to-date BASS.dll v.2.4.15.0 - December 17, 2019.
      All BASS Dll's are 32bit. Those and the needed UDF's are included in the zip file.
      I will try to explain how it works in the next post.

      Download:
      BASS VST Recorder v1.1.zip
       
    • By Bilgus
      This is an update or derivative work of Beege 's Scrolling Line Graph UDF
      https://www.autoitscript.com/forum/topic/109599-scrolling-line-graph-udf
       
      I noticed a few issues for my use case with the UDF one being that adding a sample required updating the waveform
      High CPU usage went hand in hand with that requirement
      Another issue was just how long updating took to complete
      I've hopefully rectified that with this version
       
      There are a few changes (only 1 line per graph for instance)
      The addition of a function AddSample (uses graphics paths to speed up drawing samples on update) Gridlines are only generated once A sample finished line can be added UpdateGraph allows you to compress the discarded portion of the graph (it looks kinda cool but uses more CPU) Lower Cpu usage Uses real Control Ids - it is a label control underneath so you get click events and can display text when control is disabled Example (Waveform.au3)
       
      Example 2 (peak.au3)
      UDF
      Updated:
      Previous Downloads [38 / 38/ 0]
      SSLG.au3 waveform.au3 Peak.au3
×
×
  • Create New...