Probleme mit CreateImage und LoadImage. Nach 23 ist Schluss!

Anfängerfragen zum Programmieren mit PureBasic.
OlderCoder
Beiträge: 134
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Probleme mit CreateImage und LoadImage. Nach 23 ist Schluss!

Beitrag von OlderCoder »

Hallo allerseits,

ich bin gerade dabei, ein Programm zu schreiben, das Programmverknüpfungen verwaltet und griffbereit anbietet. Ein Klick auf ein Icon startet dann ein Programm.
Bisher hat es auch ganz passabel funktioniert.
Aber die letzte Programmerweiterung hat mir ein bisher unlösbares Problem beschehrt, bei dem ich Mühe habe, es zu beschreiben.

Ich verwende auch Symbole, die ich in ein Image lade und dann in ein anderes Image mittels DrawImage zeichne, um dieses dann mithilfe eines ImageGadgets auszugeben.
Mit Images hatte ich schon öfter seltsame Probleme, diesmal auch wieder.

Ich möchte euch jetzt nicht mit knapp 1000 Zeilen Programmcode erschlagen, deshalb poste ich das hier jetzt erst mal nicht. Das kann ich, wenn es sich nicht vermeiden lässt, immer noch tun, falls sich jemand darauf einlassen möchte.
Aber es gibt eine Stelle mitten im Programm, an der sich jetzt ein Problem zeigt.

Code: Alles auswählen

