Modify

Opened 3 years ago

Last modified 2 years ago

#3968 assigned Bug

global struct gets corrupted after GUISetState()

Reported by: argumentum Owned by: Jon
Milestone: Component: AutoIt
Version: 3.3.16.1 Severity: None
Keywords: Struct Cc:

Description (last modified by mLipok)

#include <WinAPISys.au3> ; for $tagLOGFONT ;
Global $___gt__HiDpi_WinFont, $sFont
_SystemParametersInfo_GetSystemFont()
$hGUI = GUICreate('Test', 400, 400)

GUISetState(@SW_SHOW, $hGUI) ; try the code with this and without it

ConsoleWrite("Font : Attributes: " & $___gt__HiDpi_WinFont.Attributes & @CRLF)
ConsoleWrite("Font :     Weight: " & DllStructGetData($___gt__HiDpi_WinFont, 'Weight') & @CRLF)
ConsoleWrite("Font :    Quality: " & DllStructGetData($___gt__HiDpi_WinFont, 'Quality') & @CRLF)
ConsoleWrite("Font :   FaceName: " & DllStructGetData($___gt__HiDpi_WinFont, 'FaceName') & @CRLF)
ConsoleWrite("Font :   FaceName: " & $sFont & @CRLF) ; this never changes

Func _SystemParametersInfo_GetSystemFont()
        Local $dMenuFont = Binary(RegRead('HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics', 'MenuFont'))
        ConsoleWrite($dMenuFont & @CRLF)
        Local $tLOGFONT = DllStructCreate('byte[' & BinaryLen($dMenuFont) & ']')
        DllStructSetData($tLOGFONT, 1, $dMenuFont)
        $___gt__HiDpi_WinFont = DllStructCreate($tagLOGFONT, DllStructGetPtr($tLOGFONT))
        $sFont = DllStructGetData($___gt__HiDpi_WinFont, 'FaceName')
EndFunc

While troubleshooting we discovered a bug.
The thread is at https://www.autoitscript.com/forum/topic/210637-systemparametersinfo-getsystemfont-i-made-an-ugly-bug/?do=findComment&comment=1522165

Attachments (0)

Change History (8)

comment:1 by argumentum, 3 years ago

so, the bug was in the coder.
This works as advertised:

#include <WinAPISys.au3>
#include <WinAPIsysinfoConstants.au3>

Global $___gt__HiDpi_WinFont = _SystemParametersInfo_GetSystemFont()

$hGUI = GUICreate('Test', 400, 400)
GUISetState(@SW_SHOW, $hGUI)

ConsoleWrite("Font : Attributes: " & $___gt__HiDpi_WinFont.Attributes & @CRLF)
ConsoleWrite("Font :     Weight: " & $___gt__HiDpi_WinFont.Weight & @CRLF)
ConsoleWrite("Font :    Quality: " & $___gt__HiDpi_WinFont.Quality & @CRLF)
ConsoleWrite("Font :   FaceName: " & $___gt__HiDpi_WinFont.FaceName & @CRLF)


Func _SystemParametersInfo_GetSystemFont()
    Local $tLOGFONT = DllStructCreate(StringReplace($tagLOGFONT, 'OutPrecision', 'Attributes'))
    Local $iSize = DllStructGetSize($tLOGFONT)
    Local $tNONCLIENTMETRICS = DllStructCreate("STRUCT;uint cbsize;int iBorderWidth;int iScrollWidth;int iScrollHeight;int iCaptionWidth;" & _
    "int iCaptionHeight;byte lfCaptionFont[" & $iSize & "];int iSmCaptionWidth;int iSmCaptionHeight;byte lfSmCaptionFont[" & $iSize & "];int iMenuWidth;" & _
    "int iMenuHeight;byte lfMenuFont[" & $iSize & "];byte lfStatusFont[" & $iSize & "];byte lfMessageFont[" & $iSize & "];int iPaddedBorderWidth;ENDSTRUCT")
    $tNONCLIENTMETRICS.cbsize = DllStructGetSize($tNONCLIENTMETRICS)
    If Not _WinAPI_SystemParametersInfo($SPI_GETNONCLIENTMETRICS, $tNONCLIENTMETRICS.cbsize, $tNONCLIENTMETRICS) Then Return SetError(@error, @extended, 0)
    Local $tTemp = DllStructCreate($tagLOGFONT, DllStructGetPtr($tNONCLIENTMETRICS, "lfCaptionFont"))
    With $tLOGFONT
        .Weight = $tTemp.Weight
        .FaceName = $tTemp.FaceName
        .Quality = $tTemp.Quality
        .Attributes = BitOR(($tTemp.Italic ? 2 : 0),($tTemp.Underline ? 4 : 0),($tTemp.Strikeout ? 8 : 0))
    EndWith
    Return $tLOGFONT
