GDI+ Absturz

  • Hallo Leute,
    habe mal wieder ein Problem mit GDI+ und zwar: Das Programm stürzt immer ab wenn ich auf den Button Fenster Schließen drücke.

    [autoit]

    #include <GDIPlus.au3>
    #include <GUIConstants.au3>
    #include <GUIRegion.au3>
    #include <WindowsConstants.au3>

    [/autoit][autoit][/autoit][autoit]

    $BackgroundPath = "C:\Users\Pascal\Desktop\Neuer Ordner (2)\Backgrounds\gui_background5.jpg"
    Global $GUIWidth = 500, $GUIHeight = 600, $GUIXPos = @DesktopWidth / 2 - 250, $GUIYPos = @DesktopHeight / 2 - 300
    Global $Gui = GUICreate("GDI+", $GUIWidth, $GUIHeight)
    Global $Background = _GDIPlus_ImageLoadFromFile($BackgroundPath), $Graphics = _GDIPlus_GraphicsCreateFromHWND($Gui), $BackgroundImage = _GDIPlus_GraphicsDrawImage($Graphics, $Background, 0, 0)

    [/autoit][autoit][/autoit][autoit]

    Opt("GUICloseOnESC",1)

    [/autoit][autoit][/autoit][autoit]

    HotKeySet("{F5}","Info")

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    Func Info()
    OnAutoItExitRegister("end")

    $Gui = GUICreate("GDI+", $GUIWidth, $GUIHeight, $GUIXPos, $GUIYPos, $WS_POPUP, 0)

    [/autoit][autoit][/autoit][autoit]

    _GDIPlus_Startup()

    [/autoit][autoit][/autoit][autoit]

    GUISetOnEvent(-3, "end")
    GUIRegisterMsg(0x000F,"WM_PAINT")
    GUISetState()

    [/autoit][autoit][/autoit][autoit]

    $Graphics = _GDIPlus_GraphicsCreateFromHWND($Gui)
    $Background = _GDIPlus_ImageLoadFromFile($BackgroundPath)
    $BackgroundImage = _GDIPlus_GraphicsDrawImage($Graphics, $Background, 0, 0)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($GUIWidth, $GUIHeight, $Graphics)
    $hBackbuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    $ProgEnd = GUICtrlCreateButton("Programm Beenden!", 390, 560, 100, 30)
    $WinClose = GUICtrlCreateButton("Fenster Schließen!", 390, 510, 100, 30)

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    While 1
    Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
    EndOnESC()
    Case $ProgEnd
    EndOnESC()
    Case $WinClose
    end()
    EndSwitch
    WEnd
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func end()
    _GDIPlus_ImageDispose($BackgroundImage)
    _GDIPlus_GraphicsDispose($Gui)
    _GDIPlus_Shutdown()
    Exit
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func WM_PAINT()
    $Background = _GDIPlus_ImageLoadFromFile($BackgroundPath)
    _GDIPlus_GraphicsDrawImage($Graphics, $Background, 0, 0)
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func EndOnESC()
    Exit
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    while 1

    WEnd

    [/autoit]

    Hier das Skript.

    PS: Ihr müsst das Bild durch irgend eins von euch ersetzen, damit ihr was auf der GUI seht. Und es ist beabsichtigt dass das Programm keinen Rahmen hat.

  • Erstens, deine Endlossleife am Ende des Scripts könnte ne kleine Pause vertragen (so ca. Sleep(1000)). ;) Zweitens, Erzeugst du diverse Grafiken und Images 2 mal, und dann auch noch bevor _GDIPlus_Startup aufgerufen wurde, was für die Ausführung dieser Funktionen essentiell ist. Drittens, Du verwendest GUISetOnEvent ohne den OnEvent Modus einzuschalten und benutzt dann nachher trotzdem noch GUIGetMsg :huh:. Viertens, Beim Aufräumen löschst du nur die Hälfte der erzeugten GDI+ Objekte... Fünftens, ein Programm auf 2 verschiedene Arten zu beenden und nur bei einer die im RAM angelagerten Ressourcen zu entfernen. Sechstens (das Problem das dir aufgefallen ist), du musst die Funktion GraphicsDispose auch auf ein Handle zu einem Graphics Objekt anwenden, nicht auf das Handle deiner GUI...

  • Problem aber ist wenn ich die ganzen Globals nicht hätte würde der mir beim Beenden eine Fehlermeldung geben das ich die Variablen nicht definiert hätte,weil ich die GDI+ oberfläche in ner Funktion habe die ich auch brauche , (wenn ich die Funktion wegmache , also die Oberfläche aus der Funktion nehme dann ist das fenster von anfang an da ich will aber das das Fenster auf tastendruck aufgerufen werden kann) also kann ich die Globals nicht wegmachen .

    Und was soll ich für GuiGetMsg() denn bitte einsetzen ?

    Aber ansonsten Danke

    Hier nochmal ein Bisschen Überarbeitet :

    [autoit]

    #include <GDIPlus.au3>
    #include <GUIConstants.au3>
    #include <GUIRegion.au3>
    #include <WindowsConstants.au3>

    [/autoit][autoit][/autoit][autoit]

    $BackgroundPath = "C:\Users\Pascal\Desktop\Neuer Ordner (2)\Backgrounds\gui_background5.jpg"
    Global $GUIWidth = 500, $GUIHeight = 600, $GUIXPos = @DesktopWidth / 2 - 250, $GUIYPos = @DesktopHeight / 2 - 300
    Global $Gui = GUICreate("GDI+", $GUIWidth, $GUIHeight)
    Global $Background = _GDIPlus_ImageLoadFromFile($BackgroundPath), $Graphics = _GDIPlus_GraphicsCreateFromHWND($Gui), $BackgroundImage = _GDIPlus_GraphicsDrawImage($Graphics, $Background, 0, 0)

    [/autoit][autoit][/autoit][autoit]

    Opt("GUICloseOnESC",1)
    Opt("GUIOnEventMode",1)

    [/autoit][autoit][/autoit][autoit]

    HotKeySet("{F5}","Info")

    [/autoit][autoit][/autoit][autoit]

    Func Info()
    OnAutoItExitRegister("end")

    $Gui = GUICreate("GDI+", $GUIWidth, $GUIHeight, $GUIXPos, $GUIYPos, $WS_POPUP, 0)

    [/autoit][autoit][/autoit][autoit]

    _GDIPlus_Startup()

    [/autoit][autoit][/autoit][autoit]

    GUISetOnEvent(-3, "end")
    GUIRegisterMsg(0x000F,"WM_PAINT")
    GUISetState()

    [/autoit][autoit][/autoit][autoit]

    $Graphics = _GDIPlus_GraphicsCreateFromHWND($Gui)
    $Background = _GDIPlus_ImageLoadFromFile($BackgroundPath)
    $BackgroundImage = _GDIPlus_GraphicsDrawImage($Graphics, $Background, 0, 0)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($GUIWidth, $GUIHeight, $Graphics)
    $hBackbuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    $ProgEnd = GUICtrlCreateButton("Programm Beenden!", 390, 560, 100, 30)
    $WinClose = GUICtrlCreateButton("Fenster Schließen!", 390, 510, 100, 30)

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    While 1
    Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
    EndOnESC()
    Case $ProgEnd
    EndOnESC()
    Case $WinClose
    end()
    EndSwitch
    WEnd
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func end()
    _GDIPlus_GraphicsClear($Graphics, 0xFF000000)
    _GDIPlus_ImageDispose($Background)
    _GDIPlus_GraphicsDispose($Gui)
    _GDIPlus_Shutdown()
    Exit
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func WM_PAINT()
    $Background = _GDIPlus_ImageLoadFromFile($BackgroundPath)
    _GDIPlus_GraphicsDrawImage($Graphics, $Background, 0, 0)
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func EndOnESC()
    _GDIPlus_GraphicsClear($Graphics, 0xFF000000)
    _GDIPlus_ImageDispose($Background)
    _GDIPlus_GraphicsDispose($Gui)
    _GDIPlus_Shutdown()
    Exit
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    while 1
    Sleep(1000)
    WEnd

    [/autoit]
  • Zitat

    also kann ich die Globals nicht wegmachen .


    Nein, aber eine Variable kann man auch deklarieren ohne ihr einen Wert zuzuweisen.

    Zitat

    Und was soll ich für GuiGetMsg() denn bitte einsetzen ?


    Gar nichts... Du sollst entweder GUISetOnEvent(-3, "end") entfernen, weil es nichts bewirkt. Oder das ganze auf den OnEventModus umschreiben..
    So macht dein Script genauso keinen Sinn, weil du den OnEventMode aktiviert hast, und dennoch GUIGetMsg verwendest.

    Ich würde an deiner Stelle die Vorteile von AutoItExitRegister ausnutzen, und EINE Exit Funktion machen die nichts weiter enthält als den Exit Befehl, und dann noch eine, die nichts außer den _GDIPlus_BlablaDispose Funktionen enthält. Exit in die Funktion einzubauen die beim beenden von AutoIt aufgerufen wird ist Blödsinn.
    Noch besser und einfacher ist es aber, wenn du die ganzen GDIPlus Objekte einmal am Anfang deklarierst und generierst und am Ende wieder löschst. Das laden eines Bildes, das erzeugen einer Grafik, oder einer Bitmap dauert vielleicht insgesamt ein paar Millisekunden.. Das ist Nichts, da kannst du es doch auch einfach bei jedem Scriptstart laden, unabhängig davon, ob es nun verwendet wird oder nicht. Auf den Arbeitsspeicher dürfte sich das auch so gut wie gar nicht auswirken.

  • Habe das Skript jetzt ein bisschen Überarbeitet, nur kann ich kein zweites Bild auf die Gui zeichnen, geschweige denn von dem String ... Bitte um Hilfe

    [autoit]

    #include <GDIPlus.au3>
    #include <GUIConstants.au3>
    #include <GUIRegion.au3>
    #include <WindowsConstants.au3>

    [/autoit][autoit][/autoit][autoit]

    $BackgroundPath = "C:\Users\Pascal\Desktop\Neuer Ordner (2)\Backgrounds\gui_background5.jpg"
    $LabelPath = "C:\Users\Pascal\Desktop\gui_background_label.jpg"
    $A = "A"
    $Title = "TEST "
    $Version = "3.0 Beta"
    $Eswurde = "Dein IQ Beträgt"
    $Gedrueckt = " ."
    $counterA = 0
    Global $GUIWidth = 500, $GUIHeight = 600, $GUIXPos = @DesktopWidth / 2 - 250, $GUIYPos = @DesktopHeight / 2 - 300
    Global $Gui = GUICreate("" & $Title & $Version, $GUIWidth, $GUIHeight)
    Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($Gui)

    [/autoit][autoit][/autoit][autoit]

    Opt("GUICloseOnESC",1)

    [/autoit][autoit][/autoit][autoit]

    HotKeySet("{F5}","Info")

    [/autoit][autoit][/autoit][autoit]

    Func Info()
    OnAutoItExitRegister("end")

    $Gui = GUICreate("" & $Title & $Version, $GUIWidth, $GUIHeight, $GUIXPos, $GUIYPos, $WS_POPUP, 0); Gui erstellen

    [/autoit][autoit][/autoit][autoit]

    _GDIPlus_Startup() ;GDI+ Starten
    $hGraphics = _GDIPlus_GraphicsCreateFromHWND($Gui) ;Grafik auf Gui erstellen
    $Background = _GDIPlus_ImageLoadFromFile($BackgroundPath) ;Bild laden
    $BackgroundImage = _GDIPlus_GraphicsDrawImage($hGraphics, $Background, 0, 0) ;Bild zeichnen
    $Label = _GDIPlus_ImageLoadFromFile($LabelPath) ;zweites Bild laden
    $Pic1 = _GDIPlus_GraphicsDrawImageRect($hGraphics, $Label, 10, 10, 23, 23) ;zweites Bild zeichnen (Funktioniert nicht)

    [/autoit][autoit][/autoit][autoit]

    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($GUIWidth, $GUIHeight, $hGraphics) ;Buffer
    $hBackbuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap) ;Buffer

    [/autoit][autoit][/autoit][autoit]

    GUICtrlCreatePic($LabelPath, 90, 90, 23, 23) ;selbst so kann ich das zweite Bild nicht zeichnen

    [/autoit][autoit][/autoit][autoit]

    $String = _GDIPlus_StringFormatCreate(0x0001,0) ;String erstellen
    $AText = _GDIPlus_GraphicsDrawString($hGraphics, $A, 15, 15,"Arial") ;String auf das (nicht) geladene Bild zeichnen , der auch nich klappt

    [/autoit][autoit][/autoit][autoit]

    $ProgEnd = GUICtrlCreateButton("Programm Beenden!", 380, 560, 110, 30) ;Button zum Beenden des Skripts
    $WinClose = GUICtrlCreateButton("Fenster Schließen!", 380, 510, 110, 30) ;Button zum schließen des Fensters

    [/autoit][autoit][/autoit][autoit]

    GUIRegisterMsg(0x000F,"WM_PAINT") ;Funktion für Fehlerbeseitigund beim minimieren oder
    GUISetState() ;drüber ziehen eines Fenster vom eigenen Fenster

    [/autoit][autoit][/autoit][autoit]

    While 1
    Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
    EndOnESC()
    Case $ProgEnd
    EndOnESC()
    Case $WinClose
    GUIDelete("GDI+")
    _ReduceMemory()
    EndSwitch
    WEnd
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func _ReduceMemory($i_PID = -1)
    Local $ai_Return
    If $i_PID <> -1 Then
    Local $ai_Handle = DllCall("kernel32.dll", 'int', 'OpenProcess', 'int', 0x1f0fff, 'int', False, 'int', $i_PID)
    $ai_Return = DllCall("psapi.dll", 'int', 'EmptyWorkingSet', 'long', $ai_Handle[0])
    DllCall('kernel32.dll', 'int', 'CloseHandle', 'int', $ai_Handle[0])
    Else
    $ai_Return = DllCall("psapi.dll", 'int', 'EmptyWorkingSet', 'long', -1)
    EndIf
    Return $ai_Return[0]
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func WM_PAINT()
    $Background = _GDIPlus_ImageLoadFromFile($BackgroundPath)
    $BackgroundImage = _GDIPlus_GraphicsDrawImage($hGraphics, $Background, 0, 0)
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func EndOnESC()
    _ReduceMemory()
    Exit
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    while 1
    Sleep(50)
    _ReduceMemory()
    WEnd

    [/autoit]
  • Ich hab versucht die gröbsten Fehler aus deinem Script zu beseitigen. Leider ist von deinem Script danach nichts mehr übrig gewesen.
    Hast du eigentlich die letzten Beiträge von mir gelesen? Du machst nämlich genau die selben Fehler wie vorher, mit dem kleinen Unterschied, dass dieses Mal noch viel mehr drin sind...
    Die ReduceMemory Funktion ist kein Ersatz für die Dispose Funktionen die du jetzt aus irgendeinem schwachsinnigem Grund ganz entfernt hast.
    Und sie alle 50 Millisekunden anzuwenden, wird dir auch nicht dabei helfen, dein Programm effizienter zu gestalten. Besonders nicht wenn du bei jeder WM_PAINT Message das Bild erneut in den Arbeitsspeicher lädst, obwohl es schon da ist, ohne das alte zu löschen. Das sorgt dafür, dass dein RAM mit der Zeit immer weiter vollläuft. Die GUI und die Grafik erstellst du wieder 2 mal im Script, nur wird die GUI nie sichtbar geschaltet und die Grafik nie generiert weil _GDIPlus_startup nie aufgerufen wurde.
    Dann speicherst du Rückgabewerte von Funktionen wie _GDIPlus_GraphicsDrawImage etc. in Variablen obwohl du den Rückgabewert nie brauchst und auch nicht verwendest. Die Funktionen geben nur 1 bei Erfolg und 0 bei einem Fehler zurück - mehr nicht.
    Dann erstellst du eine Bitmap und ihren Grafikkontext als Backbuffer verwendest aber keines von beidem (und gibst es natürlich auch nicht wieder frei).
    Ich weiß nicht wie groß dein Bild ist, aber wenn es so groß ist wie die GUI selbst, dann brauchst du dich nicht wundern wenn dadurch ein Button oder mehrere verdeckt werden. Schließlich zeichnest du da einfach ein Bild drüber...
    Du tust praktisch alles, um möglichst viel Arbeitsspeicher zu verpulvern den du nie wieder freigibst, und versuchst das ganze dann mit einer Funktion im Griff zu halten die für externe Programme gedacht ist, wo du das Speichermanagement nicht kontrollieren kannst.
    Wie soll ich dich denn unterstützen wenn du meine Vorschläge komplett ignorierst und nur noch mehr Fehler einbaust, ohne gleich alles für dich zu machen? :huh:

  • Hi,

    deine Pfadangaben sind übrigens auch nicht wirklich zu gebrauchen, wenn dein Programm später auch auf anderen Rechnern laufen soll.
    Du musst dann schon relative Angaben mit z.B.

    [autoit]

    @ScriptDir

    [/autoit]

    verwenden, anstelle der absoluten.

    Würde das ganze gerne auch mal testen, aber dafür fehlt mir das Include "GuiRegion.au3".

    Woher hast du das?

    Gruß stay

  • Danke für die ganzen antworten. Die Fehler die ich einbaue , sind ja nur da weil ich so gut wie keine GDI+ kenntnisse habe ... du könntest mir ja mal ein Beispiel geben wie ich ein Fenster wie hier ohne Rand habe mit nem Background und nem kleinerem bild wo ein String drauf gechrieben wird, ich bin halt im GDI+ bereich neu und kenne die ganzen Dispose/freigeben befehle nicht.

    stayawayknight ich habe das aus dem orum hier aber das kannst du raus lassen habe ich vergessen raus zu machen ...