301 LoadImage(2,programmpfad$+"Bilder\"+h$+".jpg")
302 If Not IsImage(2)
303   CreateImage(2,32,32)
304 EndIf  
305 StartDrawing(ImageOutput(1))              
306   DrawImage(ImageID(2),(i-1)*(32+textflag*90)+editflag*5,(ymax-1)*32,32,32)
307 StopDrawing()
308 FreeImage(2) 
Zeile 301 Lädt ein Bild in Image 2, um es in Image 1 zu zeichen.
Die Zeilen 302-304 sollen nur dafür sorgen, dass das Image auch dann vorhanden ist, wenn das Bild nicht gefunden wurde, was aber bisher kein Problem darstellt.
Wenn ich diese 3 Zeilen weglasse, ändert sich auch nichts.
In den Zeilen 305-307 wird das eine Image in das andere gezeichnet.

Diese Zeilen werden immer dann durchlaufen, wenn ich meine-Icon-Darstellung neu ausgebe. Und das ist z.B. dann nötig, wenn ich mittels Tasten die Anordnung verändert habe.
Und das kann ich jetzt genau 23 mal hintereinander tun.
Danach fängt mein Programm entweder an zu spinnen, d.h. Icons werden gelöscht, der Desktop zeigt teilweise wirres Zeug, Sicherheitsabfrage-Requester meines Programms werden nur teilweise und zu groß dargestellt - und zwar, wenn Zeile 08 auskommentiert ist.
Wenn Zeile 08 ebenfalls verwendet wird, dann gibt es genau nach 23 Mal Durchlauf eine Fehlermeldung in Zeile 306, "Das angegebene #Image ist nicht initialisiert".
Ich hab das überprüft. Nach den 23 Mal kann weder in Zeile 301, noch in Zeile 303 das Image 2 nochmal erzeugt werden, was dann die Fehlermeldung erklärt.
Möglich, dass an ganz anderer Stelle im Programm das Problem ausgelöst wird. Das kann ich momentan nicht sagen.
Ich hatte zuerst die Zeile 308 vergessen und dann gehofft, dass diese mein Problem jetzt löst, was aber leider nicht so ist.
Mir ist völlig schleierhaft, warum das Image 23mal erzeugt werden kann, und danach nicht mehr.

Ich hoffe sehr, dass Ihr Licht in mein Dunkel bringen könnt.

Gruß
Oldercoder
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Probleme mit CreateImage und LoadImage. Nach 23 ist Schl

Beitrag von STARGÅTE »

Erst mal Willkommen im Forum.

An sich ist an deinem kleinen Code nichts falsch.
Das Problem kann nun an folgenden anderen Stellen liegen:
  • Du verwendest irgendwo anders (zB in einem Thread) auch ein Image mit der Nummer 2, was zum Konflikt führt.
  • Du überschreibt unbemerkt den Speicher des Images, zB durch ein illegales Poke() in einem Memory. Das kann man finden, wenn du den Purifier einschaltest (unter Kompileroptionen)
  • Du verwendest Threads, und hast kein Thread-Safe aktiviert.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
OlderCoder
Beiträge: 134
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Probleme mit CreateImage und LoadImage. Nach 23 ist Schl

Beitrag von OlderCoder »

Threads verwende ich nicht. Da hab ich bisher keinen blassen Schimmer von.
Poke o.ä. verwende ich ebenfalls nicht.
Ich hab parallel im Taskmanager den Speicherbedarf des Programms überprüft in der Erwartung, das dort vielleicht der Speicherbedarf auffällig ansteigt, was nicht der Fall ist.
Mir ist schon des öftern passiert, dass LoadImage zunächst einfach überhaupt nicht funktionieren will. Und plötzlich geht es dann, ohne das ich irgendetwas relevantes verändert habe. Diesen Eindruck hatte ich jedenfalls.
Kann es jetzt sein, dass ich irgendwo im Programm nochmal auf das Image 2 in einer Art und Weise zugreife, die zu diesem Problem führen könnte?
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Probleme mit CreateImage und LoadImage. Nach 23 ist Schl

Beitrag von STARGÅTE »

Wenn du wirklich keine Threads nutzt, dann existiert das Image 2 ja nur zwischen Zeile 301 und 308.
Wenn du also irgendwo anders noch mal diese Nummer benutzt, erzeugt es zumindest keine Fehler in diesem Codeausschnitt.

Du kannst ja noch mal im StartDrawing() prüfen ob, IsImage(2) erfolgreich war.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
Bisonte
Beiträge: 2468
Registriert: 01.04.2007 20:18

Re: Probleme mit CreateImage und LoadImage. Nach 23 ist Schl

Beitrag von Bisonte »

Sollte LoadImage() mal scheinbar nicht funktionieren, liegt das meist am Bildformat.

Wenn kein Imageplugin (z.B. UseJPEGDecoder() oder UsePNGDecoder() ) initialisiert wurde
kann Loadimage z.B. kein PNG oder JPG Bild laden, und gibt dann immer 0 zurück.

Um solche "wahrscheinlichen" Konflikte, wie evt. doppelt benutzte ImageNr., nehme ich Konstanten für die Bilder, die ich später brauche,
um sie z.B. in ImageGadgets zu verwenden und für temporäre Bilder #PB_Any.

so als kleines Beispiel :

Code: Alles auswählen

UseJPEGImageDecoder()

Enumeration
  #Bild_1
  #Bild_2
EndEnumeration

Procedure LoadBild(ProgrammPfad$, h$, i, TextFlag, EditFlag, yMax)
  
  Protected Bild = LoadImage(#PB_Any, ProgrammPfad$ + "Bilder\" + h$ + ".jpg")
  
  If IsImage(Bild)
    If IsImage(#Bild_1)
      If StartDrawing(ImageOutput(#Bild_1))
        DrawImage(ImageID(Bild),(i-1)*(32+textflag*90)+editflag*5,(ymax-1)*32,32,32)
        StopDrawing()  
      EndIf
    EndIf
    FreeImage(Bild)
  EndIf
  
EndProcedure
PureBasic 6.21 (Windows x86/x64) | Windows11 Pro x64 | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | GeForce RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
Benutzeravatar
Regenduft
Beiträge: 574
Registriert: 25.03.2008 15:07
Wohnort: THE LÄÄÄND!

Re: Probleme mit CreateImage und LoadImage. Nach 23 ist Schl

Beitrag von Regenduft »

Einfach mal ein paar Ideen:

Evtl. Überlauf in Zeile 306?

Code: Alles auswählen

DrawImage(ImageID(2),(i-1)*(32+textflag*90)+editflag*5,(ymax-1)*32,32,32)
Genauer

Code: Alles auswählen

(i-1)*(32+textflag*90)+editflag*5
Vielleicht einfach mal die neue Bool()-Funktion für die Flags nutzen, damit Sie definitiv nur 1 oder 0 ergeben.

Code: Alles auswählen

Bool(textflag)
Bool(editflag)
Zum Ausschließen von PB-Bugs:
Schonmal DrawAlphaImage() als Alternative zu DrawImage() ausprobiert?
Vielleicht mal 32 Bit Farbtiefe versuchen?

Eine Idee wäre noch evtl. (temporär) mal ein eigenes DrawImage() zu schreiben und einzeln die Pixel zu plotten. Plot() führt zu einem Crash bzw. einer Debuggermeldung, wenn außerhalb des Bildes geplottet wird.

Hast Du schon mal den Code auf einem anderen Rechner und/oder OS getestet? Ich hatte schon mal ganz seltsame Probleme mit dem Path-Requester und es lag am Ende an meinem verpfriemelten Windows XP.

Vielleicht sind einfach die Illuminati Schuld? 23! :wink:
PureBasic 5.73 LTE x86/x64 | Windows 7 (x64)
OlderCoder
Beiträge: 134
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Probleme mit CreateImage und LoadImage. Nach 23 ist Schl

Beitrag von OlderCoder »

STARGÅTE hat geschrieben:Wenn du wirklich keine Threads nutzt, dann existiert das Image 2 ja nur zwischen Zeile 301 und 308.
Wenn du also irgendwo anders noch mal diese Nummer benutzt, erzeugt es zumindest keine Fehler in diesem Codeausschnitt.

Du kannst ja noch mal im StartDrawing() prüfen ob, IsImage(2) erfolgreich war.
Image 2 hab ich noch woanders verwendet, aber das kann kein Problem verursacht haben, weil ich die Zeilen gar nicht durchlaufen habe. Dort hab ich sicherheitshalber jetzt eine andere Nummer verwendet, was aber wie erwartet nichts geholfen hat.
Mit IsImage(2) hatte ich herausgefunden, dass nach 23 Durchläufen das Image nicht mehr initialisiert wird.
Bisonte hat geschrieben:Sollte LoadImage() mal scheinbar nicht funktionieren, liegt das meist am Bildformat.

Wenn kein Imageplugin (z.B. UseJPEGDecoder() oder UsePNGDecoder() ) initialisiert wurde
kann Loadimage z.B. kein PNG oder JPG Bild laden, und gibt dann immer 0 zurück.

Um solche "wahrscheinlichen" Konflikte, wie evt. doppelt benutzte ImageNr., nehme ich Konstanten für die Bilder, die ich später brauche,
um sie z.B. in ImageGadgets zu verwenden und für temporäre Bilder #PB_Any.

so als kleines Beispiel...
Das Bildformat ist in jedem Durchlauf immer dasselbe, 32x32 Pixel, das dürfte nach dem 23. Mal keinen Fehler erzeugen.
Den Jpg-Dekoder hab ich natürlich initialisiert. Sonst würden die ersten 22 Durchläufe auch nicht funktionieren.
An Enumeration und #PB_Any stört mich neben der Tatsache, dass ich es von den ganzen Jahren vorher nicht gewöhnt war, dass ich die Nummern, die vergeben werden, nicht direkt sehen kann und extra abfragen muss. Aber das ist wohl auch eine Frage der Praxis.

@Regenduft:
Hab ich gerade probiert. Die errechneten Werte in Zeile 306 bewegen sich bis zum Fehler immer im gleichen Rahmen.
Ein plötzlicher Überlauf oder Zeichnen neben der Fläche sollte so nicht möglich sein.
Und damit sollte auch der Test mit dem manuellen Zeichnen mittels Plot nicht nötig sein (das wäre beim Ausgeben von Bildern auch irgendwie schwierig oder unmöglich, oder?)
Der Fehler bemängelt in der Zeile 306 auch die fehlende Initialisierung des Images 2, was vor der DrawImage-Zeile passiert.

DrawAlphaImage werde ich testen. Bei den 32 Farben muss ich herausfinden, inwieweit ich es verstehe und anwenden kann.
Aber eigentlich ist doch, wie gesagt, das Problem, dass das Image 2 plötzlich nicht mehr initialisiert werden konnte, nicht vorhanden ist. Dann müsste DrawAlphaImage auch versagen.
Auf einem anderen Rechner kann ich es mal probieren, ist nicht ganz einfach, ich komm nicht oft an das andere Gerät.

Ich habe noch eine andere Funktion außerdem Verschieben von Icons im Fenster in meinem Programm, und das ist das Löschen. Hier kann ich genau 28 Löschvorgänge vornehmen, bevor wieder genau der gleiche Fehler passiert.

Die oberen Zeilen geben nur Symbole als Kennzeichnung der verschiedenen Programmgruppen aus
Ich sollte vielleicht noch dazu sagen, dass ich zum eigentlichen Ausgeben der Icons folgende Methode verwende:

Code: Alles auswählen

SHGetFileInfo_(Pfad, #Null, @Icon, SizeOf(SHFILEINFO), #SHGFI_ICON|#SHGFI_USEFILEATTRIBUTES)
ic=Icon\hIcon
If GetIconInfo_(ic, @IconInfo)
  ImgHDC = StartDrawing(ImageOutput(1))    ; Zeichnen auf diesem Image festlegen
    DrawIconEx_(ImgHDC,(i-1)*(32+textflag*90)+editflag*5,(ymax-k)*32, ic, 32, 32, 0, 0, #DI_NORMAL)
  StopDrawing()
endif
Hab ich glaub ich aus der WinAPI-Library.
Aus dem Pfad wird das Icon geholt und dann in das Image gezeichnet.
Aber hier spielt das Image 2 keine Rolle.
Aber wer weiß, ob das nicht irgendwelche Auswirkungen hat, die ich nicht kenne.

Wer sich das antun möchte, hier jetzt doch der momentane Gesamtcode mit allen Kommentaren.
Achtung, ganz sicher vorsintflutlich gestrickt, nachlässig strukturiert. Das kann man ohne Frage sehr viel besser machen, und ich hab mich noch nie an lokale Variablen gewöhnen können, deshalb die Global-Flut am Anfang.
Und zum sofortigem Funktionieren fehlen noch ein paar Bilder sowie ein Textfile für den Anfang, kann ich nachreichen, falls gewünscht. (Hab ich unten verlinkt!)
Blöd, keine Zeilennummern. Und blöd2, der ganze Code wird auf der Seite komplett ausgebreitet. Ein kleines scrollbares Fenster hätte Euch nicht so erschlagen. Hab ich woanders schon gesehen.

Code: Alles auswählen

; Link 2.0

;{ Infos
; (hier einige Zeilen Infos entfernt)

; ### Bugs ###
; Eigenschaften verändern und dann im Linkfenster neuen Link wählen, Nein bei Save -> Eigenschaften ohne Inhalt! Weitere Links auswählen geht dann nicht mehr.
; Nach etwa 23 seitlichen Verschiebe-Aktionen Fehler in Zeile 306 Initialisierung Image 2 fehlt
; Auch beim senkrechten Tauschen un Löschen (hier 28) ist das so. 
; beim seitlichen Verschieben von Links wird das Fenster, wenn nötig, nicht verkleinert, da noch nicht überprüft wird, ob das Maximum noch gerechtfertigt ist!!!
; manchmal wird beim Editiern von Links das gesamte Linkfenster einfach nur schwarz ohne Links!!!!
; das Eigenschaften-Fenster taucht häufig im Hintergrund auf und muss erst nach vorne geholt werden
; Text- oder Word-Dateien machen eine Problemlösung notwendig: Extensions hinten merken, im System verknüpfte Programme abholen (API?) und Pfad als Parameter überg.

;}

;{ Variablen

EnableExplicit

; Variablen initialisieren
Global ic                 ; für das aktuelle Icon-Handle
Define pfad.s             ; für den aktuellen Pfad 
Global inr                ; laufende Image- und Gadget-Nr
Global ImgNr              ; Zeiger auf das Image 
Global spalten.b          ; Maximale Anzahl der Icon-Spalten im Fenster
Global reihen.b           ; Maximale Anzahl der Icon-Reihen im Fenster 
Global Dim pfade$(40,50)  ; Pfade der Links
Global Dim icon$(40,50)   ; für die Icon-Pfade; meist, aber nicht immer, identisch mit dem Link-Pfad
Global Dim namen$(40,50)  ; Bezeichnungen der Links für die zusätzliche Namensangabe
Global Dim info$(40,50)   ; Info-Zusatztext
Global Dim admin.b(40,50) ; 0= nicht als Admin starten, 1= als Admin starten
Global Dim vcd$(40,50)    ; für zusätzlichen Programmpfad, z.B. für virtuelle Datenträger, wird vorher aufgerufen
Global Dim anzspalt.b(50) ; enthält die Anzahl der belegten Links pro Spalte. Für Einfügen weiterer Links nützlich
Global datenende.b        ; wenn auf 1, dann Daten zuende
Global h.f                ; Allgemeine Hilfsvariable
Global h1.f               ; Allgemeine Hilfsvariable
Global h$                 ; Text-Zwischenspeicher
Global h2$                ; Text-Zwischenspeicher
Global h3$                ; Text-Zwischenspeicher
Global x.b                ; aktuelle Spalte
Global y.b                ; aktuelle Zeile, von unten gezählt!                 
Global tx.b               ; aktuelle Hilfs-Spalte, z.B. vom Eigenschaftsfenster für das Linkfenster
Global ty.b               ; aktuelle Hilfs-Reihe, z.B. vom Eigenschaftsfenster für das Linkfenster                 
Global xmax.b             ; maximale Anzahl Spalten
Global ymax.b             ; maximale Anzahl Reihen
Global i.w                ; Laufvariable (und andere Hilfswerte)
Global k.w                ; Laufvariable (und andere Hilfswerte) 
Global programmpfad$      ; der Pfad, indem das Programm ist, damit findet das Programm die Bilder
Global EventID.l          ; das Fenster-Event  
Global textflag.b         ; wenn auf 1, dann sind die Linktitel eingeblendet und das Fenster entsprechend breiter          
Global font.l             ; Font für die Textausgabe
Global screenbreite.w     ; Breite des Bildschirms
Global screenhoehe.w      ; Höhe des Bildschirms
Global mausx.w            ; aktuelle X-Mauskoordinate
Global mausy.w            ; aktuelle Y-Mauskoordinate
Global editflag.b         ; wenn auf 1, dann ist der Editmodus aktiv
Global aenderung.b        ; wenn auf 1, dann sind die Links verändert, ohne dass bisher gespeichert wurde  
Global aenderunge.b       ; wenn auf 1, dann sind die Eigenschaften eines Links verändert, ohne dass bisher gespeichert wurde  
Global shotbreite.w       ; Anzeigebreite des Screenshots
Global shothoehe.w        ; Anzeigehöhe des Screenshots
Global Tpfade$            ; temporäre Ersatzvariablen für die Bearbeitung im Eigenschaften-Fenster
Global Ticon$             ; "
Global Tnamen$            ; "
Global Tinfo$             ; "
Global Tadmin.b           ; "
Global Tvcd$              ; "
Global screenshotflag.b   ; auf 1, wenn für die Linkbezeichnung ein passender Screenshot gefunden wurde. Zur Zeit nicht unbedingt nötig
Global test.l             ; Testvariable z.B. für Rückgabe bei LoadImage ua. 
Global antwort.s          ; Antwort von der Sicherheitsabfrage

UseJPEGImageDecoder()

; Variablen voreinstellen
spalten=10   ; absolutes Maximum für Spalten und Reihen. Sollte später über eine ini-Datei festgelegt werden.
reihen=30
programmpfad$=GetCurrentDirectory()  ; Programmpfad holen
font = FontID(LoadFont(#PB_Any, "Arial",9))
screenbreite=GetSystemMetrics_(#SM_CXSCREEN)
screenhoehe=GetSystemMetrics_(#SM_CYSCREEN)

;}

;{ Proceduren
Procedure datenhol()
  ; # steht für nächste Spalte und Spaltenbeschriftung, Bild ist dann eine Bilddatei im beiliegenden Bildordner
  ; @ ist das Endekennzeichen. Danach ist Schluss mit den Daten

  x=0 ; Spalte erst mal auf 0, weil schon am Anfang eine Weiterschaltung ausgelöst wird
  y=0 ; Zeile erst mal auf 0, 1 entspricht der untersten Zeile, weil die Schaltflächen von unten nach oben aufgereiht werden, wird sofort wieder um 1 erhöht
      ; in dieser untersten Zeile stehen grundsätzlich immer die Spaltenbeschriftungen
      
  datenende=0
  i=0  
      
  If ReadFile(0, "daten2.txt")   ; wenn die Datei geöffnet werden konnte, setzen wir fort...
        
    While Eof(0) = 0                ; solange Dateiende nicht erreicht
      
       h$ = ReadString(0)      
       If Left(h$,1) <> ";" And h$<>""  ; wenn kein Kommentar oder Leerzeile  
         If h$="@"                     ; Wenn es das Endezeichen ist
           datenende=1                 ; Datenende auf 1 setzen. Das führt aus der Datenhol-Schleife heraus 
         ElseIf h$="#"                 ; wenn es die Kennung für die nächste Spalte ist
           x+1                         ; nächste Spalte
           y=0                         ; und Zeile wieder ganz unten wählen
         ElseIf h$="§"                 ; Kennung für vom Link-Pfad abweichenden Icon-Pfad
           y+1                         ; erst mal um eine Reihe weiterschalten. Anfangs nur auf 0
           pfade$(x,y)=ReadString(0)   ; Pfadnamen holen und auf aktueller Position ablegen, das kann bei der ersten Reihe auch die Bilddatei der Beschriftung sein
           icon$(x,y)=ReadString(0)    ; Icon-Pfad zusätzlich holen, da abweichend
           namen$(x,y)=ReadString(0)   ; Namen holen und auf aktueller Position ablegen
           info$(x,y)=ReadString(0)    ; Info-Zusatztext holen
           admin(x,y)=Val(ReadString(0)); Admin-Einstellungen holen
           vcd$(x,y)=ReadString(0)     ; Zusatz-Programmpfad holen
           anzspalt(x)+1               ; Anzahl der Links pro Spalte um eins erhöhen  
           If y>ymax                   ; wenn die aktuelle Reihe größer als die bisher maximale ist
             ymax=y                    ; dann merken
           EndIf  
         Else  
           y+1                         ; erst mal um eine Reihe weiterschalten. Anfangs nur auf 0
           pfade$(x,y)=h$              ; Pfadnamen auf aktueller Position ablegen, das kann bei der ersten Reihe auch die Bilddatei der Beschriftung sein
           icon$(x,y)=h$               ; Icon-Pfad ebenfalls auf den Link-Pfad setzen
           namen$(x,y)=ReadString(0)   ; Namen holen und auf aktueller Position ablegen
           info$(x,y)=ReadString(0)    ; Info-Zusatztext holen
           If y<>1                      ; wenn es nicht die erste Reihe ist
             admin(x,y)=Val(ReadString(0)); Admin-Einstellungen holen
             vcd$(x,y)=ReadString(0)     ; Zusatz-Programmpfad holen
           EndIf  
           anzspalt(x)+1               ; Anzahl der Links pro Spalte um eins erhöhen 
           If y>ymax                   ; wenn die aktuelle Reihe größer als die bisher maximale ist
             ymax=y                    ; dann merken
           EndIf  
         EndIf  
       EndIf
    Wend
    xmax=x                 ; Anzahl der Spalten merken
    
    ; schließen der zuvor geöffneten Datei
    CloseFile(0)
    
  Else   ;  sonst Fehlermeldung ausgeben. Programm kann eingeschränkt verwendet werden
     MessageRequester("Initialisierungsfehler","Konnte Datei daten.txt nicht öffnen!")
     End
  EndIf
  
EndProcedure  
Procedure speichern()
  
  ; Abfrage-Requester ausgeben (API)
  Define msg.MSGBOXPARAMS
  With msg
    \lpszText = @"Änderungen abspeichern (wird sonst verworfen)?"
    \lpszCaption = @"Sicherheitsfrage"
    \dwStyle = #PB_MessageRequester_YesNoCancel
  EndWith
  h=MessageBoxIndirect_(@msg)
  ; in lesbare Antwort konvertieren
  Select h
    Case #PB_MessageRequester_Yes
      antwort="ja"
    Case #PB_MessageRequester_No
      antwort="nein"
    Case #PB_MessageRequester_Cancel
      antwort="Cancel"
  EndSelect    
    
  If antwort="ja"  ; nur wenn nach Rückfrage auch gewünscht
    ; auch in Eigenschaften Änderungen?
    If aenderunge
      pfade$(x,y)=Tpfade$
      icon$(x,y)=Ticon$
      namen$(x,y)=Tnamen$
      info$(x,y)=Tinfo$
      admin(x,y)=Tadmin
      vcd$(x,y)=Tvcd$
    EndIf  
    ; Linkdaten wieder abspeichern
    If CreateFile(1,"daten2.txt")        ; falls Datei angelegt werden konnte
      For i=1 To xmax
        For k=1 To ymax
          If k=1                         ; wenn es die erste Reihe ist -> Beschriftung
            WriteStringN(1,"#")          ; Kennung für Beschriftung ausgeben
            WriteStringN(1,pfade$(i,k))  ; in diesem Fall Bildnamen abspeichern
            WriteStringN(1,namen$(i,k))  ; Bezeichnung abspeichern
            WriteStringN(1,"")           ; Leerzeile abspeichern. Geht das so?  
          ElseIf pfade$(i,k)<>""         ; wenn überhaupt dort ein Link vorhanden ist 
            If pfade$(i,k)<>icon$(i,k)   ; wenn der Icon-Pfad vom Programm-Pfad abweicht
              WriteStringN(1,"§")        ; Kennung für separaten Icon-Pfad abspeichern
              WriteStringN(1,pfade$(i,k)); Programm-Pfad abspeichern
              WriteStringN(1,icon$(i,k)) ; Icon-Pfad abspeichern
              WriteStringN(1,namen$(i,k)); Bezeichnung abspeichern
              WriteStringN(1,info$(i,k)) ; Info-Zusatztext abspeichern
              WriteStringN(1,Str(admin(i,k)))  ; Admin-Status abspeichern
              WriteStringN(1,vcd$(i,k)) ; Zusatz-Programmpfad abspeichern
            Else
              WriteStringN(1,pfade$(i,k)); Programm-Pfad abspeichern
              WriteStringN(1,namen$(i,k)); Bezeichnung abspeichern
              WriteStringN(1,info$(i,k)) ; Info-Zusatztext abspeichern
              WriteStringN(1,Str(admin(i,k)))  ; Admin-Status abspeichern
              WriteStringN(1,vcd$(i,k)) ; Zusatz-Programmpfad abspeichern
            EndIf  
            WriteStringN(1,"")           ; Leerzeile abspeichern. Geht das so?  
          EndIf
        Next k
      Next i
      WriteStringN(1,"@")                ; Ende-Kennung, kann später entfallen
      CloseFile(1)
      aenderung=0                        ; Änderungsflags zurücksetzen 
      aenderunge=0
    Else
      MessageRequester("Fehler!","Daten konnten nicht geschrieben werden!")  
    EndIf 
  EndIf  
EndProcedure  
Procedure.l CatchExeIcon(Pfad.s)
  ; Abholen des Icons aus der Datei und Übertragen in ein Image. Letzteres müsste nicht unbedingt sein, weil man das Icon-Handle, hier ic, auch direkt
  ; im ImageGadget anstelle des ImageID() verwenden könnte, aber dann kann man das Icon nicht, falls gewünscht, z.B. skalieren
  Protected Icon.SHFILEINFO,IconBr,IconHo,IconInfo.ICONINFO,ImgID,ImgHDC   ; ein paar lokale Variablen für die Procedur
  SHGetFileInfo_(Pfad, #Null, @Icon, SizeOf(SHFILEINFO), #SHGFI_ICON|#SHGFI_USEFILEATTRIBUTES) ;Abholen der Icon-Struktur der Datei. Nicht alle Parameter sind bekannt
  ic=Icon\hIcon   ; Herausfischen des Icon-Handles aus der Struktur
  If GetIconInfo_(ic, @IconInfo)  ;check Icon & get IconSize: also fals es ein Icon ist
;     IconBr = IconInfo\xHotspot * 2   ; Maße des Icons ermitteln, mal aufheben, kann ich vielleicht später noch brauchen
;     IconHo = IconInfo\yHotspot * 2
    ImgHDC = StartDrawing(ImageOutput(1))    ; Zeichnen auf diesem Image festlegen
      DrawIconEx_(ImgHDC,(i-1)*(32+textflag*90)+editflag*5,(ymax-k)*32, ic, 32, 32, 0, 0, #DI_NORMAL)   ; das Icon in das Image zeichnen
    StopDrawing()
  EndIf
EndProcedure
Procedure fenster()
  If Not OpenWindow(0,58-editflag*5,screenhoehe-ymax*32-30,xmax*(32+textflag*90)-1+editflag*10,ymax*32-1,"Link 2.0",#PB_Window_BorderLess)
    MessageRequester("Fehler!","Fenster konnte nicht geöffnet werden!")
    End
  EndIf  
  
  SmartWindowRefresh(0,1)
  
  AddKeyboardShortcut(0,#PB_Shortcut_Escape,1000)   ; Shortcut - ESC für Programmende 
  AddKeyboardShortcut(0,#PB_Shortcut_T,1001)        ; Shortcut - T für Toggle Link-Namen ein/aus 
  AddKeyboardShortcut(0,#PB_Shortcut_Space,1002)    ; Shortcut - Space für Einblenden des größeren Bildes 
  AddKeyboardShortcut(0,#PB_Shortcut_Shift | #PB_Shortcut_E,1003)  ; Shortcut - Shift+E für Editiermodus einschalten
  AddKeyboardShortcut(0,#PB_Shortcut_Delete,1004)   ; Shortcut - Entf für das Löschen von Links im Editiermodus
  AddKeyboardShortcut(0,#PB_Shortcut_H,1005)        ; Shortcut - H für Hilfe
  AddKeyboardShortcut(0,#PB_Shortcut_F1,1006)       ; Shortcut - F1 ebenfalls für Hilfe
  AddKeyboardShortcut(0,#PB_Shortcut_Up,1007)       ; Shortcut - Cursor Up für das Vertauschen von Links im Editiermodus nach oben
  AddKeyboardShortcut(0,#PB_Shortcut_Down,1008)     ; Shortcut - Cursor Down für das Vertauschen von Links im Editiermodus nach unten
  AddKeyboardShortcut(0,#PB_Shortcut_Left,1009)       ; Shortcut - Cursor Left für das Verschieben von Links im Editiermodus in die  linke Spalte
  AddKeyboardShortcut(0,#PB_Shortcut_Right,1010)     ; Shortcut - Cursor Right für das Verschieben von Links im Editiermodus in die rechte Spalte
  
EndProcedure
Procedure iconsaus()
  ImgNr=CreateImage(1,spalten*(32+textflag*90)+editflag*10,reihen*32)   ; ein Image anlegen
  StartDrawing(ImageOutput(1))                ; vorher dort in der Fensterfarbe den Hintergrund löschen (warum nötig?)
    Box(0, 0,spalten*(32+textflag*90),reihen*32, 0)
    If textflag   ; falls textflag gesetzt
      Box(0, WindowHeight(0)-31,spalten*(32+textflag*90),WindowHeight(0), $777777)
    EndIf  
    If editflag                               ; falls Editiermodus eingeschaltet
      Box(0, 0,5,reihen*32, $0000FF)          ; links und rechts rote Linien zeichnen
      Box(xmax*(32+textflag*90)+5,0,5,reihen*32, $0000FF)
    EndIf  
    StopDrawing()
  
  ; Icons ausgeben
  For i=1 To xmax
    For k=1 To ymax
      h$=pfade$(i,k)
      If pfade$(i,k)<>""  ; nur wenn auch ein Pfad im Array zu finden ist und somit dort auch ein Link vorhanden ist
        If k=1   ; wenn es sich um die unterste Reihe handelt
          LoadImage(2,programmpfad$+"Bilder\"+h$+".jpg")                          ; Beschriftungsbild einladen 
;           If Not IsImage(2)
;             CreateImage(2,32,32)
;           EndIf  
          StartDrawing(ImageOutput(1))                                            ; aktuellen Ausgabekanal auf das Ziel-Image setzen
          Debug ymax
          DrawImage(ImageID(2),(i-1)*(32+textflag*90)+editflag*5,(ymax-1)*32,32,32)                    ; Beschriftungsbild ins Gesamtimage zeichnen
          StopDrawing()
          FreeImage(2)  
        Else     ; sonst normal das Icon der Zieldatei ausgeben
          CatchExeIcon(icon$(i,k))  ; dann auch ein Icon holen und ins Image zeichnen
        EndIf  
        ; jetzt Linknamen hin, falls textflag auf 1
        If textflag
          StartDrawing(ImageOutput(1))                                            ; aktuellen Ausgabekanal auf das Ziel-Image setzen
            DrawingFont(font)
            If k=1 ; wenn in der Beschriftungsreihe, dann Hintergrundfarbe grau, sonst schwarz
              BackColor($777777)  
            Else
              BackColor(0)
            EndIf  
            DrawText((i-1)*(32+textflag*90)+33+editflag*5,(ymax-k)*32+8,namen$(i,k),$FFFFFF)
          StopDrawing()  
        EndIf  
      EndIf  
    Next k 
  Next i
  ImageGadget(1,-3,-3,spalten*32,reihen*(32+textflag*90),ImageID(1),1)  ; anschließend das fertige Image per Gadget sichtbar machen, -3, für Fensterränder weg
  If editflag                                                           ; nur wenn der Editiermodus eingeschaltet ist 
    EnableGadgetDrop(1, #PB_Drop_Files,#PB_Drag_Copy)                     ; Vorbereiten für Drag&Drop beim Editieren  
  EndIf  
EndProcedure
Procedure eigaus()
  ; Anzeigen/Ausgaben für das Eigenschaftenfenster
  
  ; Icon mittels API-Funktion aus dem Icon-Pfad extrahieren
  Protected Icon.SHFILEINFO,IconInfo.ICONINFO,ImgID,ImgHDC   ; ein paar lokale Variablen für die Procedur
  SHGetFileInfo_(Ticon$, #Null, @Icon, SizeOf(SHFILEINFO), #SHGFI_ICON|#SHGFI_USEFILEATTRIBUTES) ;Abholen der Icon-Struktur der Datei. Nicht alle Param. sind bekannt
  ic=Icon\hIcon   ; Herausfischen des Icon-Handles aus der Struktur

  
  ; Gadgets für das Eigenschaftenfenster ausgeben
  TextGadget    (10,423, 15, 50, 20,"Icon")
  ImageGadget   (11,459,  5, 32, 32,ic)
  TextGadget    (12,  5, 25,400, 20,"Programm-Pfad:")
  StringGadget  (13,  5, 42,440, 20,Tpfade$) 
  ButtonGadget  (14,455, 42, 40, 20,"...")
  TextGadget    (15,  5, 70,100, 20,"Icon-Pfad:")
  StringGadget  (16,  5, 88,440, 20,Ticon$) 
  ButtonGadget  (17,455, 88, 40, 20,"...")
  TextGadget    (18,266, 68,200, 20,"Programm-Pfad in Icon-Pfad kopieren")
  ButtonGadget  (19,455, 65, 40, 20,"")
  TextGadget    (20,  5,115,400, 20,"Link-Bezeichnung:")
  StringGadget  (21,  5,132,440, 20,Tnamen$) 
  TextGadget    (27,380,157,200, 20,"Als Admin starten")  
  CheckBoxGadget(28,470,155, 20, 20,"")
  TextGadget    (22,  5,210,200, 20,"Info-Zusatztext:")
  EditorGadget  (23,  5,230,200,110,#PB_Editor_WordWrap)
  TextGadget    (24,273,210,100, 20,"Screenshot:")
  ImageGadget   (25,273,230,240,140,ImageID(3))
  ButtonGadget  (26,  5,350, 40, 20,"Reset")
  TextGadget    (29,  5,165,200, 20,"Zusätzliches Programm vorher starten")  
  StringGadget  (30,  5,182,400, 20,Tvcd$) 
  
  
  ; Button richtig anzeigen
  h=Bool(Tpfade$=Ticon$)   ; diesen Ausdruck darf ich nicht direkt in Gadget-Befehlen verwenden, sonst Syntax Error               
  DisableGadget(19,h)      ; je nach Übereinstimmung Button und Text ausgrauen oder anzeigen
  DisableGadget(18,h)
  
  ; Checkbox richtig anzeigen
  SetGadgetState(28,admin(x,y))
  
  ; und Text im Zusatz-Text-Gadget anzeigen
  SetGadgetText(23,Tinfo$)  

  
EndProcedure
Procedure screenshotaus()
  ; zuerst das Image wieder schwarz färben
  StartDrawing(ImageOutput(3))
    Box(0,0,200,110,0)
  StopDrawing()
  If LoadImage(3,programmpfad$+"Screenshots\"+Tnamen$+".jpg")                    ; wenn großes Bild eingeladen 
    ; Bild entsprechend verkleinern (h=breite, h1=hoehe)
    i=ImageWidth(3)   ; tatsächliche Größe des Screenshots holen
    k=ImageHeight(3)
    h=200             ; Maße an die angenommene Größe im Eigenschaftenfenster (200x110) anpassen
    h1=200/i * k
    If h1>110
      h1=110
      h=110/k * i
    EndIf  
    ResizeImage(3,h,h1) ; und Imagegröße entsprechend verändern
    screenshotflag=1
  Else
    screenshotflag=0
  EndIf
EndProcedure
Procedure eigenschaften()
  ; Fenster für das Ausgeben und Ändern der Link-Eigenschaften  
    
  ; Fenster öffnen
  If Not OpenWindow(1,0,0,500,380,"Eigenschaften",#PB_Window_ScreenCentered | #PB_Window_SystemMenu)
    MessageRequester("Fehler!","Fenster konnte nicht geöffnet werden!")
    End
  EndIf  
  
  AddKeyboardShortcut(1,#PB_Shortcut_Escape,1000)   ; Shortcut - ESC für Schließen des Eigenschaften-Fensters
  AddKeyboardShortcut(1,#PB_Shortcut_F1,1006)       ; Shortcut - F1 für Hilfe, hier nicht H wegen Texteingaben
  
  ; temporäre Variablen zum Bearbeiten verwenden
  Tpfade$=pfade$(x,y)
  Ticon$=icon$(x,y)
  Tnamen$=namen$(x,y)
  Tinfo$=info$(x,y)
  Tadmin=admin(x,y)
  Tvcd$=vcd$(x,y)
  
  ; Screenshot vorbereiten, falls vorhanden
  CreateImage(3,200,110)
  screenshotaus()
  eigaus()
  SetActiveGadget(21)

  
  Repeat : Until WindowEvent() = 0  ; anfängliche Events wegräumen, gibt sonst Missverständnisse mit aenderung
  ; Warten auf Eingaben
  Repeat
    EventID = WaitWindowEvent(20)                 ; alle 20ms nach Events prüfen 
    If EventID=#PB_Event_Menu
      If EventMenu()=1000                         ; Bei Escape Eigenschaften-Fenster schließen
        If aenderunge                             ; falls noch nicht abgespeicherte Link-Änderungen existieren
          ; temporäre Variablen in die Felder zurückspeichern
          speichern()                             ; dann speichern
        EndIf  
        If antwort<>"Cancel"  ; falls kein Speicher-Abbruch mit Cancel
          If antwort="nein"  ; falls kein Speichern gewünscht
            aenderunge=0
          EndIf
          CloseWindow(1)
          UseGadgetList(WindowID(0))                ; Wieder auf die Gadgets des ersten Fensters zurückstellen, sonst gibt es einen Fehler
          ProcedureReturn
        EndIf  
      EndIf  
    ElseIf EventID=#PB_Event_Gadget               ; wenn ein Gadget-Ereignis stattgefunden hat
      Select EventGadget()
          
        Case 1 ; im ersten Fenster auf die Links geklickt, um einen anderen Link im Eigenschaftsfenster darzustellen
          If aenderunge=1                         ; wenn es Änderungen in den Eigenschaften des aktuellen Links gab
            speichern()                             ; dann speichern
            If antwort="nein"  ; falls kein Speichern gewünscht
              aenderunge=0
            EndIf
          EndIf
          
          If antwort<>"Cancel"  ; falls kein Speicher-Abbruch mit Cancel
            mausx=WindowMouseX(0)                   ; Aktuelle Mausposition im Fenster holen
            mausy=WindowMouseY(0)
            tx=mausx/(32+textflag*90)+1              ; Aktuelle Spalten und Reihen bei den Icons ausrechnen 
            ty=(WindowHeight(0)-mausy)/32+1
            If ty>1 And pfade$(x,y)<>""              ; wenn es nicht die Beschriftungsreihe ist und dort ein Link vorhanden ist
              x=tx : y=ty                            ; erst wenn sicher ist, dass man einen neuen Link darstellt, dann x und y aktualisieren
              ; temporäre Variablen zum Bearbeiten verwenden
              Tpfade$=pfade$(x,y)
              Ticon$=icon$(x,y)
              Tnamen$=namen$(x,y)
              Tinfo$=info$(x,y)
              Tadmin=admin(x,y)
              Tvcd$=vcd$(x,y)
            
              screenshotaus()   ; und Infos wieder korrekt anzeigen
              eigaus()
            EndIf       
          EndIf 
        Case 13                                   ; String-Gadget mit Programm-Pfad verändert
          h$=GetGadgetText(13)                    ; Text holen
          If h$<>"" And h$<>Tpfade$               ; Falls Text eingegeben, und zwar einen veränderten
            tpfade$=h$
            
            ; Checkbox richtig anzeigen , nicht eigaus aufrufen, sonst ist der Focus weg und der Schreibfluss unterbrochen
            h=Bool(Tpfade$=Ticon$)   ; diesen Ausdruck darf ich nicht direkt in SetGadgetState verwenden, sonst Syntax Error               
            ;SetGadgetState(19,h)             ; Häkchen setzen, wenn Iconpfad mit Programmpfad identisch ist 
            DisableGadget(19,h)
            DisableGadget(18,h)
              
            aenderunge=1
          EndIf  
        Case 14                                   ; Klick auf den Button zum Auswählen eines neuen Programm-Pfades
          h$ = OpenFileRequester("Neue Datei für das Programm wählen",Tpfade$,"*.*", 06)
          If h$<>"" And h$<>Tpfade$               ; Falls Datei ausgewählt, und zwar eine neue
            Tpfade$=h$
            Ticon$=h$
            eigaus()
            aenderunge=1
          EndIf  
        Case 16                                   ; String-Gadget mit Icon-Pfad verändert
          h$=GetGadgetText(16)                    ; Text holen
          If h$<>"" And h$<>Ticon$               ; Falls Text eingegeben, und zwar einen veränderten
            Ticon$=h$
            
            ; Checkbox richtig anzeigen , nicht eigaus aufrufen, sonst ist der Focus weg und der Schreibfluss unterbrochen
            h=Bool(Tpfade$=Ticon$)   ; diesen Ausdruck darf ich nicht direkt in Gadgetbefehlen verwenden, sonst Syntax Error               
            DisableGadget(19,h)      ; je nach Übereinstimmung Button und Text ausgrauen oder anzeigen
            DisableGadget(18,h)
            
            ; Icon mittels API-Funktion aus dem Icon-Pfad extrahieren
            Protected Icon.SHFILEINFO,IconInfo.ICONINFO,ImgID,ImgHDC   ; ein paar lokale Variablen für die Procedur
            SHGetFileInfo_(Ticon$, #Null, @Icon, SizeOf(SHFILEINFO), #SHGFI_ICON|#SHGFI_USEFILEATTRIBUTES) ;Abholen der Icon-Struktur der Datei. Nicht alle Param. sind bekannt
            ic=Icon\hIcon   ; Herausfischen des Icon-Handles aus der Struktur
            ImageGadget   (11,459,  5, 32,32,ic)
            
            aenderunge=1
          EndIf  
          
        Case 17                                   ; Klick auf den Button zum Auswählen eines neuen Icon-Pfades
          h$ = OpenFileRequester("Neue Datei für das Icon wählen",Ticon$,"*.*", 06)
          If h$<>"" And h$<>Ticon$               ; Falls Datei ausgewählt, und zwar eine neue
            Ticon$=h$
            eigaus()
            aenderunge=1
          EndIf
        Case 19                                   ; Klick auf den Button zum Kopieren des Programm-Pfads in den Icon-Pfad
          Ticon$=Tpfade$
          eigaus()
          aenderunge=1
        Case 21                                   ; Link-Bezeichnung verändert?
          Tnamen$=GetGadgetText(21)               ; neuen Namen holen
          If Tnamen$<>namen$(x,y)                 ; wenn sich die neue Link-Bezeichnung von der alten unterscheidet
            aenderunge=1
          EndIf
          ; Grundsätzlich den Screenshot nach jeder Änderung der Bezeichnung ausgeben, damit diese Darstellung immer stimmt. Hoffentlich nicht zu langsam auf
          ; langsameren Rechnern
          screenshotaus()
          ImageGadget(25,273,230,240,140,ImageID(3))
        Case 23                                   ; Zusatztext verändert?
          Tinfo$=GetGadgetText(23)                ; Text in Infotext übertragen
          If Tinfo$<>info$(x,y)                   ; nur wenn der Text auch vom gespeicherten abweicht
            aenderunge=1
          EndIf  
        Case 26                                   ; Reset aller veränderten Daten
          Tpfade$=pfade$(x,y)                     ; Werte wieder aus den Datenfeldern zurückholen
          Ticon$=icon$(x,y)
          Tnamen$=namen$(x,y)
          Tinfo$=info$(x,y)
          Tadmin=admin(x,y)
          Tvcd$=vcd$(x,y)
          screenshotflag=1
          screenshotaus()
          aenderunge=0
          eigaus()                                ; und Anzeige wieder aktualisieren
        Case 28                                   ; Admineinstellung geändert
          Tadmin=GetGadgetState(28)
          If Tadmin<>admin(x,y)                   ; nur wenn die neue Einstellung von der gespeicherten abweicht
            aenderunge=1  
          EndIf  
          admin(x,y)
        Case 30                                   ; Zusatz-Programmpfad geändert
          Tvcd$=GetGadgetText(30)
          If tvcd$<>vcd$(x,y)                   ; nur wenn der neue Pfad vom gespeicherten abweicht
            aenderunge=1  
          EndIf  
      EndSelect
    ElseIf EventID=#PB_Event_CloseWindow            ; wenn Fenster geschlossen -> zurück zum Link-Fenster
      If aenderunge                              ; falls noch nicht abgespeicherte Link-Änderungen existieren
        speichern()                              ; speichern
      EndIf  
      If antwort<>"Cancel"  ; falls kein Speicher-Abbruch mit Cancel
        If antwort="nein"  ; falls kein Speichern gewünscht
          aenderunge=0
        EndIf
        CloseWindow(1)
        UseGadgetList(WindowID(0))                 ; Wieder auf die Gadgets des ersten Fensters zurückstellen, sonst gibt es einen Fehler
        ProcedureReturn
      EndIf  
    EndIf  
  ForEver  
    ; Until EventID = #PB_Event_CloseWindow            ; wenn Fenster geschlossen -> Programmende
  
  ; Fenster schließen und zurück zum anderen Fenster
  CloseWindow(1)
EndProcedure  
Procedure zielholen()
  ; Holt den Zielpfad aus der Verknüpfung
  If ReadFile(0,h$)          ; wenn die Verknüpfung geöffnet werden konnte
    h2$=""
    While Not Eof(0)
      h3$=ReadString(0)
      ;Debug h3$
      If Mid(h3$,2,1)=":"  ; wenn an der zweiten Stelle ein Doppelpunkt steht (ob das immer funktioniert? aus dem PureBasic-Forum)
        h2$=h3$
      ElseIf Left(h3$,4)="URL="
        h2$=Mid(h3$,5)
      EndIf  
    Wend  
    CloseFile(0)
  EndIf
EndProcedure
Procedure RunAsAdmin(ProgramName$, WorkingDirectory$)
  ; von PB-Forum
  Protected shExecInfo.SHELLEXECUTEINFO
 
  With shExecInfo
    \cbSize = SizeOf(SHELLEXECUTEINFO)
    \lpVerb = @"runas"
    \lpFile = @ProgramName$
    \lpDirectory = @WorkingDirectory$
    \nShow = #SW_NORMAL
  EndWith
 
  ProcedureReturn ShellExecuteEx_(shExecInfo)
EndProcedure
Procedure linkloeschen()
  pfade$(x,y)=""                      ; einfach den Link entfernen
  icon$(x,y)=""
  namen$(x,y)=""
  admin(x,y)=0
  vcd$(x,y)=""
  If y<anzspalt(x)                    ; wenn es nicht der oberste Link ist
    For i=y+1 To anzspalt(x)          ; alle Links, die darüber liegen, nach unten verschieben
      pfade$(x,i-1)=pfade$(x,i)
      icon$(x,i-1)=icon$(x,i) 
      namen$(x,i-1)=namen$(x,i) 
      admin(x,i-1)=admin(x,i)
      vcd$(x,i-1)=vcd$(x,i)
    Next i 
    ; jetzt oberstes Feld ebenfalls löschen
    pfade$(x,anzspalt(x))=""                  
    icon$(x,anzspalt(x))=""
    namen$(x,anzspalt(x))=""
    admin(x,anzspalt(x))=0
    vcd$(x,anzspalt(x))=""
  EndIf  
  anzspalt(x)-1
EndProcedure
;}

;{ Hauptprogramm

; Fenster öffnen
datenhol()
fenster()
iconsaus()

;Warteschleife bis zum Schließen des Fensters  
Repeat
  EventID = WaitWindowEvent(20)                 ; alle 20ms nach Events prüfen 
  Select eventID  
    Case #PB_Event_Menu                         ; Falls Menü verwendet
      Select EventMenu()
          
        Case 1000                               ; Falls Escape -> Programm beenden 
          If aenderung                          ; falls noch nicht abgespeicherte Link-Änderungen existieren
            speichern()                         ; dann speichern
          EndIf  
          If antwort<>"Cancel"                  ; Wenn Sicherheitsabfrage nicht mit Cancel beendet
            End 
          EndIf  
          
        Case 1001                               ; Falls T -> Linknamen ein oder aus
          textflag=1-textflag
          CloseWindow(0)
          fenster()
          iconsaus()
          
        Case 1002 ; Falls Space -> für die Dauer von Space auf den großen Programm-Screenshot umschalten
          If editflag=0                           ; nur wenn der Editiermodus ausgeschaltet ist
            mausx=WindowMouseX(0)                 ; Aktuelle Mausposition im Fenster holen
            mausy=WindowMouseY(0)
            x=mausx/(32+textflag*90)+1            ; Aktuelle Spalten und Reihen bei den Icons ausrechnen 
            y=(WindowHeight(0)-mausy)/32+1

            If y>1                                ; Wenn es nicht die erste Reihe (Beschriftung) ist
              h$=namen$(x,y)                      ; Bezeichnung holen
              If h$<>""                           ; wenn dort eine Bezeichnung steht bzw. ein Icon vorhanden ist
                If LoadImage(4,programmpfad$+"Screenshots\"+h$+".jpg")                    ; wenn großes Bild eingeladen 

                  ; Anzeigemaße des Screenshots ermitteln , nicht größer als der Bildschirm
                  shotbreite=ImageWidth(4)
                  If shotbreite>screenbreite : shotbreite=screenbreite : EndIf
                  shothoehe=ImageHeight(4)
                  If shothoehe>screenhoehe : shothoehe=screenhoehe : EndIf
                  
                  ; neues Fenster öffnen in Größe des Screenshots
                  If Not OpenWindow(1,0,0,shotbreite,shothoehe,"Window",#PB_Window_BorderLess | #PB_Window_ScreenCentered)
                    MessageRequester("Fehler!","Fenster konnte nicht geöffnet werden!")
                    End
                  EndIf  
                  AddKeyboardShortcut(1,#PB_Shortcut_Space,1002)    ; Shortcut - Space für Einblenden des größeren Bildes 
          
                  ; Link-Titel links oben einblenden
                  StartDrawing(ImageOutput(4))
                    DrawingMode(#PB_2DDrawing_AlphaBlend)
                    Box(20,16,TextWidth(namen$(x,y))+12,26,RGBA(100,100,100,190))
                    BackColor(RGBA(100,100,100,190))
                    DrawText(26,22,namen$(x,y))
                  StopDrawing()
                  
                  ; Größeres Bild ausgeben
                  ImageGadget(100,-3,-3,shotbreite,shothoehe,ImageID(4),1)  ; anschließend das fertige Image per Gadget sichtbar machen, -3, für Fensterränder weg
                  
                  ; warten, bis Space wieder losgelassen 
                  Repeat : Until WaitWindowEvent(20)=#WM_KEYUP
          
                  x=xmax     ; Spaltenanzahl zurückholen
                  CloseWindow(1)  ; Screenshot-Fenster schließen
                  FreeImage(4)
                EndIf
              EndIf  
            EndIf
          EndIf  
          
        Case 1003 ; falls Shift+E für Edit
          editflag=1-editflag                    ; Editiermodus ein- oder ausschalten
          If editflag=0 And aenderung=1          ; falls Editiermodus beendet wurde und Änderungen bestehen
            speichern()                          ; dann speichern
            If antwort="nein"                    ; wenn das Speichern abgelehnt worden ist
              
              ; erst mal alle Arrays entfernen, damit alle Inhalte gelöscht sind
              FreeArray(pfade$())
              FreeArray(icon$())
              FreeArray(namen$())
              FreeArray(info$())
              FreeArray(admin())
              FreeArray(vcd$())
              FreeArray(anzspalt())
              ; dann wieder initialisieren
              Global Dim pfade$(40,50)
              Global Dim icon$(40,50)
              Global Dim namen$(40,50)
              Global Dim info$(40,50)
              Global Dim admin.b(40,50)
              Global Dim vcd$(40,50)
              Global Dim anzspalt.b(50)
              
              ymax=0      ; Anzahl maximale Reihen wieder zurücksetzen
              aenderung=0 ; keine Änderungen mehr 
              datenhol()  ; dann die bisherige Liste wieder einladen
              
            EndIf  
          EndIf  
          If antwort<>"Cancel"                   ; Falls nicht Abbruch des Speicherns   
            CloseWindow(0)                         ; Fensterschließen 
            fenster()                              ; angepasst wieder öffnen  
            iconsaus()                             ; und Icons wieder ausgeben
          EndIf
          
        Case 1004 ; falls Entf   
          If editflag=1                            ; nur wenn der Editiermodus eingeschaltet ist
            mausx=WindowMouseX(0)                 ; Aktuelle Mausposition im Fenster holen
            mausy=WindowMouseY(0)
            x=mausx/(32+textflag*90)+1            ; Aktuelle Spalten und Reihen bei den Icons ausrechnen 
            y=(WindowHeight(0)-mausy)/32+1
            If y>1 And pfade$(x,y)<>""            ; Wenn es nicht die erste Reihe (Beschriftung) ist und dort auch ein Link vorhanden ist
              linkloeschen()              
              aenderung=1
              ; ymax kontrollieren und evtl. verringern
              h=0 
              For i=1 To xmax  ; größte Spaltenhöhe finden
                If h<anzspalt(i) : h=anzspalt(i) : EndIf
              Next i
              If ymax>h : ymax=h : EndIf ; ymax anpassen, Beschriftungszeile unten berücksichtigen, dadurch ist ymax immer um 1 größer als anzspalt()

              CloseWindow(0)                      ; Fenster und Icons neu ausgeben 
              fenster()
              iconsaus()
            EndIf
          EndIf
        Case 1005 ; Hilfe
          RunProgram("hilfe.txt")
        Case 1006 ; ebenfalls Hilfe
          RunProgram("hilfe.txt")
        Case 1007 ; Cursor up
          If editflag=1 ; nur im Editiermodus
            mausx=WindowMouseX(0)                 ; Aktuelle Mausposition im Fenster holen
            mausy=WindowMouseY(0)
            x=mausx/(32+textflag*90)+1            ; Aktuelle Spalten und Reihen bei den Icons ausrechnen 
            y=(WindowHeight(0)-mausy)/32+1
            If y<anzspalt(x) And y>1              ; nur wenn es höchstens an zweitoberster Reihe und nicht in der ersten Reihe in der Spalte steht
              ; Vertauschen der Variablen
              Swap pfade$(x,y),pfade$(x,y+1)
              Swap icon$(x,y),icon$(x,y+1)
              Swap namen$(x,y),namen$(x,y+1)
              Swap info$(x,y),info$(x,y+1)
              Swap admin(x,y),admin(x,y+1)
              Swap vcd$(x,y),vcd$(x,y+1)
              aenderung=1                         ; Änderungsflag setzen
              FreeImage(1)
              iconsaus()                          ; Icons wieder ausgeben
            EndIf  
          EndIf  
        Case 1008 ; Cursor down
          If editflag=1 ; nur im Editiermodus
            mausx=WindowMouseX(0)                 ; Aktuelle Mausposition im Fenster holen
            mausy=WindowMouseY(0)
            x=mausx/(32+textflag*90)+1            ; Aktuelle Spalten und Reihen bei den Icons ausrechnen 
            y=(WindowHeight(0)-mausy)/32+1
            If y<=anzspalt(x) And y>2             ; nur wenn es nicht oberhalt der Links in der Reihe und nicht in unterhalb der zweiten Reihe in der Spalte steht
              ; Vertauschen der Variablen
              Swap pfade$(x,y),pfade$(x,y-1)
              Swap icon$(x,y),icon$(x,y-1)
              Swap namen$(x,y),namen$(x,y-1)
              Swap info$(x,y),info$(x,y-1)
              Swap admin(x,y),admin(x,y-1)
              Swap vcd$(x,y),vcd$(x,y-1)
              aenderung=1                         ; Änderungsflag setzen
              FreeImage(1)
              iconsaus()                          ; Icons wieder ausgeben
            EndIf  
          EndIf
        Case 1009  ; Cursor left 
          If editflag=1                           ; nur im Editiermodus
            mausx=WindowMouseX(0)                 ; Aktuelle Mausposition im Fenster holen
            mausy=WindowMouseY(0)
            x=mausx/(32+textflag*90)+1            ; Aktuelle Spalten und Reihen bei den Icons ausrechnen 
            y=(WindowHeight(0)-mausy)/32+1
              If y<=anzspalt(x) And y>1 And x>1  ; nur wenn nicht oberhalt der Links und nicht in der Beschriftungsreihe und nicht in der ersten Spalte
                If anzspalt(x-1)<reihen          ; wenn links daneben in der Spalte noch Platz ist
                  ; Link zwischenspeichern
                  Tpfade$=pfade$(x,y)
                  Ticon$=icon$(x,y)
                  Tnamen$=namen$(x,y)
                  Tinfo$=info$(x,y)
                  Tadmin=admin(x,y)
                  Tvcd$=vcd$(x,y)
                  ; dann löschen
                  linkloeschen()
                  ; dann einfügen
                  x-1
                  anzspalt(x)+1                       ; Anzahl der Links in der Spalte um eins erhöhen
                  pfade$(x,anzspalt(x))=Tpfade$       ; und Daten eintragen 
                  icon$(x,anzspalt(x))=Ticon$
                  namen$(x,anzspalt(x))=Tnamen$
                  info$(x,anzspalt(x))=Tinfo$
                  admin(x,anzspalt(x))=Tadmin
                  vcd$(x,anzspalt(x))=Tvcd$
                  If anzspalt(x)>ymax                 ; wenn die Spalte höher wird als das bisherige Maximum, dieses aktualisieren
                    ymax=anzspalt(x)
                    CloseWindow(0)
                    fenster()
                  EndIf 
                  CloseWindow(0)                      ; Fenster und Icons neu ausgeben 
                  fenster()
                  iconsaus()
                  aenderung=1                         ; vermerken, dass die Links geändert wurden
                EndIf  
              EndIf             
          EndIf   
        Case 1010  ; Cursor right
          If editflag=1                           ; nur im Editiermodus
            mausx=WindowMouseX(0)                 ; Aktuelle Mausposition im Fenster holen
            mausy=WindowMouseY(0)
            x=mausx/(32+textflag*90)+1            ; Aktuelle Spalten und Reihen bei den Icons ausrechnen 
            y=(WindowHeight(0)-mausy)/32+1
              If y<=anzspalt(x) And y>1 And x<xmax; nur wenn nicht oberhalt der Links und nicht in der Beschriftungsreihe und nicht in der letzten Spalte
                If anzspalt(x+1)<reihen          ; wenn rechts daneben in der Spalte noch Platz ist
                  ; Link zwischenspeichern
                  Tpfade$=pfade$(x,y)
                  Ticon$=icon$(x,y)
                  Tnamen$=namen$(x,y)
                  Tinfo$=info$(x,y)
                  Tadmin=admin(x,y)
                  Tvcd$=vcd$(x,y)
                  ; dann löschen
                  linkloeschen()
                  ; dann einfügen
                  x+1
                  anzspalt(x)+1                       ; Anzahl der Links in der Spalte um eins erhöhen
                  pfade$(x,anzspalt(x))=Tpfade$       ; und Daten eintragen 
                  icon$(x,anzspalt(x))=Ticon$
                  namen$(x,anzspalt(x))=Tnamen$
                  info$(x,anzspalt(x))=Tinfo$
                  admin(x,anzspalt(x))=Tadmin
                  vcd$(x,anzspalt(x))=Tvcd$
                  If anzspalt(x)>ymax                 ; wenn die Spalte höher wird als das bisherige Maximum, dieses aktualisieren
                    ymax=anzspalt(x)
                    CloseWindow(0)
                    fenster()
                  EndIf  
                  CloseWindow(0)                      ; Fenster und Icons neu ausgeben 
                  fenster()
                  iconsaus()
                  aenderung=1                         ; vermerken, dass die Links geändert wurden
                EndIf  
              EndIf             
          EndIf   
      EndSelect  
        
    Case #PB_Event_Gadget ; falls Gadget-Event. Hier wird nur von einem Mausklick ausgegangen und nicht weiter untersucht
      mausx=WindowMouseX(0)                   ; Aktuelle Mausposition im Fenster holen
      mausy=WindowMouseY(0)
      x=mausx/(32+textflag*90)+1              ; Aktuelle Spalten und Reihen bei den Icons ausrechnen 
      y=(WindowHeight(0)-mausy)/32+1
      If editflag=0                           ; nur wenn Editiermodus abgeschaltet ist. Sonst ist kein Starten von Programmen möglich  
        If y>1                                ; Wenn es nicht die erste Reihe (Beschriftung) ist
          h$=pfade$(x,y)                      ; Pfad holen
          If h$<>""                           ; wenn dort auch einer steht bzw. ein Icon vorhanden ist
            If vcd$(x,y)<>""                   ; wenn auch ein Zusatz-Programmpfad vorhanden ist
              RunProgram(vcd$(x,y),"",GetPathPart(vcd$(x,y))) ; Zusatz-Programm starten und Programm-Pfad ohne File als Arbeitsverzeichnis übergeben, kein Admin mögl.
              ; delay (100)  ; etwas warten, vielleicht unnötig
            EndIf  
            If admin(x,y)=1                   ; wenn als Admin gestartet werden soll
              RunAsAdmin(h$,GetPathPart(h$))
            Else                              ; sonst normal starten  
              RunProgram(h$,"",GetPathPart(h$)) ; Programm starten und Programm-Pfad ohne File als Arbeitsverzeichnis übergeben      
            EndIf  
            Break                             ; und Link-Programm abbrechen
          EndIf  
        Else
          ; hier kommt später die Erweiterungsseite für jede Rubrik hin  
        EndIf
      Else                                    ; wenn im Editiermodus -> Eigenschaftenfenster aufrufen zum Anzeigen und Editieren der Link-Daten
        ; zuerst Reihen und Spalten holen
        mausx=WindowMouseX(0)                 ; Aktuelle Mausposition im Fenster holen
        mausy=WindowMouseY(0)
        x=mausx/(32+textflag*90)+1            ; Aktuelle Spalten und Reihen bei den Icons ausrechnen 
        y=(WindowHeight(0)-mausy)/32+1
        If y>1 And pfade$(x,y)<>""            ; Wenn es nicht die erste Reihe (Beschriftung) ist und dort auch ein Link vorhanden ist
          eigenschaften()                       ; Eigenschaften-Fenster aufrufen zum Ansehen und Editieren
          iconsaus()
        EndIf  
      EndIf  
      
    Case #PB_Event_GadgetDrop ; Drag & Drop?
      If editflag=1                                ; nur wenn der Editiermodus eingeschaltet ist
         mausx=WindowMouseX(0)-5                   ; Aktuelle Mausposition im Fenster holen
         x=mausx/(32+textflag*90)+1                ; Aktuelle Spalten und Reihen bei den Icons ausrechnen 
         If anzspalt(x)<reihen                     ; noch Platz in der Spalte?
           If x<=xmax                              ; nicht auf rechte rote Linie geklickt (dann Index zu hoch)                            
             ; Link anlegen
             h$=EventDropFiles()                   ; zuerst Pfad zur gedroppten Datei holen
             If Right(h$,4)=".lnk" Or Right(h$,4)=".URL"              ; falls es eine Verknüpfung ist   
               zielholen()                         ; den Pfad zur verknüpften Datei holen
             EndIf  
             If h2$<>""                            ; wenn auch ein Pfad gefunden wurde   
               h$=h2$
               anzspalt(x)+1                       ; Anzahl der Links in der Spalte um eins erhöhen
               pfade$(x,anzspalt(x))=h$            ; Drag&Drop-Pfad holen und in das Feld übertragen
               icon$(x,anzspalt(x))=pfade$(x,anzspalt(x)) ; Programmpfad zunächst auch als Icon-Pfad verwenden
               If anzspalt(x)>ymax                 ; wenn die Spalte höher wird als das bisherige Maximum, dieses aktualisieren
                 ymax=anzspalt(x)
                 CloseWindow(0)
                 fenster()
               EndIf  
               iconsaus()
               aenderung=1                         ; vermerken, dass die Links geändert wurden
               y=anzspalt(x)                       ; für Eigenschaftenfenster auf neuen Link positionieren
             Else                                  ; keinen gültigen Pfad gefunden
               MessageRequester("Fehler!","Diese Verknüpfung konnte keinen gültigen Pfad zurückgeben")
             EndIf  
           EndIf
         Else                                    ; sonst Fehlermeldung ausgeben
           MessageRequester("Fehler!","Kein Platz mehr in der Spalte!")
         EndIf
      EndIf  
  EndSelect  
ForEver
;}
Folgende Dateien müssen im Programmverzeichnis vorhanden sein, damit das Programm funktioniert.
https://dl.dropbox.com/u/225053/Zubeh%C ... nk_2.0.zip
Zuletzt geändert von OlderCoder am 19.03.2013 12:08, insgesamt 2-mal geändert.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Probleme mit CreateImage und LoadImage. Nach 23 ist Schl

Beitrag von ts-soft »

Abgesehen von Deinem Problem, beachte bitte, das Icon muß nach Verwendung wieder freigegeben werden:

Code: Alles auswählen

DestroyIcon_(ic)
Sonst bekommst Du Speicherleaks.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
OlderCoder
Beiträge: 134
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Probleme mit CreateImage und LoadImage. Nach 23 ist Schl

Beitrag von OlderCoder »

Oh, Hoffnung keimt auf.
Jetzt muss ich nur noch schauen, wo das genau hingehört. Danke!

hab es mal hier eingebaut:

Code: Alles auswählen

DrawIconEx_(ImgHDC,(i-1)*(32+textflag*90)+editflag*5,(ymax-k)*32, ic, 32, 32, 0, 0, #DI_NORMAL)   ; das Icon in das Image zeichnen
StopDrawing()
DestroyIcon_(ic)
Bringt leider nix! :|
OlderCoder
Beiträge: 134
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Probleme mit CreateImage und LoadImage. Nach 23 ist Schl

Beitrag von OlderCoder »

Ein paar ermittelte Werte.
Die Zahlen geben an, wie oft ich eine Funktion nutzen kann, bevor die Fehlermeldung kommt und das Programm aussteigt.
Wenn ich FreeImage(2) nicht verwende, dann kommt zum gleichen Zeitpunkt anstelle der Fehlermeldung ein Fehlverhalten des Programms wie oben beschrieben (Icons weg, Abbruchfenster wird unsichtbar...)

Funktion --- DestroyIcon_(ic) deaktiviert / aktiviert

Links vertikal tauschen (Cursor up/down) --- 23 / 60
Links löschen (Entf) --- 19 / 66
Links Spalten wechseln nach links (Cursor left) --- 17 / 45
Links Spalten wechseln nach rechts (Cursor right) --- 17 / 46

Vielleicht gibt das einem von Euch einen Hinweis, wo der Fehler liegen könnte.
Antworten