EndFunc

Do pardon my lack of experience if you would.

Last edited 3 years ago by mLipok (previous) (diff)

comment:2 by Jos, 3 years ago

Resolution: No Bug
Status: newclosed

comment:3 by J-Paul Mesnage, 3 years ago

In case it help the error was coming from the fact thatthe global variable was assign to a local variable
the correction is

#include <WinAPISys.au3> ; For $tagLOGFONT ;
Global $g_sFont
Global $___gt__HiDpi_WinFont= _SystemParametersInfo_GetSystemFont()

Local $hGUI = GUICreate('Test', 400, 400)

GUISetState(@SW_SHOW, $hGUI) ; try the code with this and without it

ConsoleWrite("Font : Attributes: " & $___gt__HiDpi_WinFont.Attributes & @CRLF)
ConsoleWrite("Font :     Weight: " & DllStructGetData($___gt__HiDpi_WinFont, 'Weight') & @CRLF)
ConsoleWrite("Font :    Quality: " & DllStructGetData($___gt__HiDpi_WinFont, 'Quality') & @CRLF)
ConsoleWrite("Font :   FaceName: " & DllStructGetData($___gt__HiDpi_WinFont, 'FaceName') & @CRLF)
ConsoleWrite("Font :   FaceName: " & $g_sFont & @CRLF) ; this never changes

Func _SystemParametersInfo_GetSystemFont()
        Local $dMenuFont = Binary(RegRead('HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics', 'MenuFont'))
        ConsoleWrite($dMenuFont & @CRLF)
        Local $tLOGFONT = DllStructCreate('byte[' & BinaryLen($dMenuFont) & ']')
        DllStructSetData($tLOGFONT, 1, $dMenuFont)
        Local $tTemp = DllStructCreate($tagLOGFONT, DllStructGetPtr($tLOGFONT))
        $g_sFont = DllStructGetData($___gt__HiDpi_WinFont, 'FaceName')
        Return $tTemp
EndFunc   ;==>_SystemParametersInfo_GetSystemFont

Cheers

Last edited 3 years ago by mLipok (previous) (diff)

comment:4 by argumentum, 3 years ago

hmm, I've run the correction you posted here but it does not correct the original code that is observable while running over and over again while testing.

comment:5 by J-Paul Mesnage, 3 years ago

Resolution: No Bug
Status: closedreopened

Hi
I understand that the return is erratic even If I fix the

$g_sFont = DllStructGetData($_gtHiDpi_WinFont, 'FaceName')
to
$g_sFont = DllStructGetData($tTemp, 'FaceName')
I don't understand the influence of the position of
Global $_gtHiDpi_WinFont= _SystemParametersInfo_GetSystemFont()
which is ok after the
GUISetState(@SW_SHOW, $hGUI) ; try the code with this and without it
here is the code which is erratic

#include <WinAPISys.au3> ; For $tagLOGFONT ;
Global $g_sFont
Local $___gt__HiDpi_WinFont= _SystemParametersInfo_GetSystemFont()

Local $hGUI = GUICreate('Test', 400, 400)

GUISetState(@SW_SHOW, $hGUI) ; try the code with this and without it

ConsoleWrite("Font : Attributes: " & $___gt__HiDpi_WinFont.Attributes & @CRLF)
ConsoleWrite("Font :     Weight: " & DllStructGetData($___gt__HiDpi_WinFont, 'Weight') & @CRLF)
ConsoleWrite("Font :    Quality: " & DllStructGetData($___gt__HiDpi_WinFont, 'Quality') & @CRLF)
ConsoleWrite("Font :   FaceName: " & DllStructGetData($___gt__HiDpi_WinFont, 'FaceName') & @CRLF)
ConsoleWrite("Font :   FaceName: " & $g_sFont & @CRLF) ; this never changes

