Zugriff auf Thread-Window über Hauptprozess

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
benji
Beiträge: 124
Registriert: 01.11.2006 20:23

Zugriff auf Thread-Window über Hauptprozess

Beitrag von benji »

Hallo Leute!
Ich schreibe zur Zeit einen Updater, der es erfordert, dass wärend des Window-Loops gleichzeitig die Update-Routine Dateien herunterlädt und ein paar Gadgets aktualisiert.

Was ich haben will ist folgendes:
Während des updatens soll die GUI voll funktionsfähig sein - und auch aktualisiert werden.

Aber:
Ich komme mit Threads noch nicht so klar - und immer wenn ich versuche zb die Update-Routine (die die Gadgets aktualisiert) in einen Thread auszulagern wird mir im debugger ausgegeben, dass das angegebene Gadget nicht initialisiert wurde. (vermutlich, weil Threads nen eigenen Speicherbereich bekommen?)
Und wenn ich es anders herum (Window und Loop im Thread) versuche, klappts auch nicht (bzw irgendwas mache ich falsch ;) ).

So sieht der Call zur Zeit aus:

Code: Alles auswählen

Open_main(progressbar_elements) ;--> main window

If CreateThread(@mainloop(), dummy)

Updateroutine(md5_handle) ;--> Hier greift der UpdateProzess, der auf Gadgets im Open_main zugreift
Else
MessageRequester("Fehler", "Fehler beim erstellen des Threads")
EndIf
Hoffe ihr könnt etwas mit meinen Spärlichen informationen anfangen!
Viele Grüße, benji! :)
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: Zugriff auf Thread-Window über Hauptprozess

Beitrag von ts-soft »

Erstellen, Event-Ereignisse abfragen usw. funktioniert nur in dem Thread, wo das Main-Fenster erstellt wurde!
Das einzige, was Du in Threads machen kannst, ist SetGadgetText, State usw., wobei das auch alles mit
vorsicht zu geniessen ist. Am besten machen Threads nichts mit dem Fenster und seinen Childs, sondern
melden lediglich ans MainLoop (SendMessage) das was zu tun ist.
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
Benutzeravatar
benji
Beiträge: 124
Registriert: 01.11.2006 20:23

Re: Zugriff auf Thread-Window über Hauptprozess

Beitrag von benji »

ts-soft hat geschrieben:Erstellen, Event-Ereignisse abfragen usw. funktioniert nur in dem Thread, wo das Main-Fenster erstellt wurde!
Das einzige, was Du in Threads machen kannst, ist SetGadgetText, State usw., wobei das auch alles mit
vorsicht zu geniessen ist. Am besten machen Threads nichts mit dem Fenster und seinen Childs, sondern
melden lediglich ans MainLoop (SendMessage) das was zu tun ist.
okay umgestellt, der Thread erstellt nun ein Window und hat den MainWindowLoop drin. Aber die UpdateRoutine kann vom Hauptprozess nicht auf die Gadgets zugreifen(die vom Thread erstellt wurden) - bekomme immer einen Gadget not initialized Error...
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: Zugriff auf Thread-Window über Hauptprozess

Beitrag von ts-soft »

Sag erst mal, was Du damit meinst auf die Gadgets zugreifen und besser mal einen ausführbaren Beispielcode
damit man eine Vorstellung bekommst, was Du da vorhast.

Das überprüfen mit IsGadget usw., sollte man grundsätzlich in Threads und Callbacks machen!
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
Benutzeravatar
benji
Beiträge: 124
Registriert: 01.11.2006 20:23

Re: Zugriff auf Thread-Window über Hauptprozess

Beitrag von benji »

ts-soft hat geschrieben:Sag erst mal, was Du damit meinst auf die Gadgets zugreifen und besser mal einen ausführbaren Beispielcode
damit man eine Vorstellung bekommst, was Du da vorhast.

Das überprüfen mit IsGadget usw., sollte man grundsätzlich in Threads und Callbacks machen!
Mit Zugriefen meine ich AddGadgetItem (in eine Liste, die im Thread erstellt wurde)

Da es sich um ein kommerzielles Projekt handelt poste ich nur ungern meinen source. Aber ich hoffe, dass dieser Abschnitt alles soweit klärt :)

