Modify

Opened 17 months ago

Last modified 9 months 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 Changed 17 months ago by argumentum

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 16 months ago by mLipok (previous) (diff)

comment:2 Changed 17 months ago by Jos

  • Resolution set to No Bug
  • Status changed from new to closed

comment:3 Changed 17 months ago by Jpm

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 16 months ago by mLipok (previous) (diff)

comment:4 Changed 17 months ago by argumentum

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 Changed 17 months ago by Jpm

  • Resolution No Bug deleted
  • Status changed from closed to reopened

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

Last edited 16 months ago by mLipok (previous) (diff)

comment:6 Changed 16 months ago by mLipok

  • Description modified (diff)

comment:7 Changed 9 months ago by Jpm

  • Owner set to Jon
  • Status changed from reopened to assigned

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 9 months ago by mLipok (previous) (diff)

comment:8 Changed 9 months ago by Jpm

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 9 months ago by mLipok (previous) (diff)

Guidelines for posting comments:

  • You cannot re-open a ticket but you may still leave a comment if you have additional information to add.
  • In-depth discussions should take place on the forum.

For more information see the full version of the ticket guidelines here.

Add Comment

Modify Ticket

Action
as assigned The owner will remain Jon.
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.