Func _SystemParametersInfo_GetSystemFont()
	Local $dMenuFont = Binary(RegRead('HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics', 'MenuFont'))
	ConsoleWrite(BinaryLen($dMenuFont) & @CRLF)
	ConsoleWrite($dMenuFont & @CRLF)
	Local $tLOGFONT = DllStructCreate('byte[' & BinaryLen($dMenuFont) & ']')
	DllStructSetData($tLOGFONT, 1, $dMenuFont)
	Local $tTemp = DllStructCreate($tagLOGFONT, DllStructGetPtr($tLOGFONT))
	$g_sFont = DllStructGetData($tTemp, 'FaceName')
	Return $tTemp
EndFunc   ;==>_SystemParametersInfo_GetSystemFont

Version 0, edited 3 years ago by J-Paul Mesnage (next)

comment:6 by mLipok, 3 years ago

Description: modified (diff)

comment:7 by J-Paul Mesnage, 2 years ago

Owner: set to Jon
Status: reopenedassigned

Hi,
I reanalyse the pb and I discover That :
The local $tTemp struct is return with local info so just after the return thos info can be overrided.
I modified the _Date_Time_EncodeSystemTime() example and I get the same problem

I am not sure how a fix can be produce
I leave to Jon the final answer

#include <FontConstants.au3>
#include <WinAPIGdi.au3>
#include <WinAPIGdiDC.au3>
#include <WinAPIHObj.au3>
#include <WinAPIMisc.au3>

; Select "Arial" font to DC and retrieve $tagOUTLINETEXTMETRIC structure
Local $hDC = _WinAPI_GetDC(0)
Local $hFont = _WinAPI_CreateFont(24, 0, 0, 0, $FW_NORMAL, 0, 0, 0, $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $ANTIALIASED_QUALITY, $DEFAULT_PITCH, 'Arial')
Local $hSv = _WinAPI_SelectObject($hDC, $hFont)
Local $tOLTM = _WinAPI_GetOutlineTextMetrics($hDC)

 ; to reproduce the bad behavior
GUICreate("test")
GUISetState()

_WinAPI_SelectObject($hDC, $hSv)
_WinAPI_ReleaseDC(0, $hDC)

If IsDllStruct($tOLTM) Then
        ConsoleWrite('Family name:   ' & _otm($tOLTM, 'otmFamilyName') & @CRLF)
        ConsoleWrite('Typeface name: ' & _otm($tOLTM, 'otmFaceName') & @CRLF)
        ConsoleWrite('Style name     ' & _otm($tOLTM, 'otmStyleName') & @CRLF)
        ConsoleWrite('Full name:     ' & _otm($tOLTM, 'otmFullName') & @CRLF)
EndIf

Func _otm(ByRef $tOLTM, $sName)
        Return _WinAPI_GetString(DllStructGetPtr($tOLTM) + DllStructGetData($tOLTM, $sName))
EndFunc   ;==>_otm

Last edited 2 years ago by mLipok (previous) (diff)

comment:8 by J-Paul Mesnage, 2 years ago

Rethinking about the pb, if a Local Struct is to be return it is need that the receiving result get a copy of the local struct

There is a lot of place where a local Structure is return without any pb if the use of the return value is used right away
something must be fixed

following script show the pb

Local $tReturn = ReturnStruct()
Local $pReturn = DllStructGetPtr($tReturn) ; should not use the local location created by the Function call
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $pReturn = ' & $pReturn & @TAB & "KO should not use the local location" & @CRLF) ;### Debug Console

Func ReturnStruct()
        Local $tStruct = DllStructCreate("Byte[128]")
        Local $pStruct = DllStructGetPtr($tStruct)
        ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $pStruct = ' & $pStruct & @CRLF) ;### Debug Console

        Local $tInternal = $tStruct ; OK just use the same location
        Local $pInternal = DllStructGetPtr($tInternal)
        ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $pInternal = ' & $pInternal & @TAB & "OK just use the same location" & @CRLF) ;### Debug Console

        Return $tStruct
EndFunc

Last edited 2 years ago by mLipok (previous) (diff)

Modify Ticket

Action
as assigned The owner will remain Jon.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.