Code: Alles auswählen

Procedure UpdateRoutine(md5handle)
Repeat
in.s = ReadString(md5handle)
If Len(in) > 1
  If FindString(in, "[", 0)
    relativepath.s = Mid(in, 2, Len(in) -2)
  Else
    md5sum.s = in
  EndIf
  
  Else
    UpdateFile(relativepath, md5sum)
    count + 1
    SetGadgetState(progress, count)
;     SetGadgetState(#progress, count)
EndIf
Until Eof(md5handle) <> 0
CloseFile(md5handle)
DeleteFile("md5")
updated = 1

;---Autostartbuttoncode---;
; If GetGadgetState(#autostart) = #PB_Checkbox_Checked
;   RunProgram("notepad.exe")
; EndIf
  


; ProcedureReturn 1
EndProcedure

Procedure Open_main(progressbar_elements)
  If OpenWindow(#main, 652, 375, 311, 201, "Notepad Launcher " + version + " Build: "+ Str(#PB_Editor_BuildCount),  #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered )
      ButtonGadget(#start, 190, 160, 110, 30, "Starten")
      GadgetToolTip(#start, "führt Notepad aus")
      CheckBoxGadget(#autostart, 70, 160, 110, 20, "automatisch Starten")
      GadgetToolTip(#autostart, "Nach dem Update Notepad automatisch ausführen")
      ProgressBarGadget(#progress, 10, 130, 290, 20, 0, progressbar_elements)
      ListViewGadget(#list, 10, 10, 290, 110)
      If autostart
        SetGadgetState(#autostart, #PB_Checkbox_Checked)
      EndIf
        

  EndIf
EndProcedure

Procedure mainloop(*dummy)
Open_main(progressbar_elements)
Repeat ; Start of the event loop
  
  Event = WaitWindowEvent() ; This line waits until an event is received from Windows
  
  WindowID = EventWindow() ; The Window where the event is generated, can be used in the gadget procedures
  
  GadgetID = EventGadget() ; Is it a gadget event?
  
  EventType = EventType() ; The event type
  
  ;You can place code here, and use the result as parameters for the procedures
  
  If Event = #PB_Event_Gadget
    
    If GadgetID = #start
      If updated
        RunMMOGrinder()
        End
        Else
        MessageRequester("Bitte warten...", "Bitte warten sie bis der Update-Vorgang beendet ist.")
        EndIf
      
    ElseIf GadgetID = #autostart
      If GetGadgetState(#autostart) = #PB_Checkbox_Checked And autostart = false
        filehandle = OpenFile(#PB_Any ,ini_file)
        If filehandle
        FileSeek(filehandle, Lof(filehandle))
          If IsEntryPresent(filehandle, "[Settings]")          
          WriteStringN(filehandle, "autostart=true")
;           SetGadgetState(#autostart, #PB_Checkbox_Checked)
          autostart = true
          Else
          WriteStringN(filehandle, "")
          WriteStringN(filehandle, "[Settings]")
          WriteStringN(filehandle, "autostart=true")
;           SetGadgetState(#autostart, #PB_Checkbox_Checked)
          autostart = true
          EndIf
          Else
          MessageRequester("Fehler", "Fehler beim Speichern, der Datei "+ini_file)
        EndIf
        CloseFile(filehandle)
        
      ElseIf GetGadgetState(#autostart) = #PB_Checkbox_Unchecked And autostart = true
      
        filehandle = OpenFile(#PB_Any ,ini_file)
        If filehandle
        FileSeek(filehandle, Lof(filehandle))
          If IsEntryPresent(filehandle, "[Settings]")          
            DeactivateEntry(filehandle, "autostart=")
          autostart = false
          EndIf
          Else
          MessageRequester("Fehler", "Fehler beim Speichern, der Datei "+ini_file)
        EndIf
        CloseFile(filehandle)

      EndIf
      
    ElseIf GadgetID = #progress
      
    ElseIf GadgetID = #list
      
    EndIf
    
  EndIf

Delay(50)
  
Until Event = #PB_Event_CloseWindow ; End of the event loop
End
EndProcedure


;-----MAIN

If CreateThread(@mainloop(), dummy)


Updateroutine(md5_handle)

Else
MessageRequester("Fehler", "Fehler beim erstellen des Threads")
EndIf
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: Zugriff auf Thread-Window über Hauptprozess

Beitrag von ts-soft »

So ist das leider nicht Testbar und hellsehen kann ich auch nicht :wink:
Das Delay(50) im MainLoop ist natürlich sehr böse, den solltest Du in jedem Falle
dort sofort entfernen.
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
Benutzeravatar
benji
Beiträge: 124
Registriert: 01.11.2006 20:23

Re: Zugriff auf Thread-Window über Hauptprozess

Beitrag von benji »

ts-soft hat geschrieben:So ist das leider nicht Testbar und hellsehen kann ich auch nicht :wink:
Das Delay(50) im MainLoop ist natürlich sehr böse, den solltest Du in jedem Falle
dort sofort entfernen.
Das hab ich gemacht.

Hum... okay... hier poste ich mal den gesamten source.... :/
Bitte vertraulich behandeln.
EDIT
Ich will haben, dass das window voll funktionsfähig ist (wie im eventloop) und von der update-procedure das Listgadget und die Processbar aktualisiert werden und danach das Programm auf eine Usereingabe wartet.
Zuletzt geändert von benji am 12.05.2010 22:23, 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: Zugriff auf Thread-Window über Hauptprozess

Beitrag von ts-soft »

Dein geheimer Code ist nicht so wichtig, eher ein ausführbarer Code, aufs minimalste gekürzt, der das Problem
aufzeigt.

Dir ist hoffentlich klar, das kurz nach dem Starten des Threads Dein Programm zuende ist?
Das kann nicht funktionieren.
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
Benutzeravatar
benji
Beiträge: 124
Registriert: 01.11.2006 20:23

Re: Zugriff auf Thread-Window über Hauptprozess

Beitrag von benji »

ts-soft hat geschrieben:Dein geheimer Code ist nicht so wichtig, eher ein ausführbarer Code, aufs minimalste gekürzt, der das Problem
aufzeigt.
das war ja nicht böse gemeint^^
ts-soft hat geschrieben:Dir ist hoffentlich klar, das kurz nach dem Starten des Threads Dein Programm zuende ist?
Das kann nicht funktionieren.
Ja ist mir klar, da kann ich ja dann wiederum den check einbauen, ob das window closed wurde.
Das Problem, dass der debugger den Error ausspuckt besteht aber leider weiterhin...
Mit geht es um die AddGadgetItem Funktion. Bei jedem call kommt die Ausgabe, dass das Gadget nicht initialisiert wurde.
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: Zugriff auf Thread-Window über Hauptprozess

Beitrag von ts-soft »

Erstmal zu Deinen "kommerziellen" Code
1. GetCurrentDirectory wird nicht immer den richtigen Pfad zurückgeben, z. B. wenn das Programm
über eine Shell gestartet wurde. Da das Programm Admin-Rechte benötigt, ist es sogar sehr wahrscheinlich,
das es über eine Shell gestartet wird, weil der Admin wird sich dafür nicht an den PC das Benutzers setzen.

2. Die Notepad-Procedure ist ja schon gemeingefährlich.

3. Ohne EnableExplicit, mal werden Variablen deklariert, mal nicht, diese 400 Zeilen sind auch für Dich in wenigen
Wochen nicht mehr nachvollziehbar.

Ich möchte ehrlich gesagt kein Kunde von Dir sein :mrgreen:
Aber egal, soll nicht mein Problem sein.

Hier der Beweis das AddGadgetItem funktioniert

Code: Alles auswählen

EnableExplicit

Global stopthread

Procedure MyAddItem(void)
  Protected value
  While  Not stopthread
    value + 1
    If IsGadget(0)
      AddGadgetItem(0, -1, Str(value))
    EndIf
    Delay(5000)
  Wend  
EndProcedure

Define thread

If OpenWindow(0, 0, 0, 270, 140, "ListViewGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ListViewGadget(0, 10, 10, 250, 120)

  thread = CreateThread(@MyAddItem(), 0)
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
  stopthread = #True
  WaitThread(thread)
EndIf

Gruß
Thomas
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
Antworten