Page 1 of 1

MessagRequester and Thread

Posted: Tue Apr 17, 2018 7:18 am
by loulou2522
Is-it possible to use cocoa message to simulate a a function like messageRequester in a thread ?
THanks

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 7:55 am
by wilbert
loulou2522 wrote:Is-it possible to use cocoa message to simulate a a function like messageRequester in a thread ?
THanks
Something like this ?
http://www.purebasic.fr/english/viewtop ... 86#p465186
http://www.purebasic.fr/english/viewtop ... 29#p465129
It uses the NSAlert class.

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 8:49 am
by loulou2522
Thanks but i ever try these function and the problem is always the same in thread

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 10:05 am
by mk-soft
Another way over PostEvent for all OS

Its a part from ThreadToGUI

Code: Select all

;-TOP
;
; MessageRequester aus Thread aufrufen
; mk-soft, v1.02, 16.03.2018

; -----------------------------------------------------------------------------

CompilerIf #PB_Compiler_Thread = 0
  CompilerError "Option Threadsafe aktivieren"
CompilerEndIf

Enumeration EventCustomValue #PB_Event_FirstCustomValue
  ; Nothing
EndEnumeration
  
Enumeration EventCustomValue
  #MyEvent_MessageRequester
EndEnumeration

Structure udtMessageRequester
  Signal.i
  Result.i
  Title.s
  Text.s
  Flags.i
EndStructure

Global LockMessageRequester = CreateMutex()

Procedure thMessageRequester(Title.s, Text.s, Flags=0)
  Protected *data.udtMessageRequester, result.i
  With *data
    *data = AllocateStructure(udtMessageRequester)
    If *data
      \Signal = CreateSemaphore()
      \Title = Title
      \Text = Text
      \Flags = Flags
      LockMutex(LockMessageRequester)
      PostEvent(#MyEvent_MessageRequester, 0, 0, 0, *data)
      WaitSemaphore(\Signal)
      UnlockMutex(LockMessageRequester)
      FreeSemaphore(\Signal)
      result = \Result
      FreeStructure(*data)
      ProcedureReturn result
    Else
      ProcedureReturn -1 ; Out Of Memory
    EndIf
  EndWith
EndProcedure

Procedure DispatchMessageRequester()
  Protected *data.udtMessageRequester
  With *data
    *data = EventData()
    If *data
      \Result = MessageRequester(\Title, \Text, \Flags)
      SignalSemaphore(\Signal)
    EndIf
  EndWith
EndProcedure

BindEvent(#MyEvent_MessageRequester, @DispatchMessageRequester())

; -----------------------------------------------------------------------------

CompilerIf #PB_Compiler_IsMainFile
  
  Procedure thMessage(Nummer)
    Protected r1
    Repeat
      Delay(1000)
      r1 = thMessageRequester("Frage", "Thread Nummer " + Nummer +  " beenden?", #PB_MessageRequester_YesNo | #PB_MessageRequester_Info)
    Until r1 = #PB_MessageRequester_Yes
  EndProcedure
  
  If OpenWindow(0, #PB_Ignore, #PB_Ignore, 200, 80, "Thread Test")
    CreateThread(@thMessage(), 1)
    CreateThread(@thMessage(), 2)
    CreateThread(@thMessage(), 3)
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          Break
      EndSelect
    ForEver
  EndIf
  
CompilerEndIf

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 1:23 pm
by loulou2522
Thanks MKsoft
IN fact here is what I want to do

Code: Select all

Procedure MyThread(msDelay.i)
  ;===============================
  Repeat
    Delay(msDelay)
    UniKey_User_Logoff(@handle)    
    retcode.l = UniKey_Find (@Handle, @p1, @p2) 
    
    If FormatNumber(retcode,0) = "200"
    ;MessageRequesterEx("Icon demo 4", "Requester with stop icon", "'stop'")
  ;MessageRequester("Conversion Fichier Suisse","Dongle de protection non trouvé"+#LF$+"Veuillez le reconnecter"+#LF$+"Puis relancer le programme",#PB_MessageRequester_Ok|#PB_MessageRequester_Error )
      UniKey_User_Logoff(@handle)
      End    
    Else 
      UniKey_User_Logoff(@handle)  
      retcode.l = UniKey_Find (@Handle, @p1, @p2) 
      If retcode = 0
        retcode = UniKey_User_Logon(@handle.w, @p11.w,@p12.w)
        Debug Str(retcode)+ "Ligne 48"
        If  retcode <> 0   
          MessageRequester("Conversion Fichier Suisse","Mot de passe du dongle erroné"+#LF$+"Veuilez revoir avec votre administrateur"+#LF$+ "Abandon programme",#PB_MessageRequester_Ok|#PB_MessageRequester_Error)
          UniKey_User_Logoff(@handle)
          End    
        EndIf
      Else 
        If retcode <> 0 
        ;MessageRequesterEx("Icon demo 4", "Requester with stop icon", "'stop'")
    
        ;  MessageRequester("Conversion Fichier Suisse","Dongle de protection non trouvé"+#LF$+"Veuillez le reconnecter"+#LF$+"Puis relancer le programme",#PB_MessageRequester_Ok|#PB_MessageRequester_Error )
          UniKey_User_Logoff(@handle)
          End 
        EndIf 
      EndIf 
    EndIf   
    ForEver
  EndProcedure
  
  Threadedun = CreateThread(@MyThread(), 3000)
It' a procedure that's verify every 3000 that'a a dongle is connected. If not I want to use Messagerequester and after quit the program

Code: Select all

 MessageRequester("Conversion Fichier Suisse","Mot de passe du dongle erroné"+#LF$+"Veuilez revoir avec votre administrateur"+#LF$+ "Abandon programme",#PB_MessageRequester_Ok|#PB_MessageRequester_Error)
          UniKey_User_Logoff(@handle)
          End    

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 1:39 pm
by mk-soft
When the program ends, the thread is also terminated.
So only works if you start a second program.

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 2:12 pm
by loulou2522
in fact I need to explain what I want to do
I launch a program with is protected by a dongle.
Every 3000 ms I test if the dongle is always connected and if not in the thread
I display a warning message and after I quit the program
With pure basic on Mac OS X the thread can't accept MessageRequester and generate an error.

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 2:25 pm
by Fred
Just post an event to your main thread and handle the event from your main event loop.

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 2:26 pm
by mk-soft
You need always a Window and an EventLoop. The window can be invisible.

Code: Select all

;-TOP
;
; MessageRequester aus Thread aufrufen
; mk-soft, v1.02, 16.03.2018

; -----------------------------------------------------------------------------

CompilerIf #PB_Compiler_Thread = 0
  CompilerError "Option Threadsafe aktivieren"
CompilerEndIf

Enumeration EventCustomValue #PB_Event_FirstCustomValue
  ; Nothing
EndEnumeration
  
Enumeration EventCustomValue
  #MyEvent_MessageRequester
EndEnumeration

Structure udtMessageRequester
  Signal.i
  Result.i
  Title.s
  Text.s
  Flags.i
EndStructure

Global LockMessageRequester = CreateMutex()

Procedure DoMessageRequester(Title.s, Text.s, Flags=0)
  Protected *data.udtMessageRequester, result.i
  With *data
    *data = AllocateStructure(udtMessageRequester)
    If *data
      \Signal = CreateSemaphore()
      \Title = Title
      \Text = Text
      \Flags = Flags
      LockMutex(LockMessageRequester)
      PostEvent(#MyEvent_MessageRequester, 0, 0, 0, *data)
      WaitSemaphore(\Signal)
      UnlockMutex(LockMessageRequester)
      FreeSemaphore(\Signal)
      result = \Result
      FreeStructure(*data)
      ProcedureReturn result
    Else
      ProcedureReturn -1 ; Out Of Memory
    EndIf
  EndWith
EndProcedure

Procedure DispatchMessageRequester()
  Protected *data.udtMessageRequester
  With *data
    *data = EventData()
    If *data
      \Result = MessageRequester(\Title, \Text, \Flags)
      SignalSemaphore(\Signal)
    EndIf
  EndWith
EndProcedure

BindEvent(#MyEvent_MessageRequester, @DispatchMessageRequester())

; -----------------------------------------------------------------------------

CompilerIf #PB_Compiler_IsMainFile
  
  Global ExitApplication
  
  Procedure thMessage(Nummer)
    Protected r1
    Repeat
      Delay(3000)
      r1 = DoMessageRequester("Frage", "Thread " + Nummer +  " exit application?", #PB_MessageRequester_YesNo | #PB_MessageRequester_Error)
    Until r1 = #PB_MessageRequester_Yes
    ExitApplication = #True
  EndProcedure
  
  If OpenWindow(0, #PB_Ignore, #PB_Ignore, 200, 80, "Hide window", #PB_Window_NoGadgets | #PB_Window_Invisible)
    CreateThread(@thMessage(), 1)
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          Break
      EndSelect
    Until ExitApplication
  EndIf
  
CompilerEndIf

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 2:51 pm
by mk-soft
Ok...

Simple example with PostEvent

Edit

Code: Select all

Global ExitApplication

Enumeration EventCustomValue #PB_Event_FirstCustomValue
  ; Nothing
EndEnumeration
  
Enumeration EventCustomValue
  #MyEvent_MissingDongle
EndEnumeration

Procedure thMessage(Nummer)
  Protected r1, dongle
  
  Repeat
    Delay(3000)
    dongle = 0
    If Not dongle
      PostEvent(#MyEvent_MissingDongle)
      Break
    EndIf
  ForEver
EndProcedure

If OpenWindow(0, #PB_Ignore, #PB_Ignore, 200, 80, "Window", #PB_Window_SystemMenu)
  CreateThread(@thMessage(), 1)
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Break
      Case #MyEvent_MissingDongle
        MessageRequester("Stop", "Missing dongle. Exit application!", #PB_MessageRequester_Ok | #PB_MessageRequester_Error)
        ExitApplication = #True
    EndSelect
  Until ExitApplication
EndIf

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 2:58 pm
by Fred
Perfect way to do that @mk-soft

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 3:22 pm
by TI-994A
As Fred had mentioned, and according to mk-soft's code, this example demonstrates how to throw different messages without posting separate events for each:

Code: Select all

#msgBoxEvent = #PB_Event_FirstCustomValue

Procedure MyThread(msDelay.i)
;===============================
  Repeat
    Delay(msDelay)
    UniKey_User_Logoff(@handle)    
    retcode.l = UniKey_Find (@Handle, @p1, @p2) 
    
    If FormatNumber(retcode,0) = "200"
      PostEvent(#msgBoxEvent, 0, 0, 0, 1)
      UniKey_User_Logoff(@handle)
      End    
    Else 
      UniKey_User_Logoff(@handle)  
      retcode.l = UniKey_Find (@Handle, @p1, @p2) 
      If retcode = 0
        retcode = UniKey_User_Logon(@handle.w, @p11.w,@p12.w)
        Debug Str(retcode) + "Ligne 48"        
        If  retcode <> 0   
          PostEvent(#msgBoxEvent, 0, 0, 0, 2)
          UniKey_User_Logoff(@handle)
          End    
        EndIf
      Else 
        If retcode <> 0 
          PostEvent(#msgBoxEvent, 0, 0, 0, 3)
          UniKey_User_Logoff(@handle)
          End 
        EndIf 
      EndIf 
    EndIf   
  ForEver
EndProcedure

Threadedun = CreateThread(@MyThread(), 3000)

wFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
mainWindow = OpenWindow(#PB_Any, 0, 0, 400, 100, "Threaded Message Box Handling", wFlags)
clockDisplay = TextGadget(#PB_Any, 0, 40, 400, 20, "Clock Display", #PB_Text_Center)
AddWindowTimer(mainWindow, clock, 1000)

Repeat
  Select WaitWindowEvent()
      
    Case #PB_Event_CloseWindow
      Select EventWindow()
        Case mainWindow
          appQuit = 1          
      EndSelect
      
    Case #PB_Event_Timer
      Select EventTimer()
        Case clock
          SetGadgetText(clockDisplay, FormatDate("%hh:%ii:%ss", Date()))
      EndSelect  
      
    Case #msgBoxEvent
      Select EventData()
        Case 1
          message$ = "Dongle de protection non trouvé" + #LF$ +
                     "Veuillez le reconnecter" + #LF$ + "Puis relancer le programme"
        Case 2
          message$ = "Mot de passe du dongle erroné" + #LF$ +
                     "Veuilez revoir avec votre administrateur" + #LF$ + "Abandon programme"
        Case 3
          message$ = "Dongle de protection non trouvé" + #LF$ + 
                     "Veuillez le reconnecter" + #LF$ + "Puis relancer le programme"
      EndSelect
      
      MessageRequester("Conversion Fichier Suisse", message$,
                       #PB_MessageRequester_Ok | #PB_MessageRequester_Error)
  EndSelect
  
Until appQuit

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 3:32 pm
by mk-soft
Or 'DoMessageRequester(Title.s, Text.s, Flags=0)' direct from Thread. Modul ThreadToGUI

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 3:48 pm
by loulou2522
THanks mk_soft this works perfectly
I have another problem becaus this thread would be executed every 5000ms
But in this example the programm can't execute anymore thing because it is blocked in the repeat for the window.
How can i make othe part of code which has to be executed in the main programm ?

Re: MessagRequester and Thread

Posted: Tue Apr 17, 2018 8:49 pm
by mk-soft
You need a own information window for this...

Here one example how to create a none blocked window over PostEvent...
I think you can modify this code for your demands

Code: Select all

;-TOP
;
; Comment : Thread Status Window
; Author  : mk-soft
; Version : v1.02
; Create  : 16.03.2018
; Update  :
;
; -----------------------------------------------------------------------------

EnableExplicit

CompilerIf #PB_Compiler_Thread = 0
  CompilerError "Use Compiler Option Threadsafe"
CompilerEndIf

Enumeration EventCustomValue #PB_Event_FirstCustomValue
  ; Nothing
EndEnumeration
  
Enumeration EventCustomValue
  #MyEvent_ThreadStatusOpen
  #MyEvent_ThreadStatusClose
  #MyEvent_ThreadStatusUpdate
EndEnumeration

Structure udtThreadStatus
  Signal.i
  Window.i
  Info.i
  Progress.i
  Cancel.i
  x.i
  y.i
  dx.i
  dy.i
  Title.s
  Text.s
  Button.s
  Min.i
  Max.i
  Value.i
EndStructure

; -----------------------------------------------------------------------------

Procedure DoOpenStatusWindow(x, y, dx, dy, Title.s, Text.s, Button.s="Cancel", Min=0, Max=100)
  Protected *data.udtThreadStatus
  With *data
    *data = AllocateStructure(udtThreadStatus)
    If *data
      \x = x
      \y = y
      \dx = dx
      \dy = dy
      \Title = Title
      \Text = Text
      \Button = Button
      \Min = Min
      \Max = Max
      \Signal = CreateSemaphore()
      PostEvent(#MyEvent_ThreadStatusOpen, 0, 0, 0, *data)
      WaitSemaphore(\Signal)
      If \Window
        ProcedureReturn *data
      Else
        FreeSemaphore(\Signal)
        FreeStructure(*data)
        ProcedureReturn 0 ; Error open windows
      EndIf
    Else
      ProcedureReturn 0 ; Out of Memory
    EndIf
  EndWith
EndProcedure

Declare DispatchTryCancelStatusWindow()

Procedure DispatchOpenStatusWindow()
  Protected *data.udtThreadStatus
  With *data
    *data = EventData()
    If *data
      \Window = OpenWindow(#PB_Any, \x, \y, \dx, \dy, \Title, #PB_Window_Tool)
      If \Window
        \Info = TextGadget(#PB_Any, 5, 5, \dx - 10, \dy - 65, \Text, #PB_Text_Center); | #PB_Text_Border) 
        \Progress = ProgressBarGadget(#PB_Any, 5, \dy - 55, \dx - 10, 20, \Min, \Max)
        \Cancel = ButtonGadget(#PB_Any, \dx / 2 - 60, \dy - 30, 120, 25, \Button)
        SetGadgetData(\Cancel, *data)
        BindGadgetEvent(\Cancel, @DispatchTryCancelStatusWindow())
      EndIf
      SignalSemaphore(\Signal)
    EndIf
  EndWith
EndProcedure

; -----------------------------------------------------------------------------

Procedure DoCloseStatusWindow(*Data.udtThreadStatus)
  With *Data
    If *Data
      PostEvent(#MyEvent_ThreadStatusClose, 0, 0, 0, *Data)
    EndIf
  EndWith
EndProcedure

Procedure DispatchCloseStatusWindow()
  Protected *data.udtThreadStatus
  With *data
    *data = EventData()
    If *data
      If IsWindow(\Window)
        CloseWindow(\Window)
      EndIf
      FreeSemaphore(\Signal)
      FreeStructure(*Data)
    EndIf
  EndWith
EndProcedure

; -----------------------------------------------------------------------------

Procedure TryCancelStatusWindow(*Data.udtThreadStatus)
  If *Data
    ProcedureReturn TrySemaphore(*Data\Signal)
  Else
    ProcedureReturn 0 
  EndIf
EndProcedure

Procedure DispatchTryCancelStatusWindow()
  Protected *data.udtThreadStatus
  With *data
    *data = GetGadgetData(EventGadget())
    If *data
      SignalSemaphore(\Signal)
    EndIf
  EndWith
EndProcedure

; -----------------------------------------------------------------------------

Procedure DoUpdateStatusWindow(*Data.udtThreadStatus, Value.i)
  With *Data
    If *Data
      \Value = Value
      PostEvent(#MyEvent_ThreadStatusUpdate, 0, 0, 0, *Data)
    EndIf
  EndWith
EndProcedure

Procedure DispatchUpdateStatusWindow()
  Protected *data.udtThreadStatus
  With *data
    *data = EventData()
    If *data
      If IsGadget(\Progress)
        SetGadgetState(\Progress, \Value)
      EndIf
    EndIf
  EndWith
EndProcedure

; -----------------------------------------------------------------------------

BindEvent(#MyEvent_ThreadStatusOpen, @DispatchOpenStatusWindow())
BindEvent(#MyEvent_ThreadStatusClose, @DispatchCloseStatusWindow())
BindEvent(#MyEvent_ThreadStatusUpdate, @DispatchUpdateStatusWindow())

; -----------------------------------------------------------------------------

; ***************************************************************************************

;-Test

CompilerIf #PB_Compiler_IsMainFile
  
  Procedure thProgress(Nummer)
    Protected *Data, Text.s, Value
    
    Debug "Start Thread " + Nummer
    text = #LF$ + "Thread Hintergrund Status" + #LF$ + "Fertig in 20 Sekunden" + #LF$ + "Zum beenden abrechen"
    *Data = DoOpenStatusWindow(#PB_Ignore, #PB_Ignore, 300, 160, "Thread Nummer " + Nummer, Text); , "Abbrechen")
    
    Repeat
      Delay(500)
      value + 500
      DoUpdateStatusWindow(*Data, (Value / 200) % 100)
    Until TryCancelStatusWindow(*Data) Or Value >= 20000
    DoCloseStatusWindow(*Data)
    Debug "Ende Thread " + Nummer + " Value = " + Value
  EndProcedure
  
  If OpenWindow(0, #PB_Ignore, #PB_Ignore, 200, 80, "Thread Test")
    CreateThread(@thProgress(), 1)
    CreateThread(@thProgress(), 2)
    CreateThread(@thProgress(), 3)
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          If EventWindow() = 0
            Break
          EndIf
      EndSelect
    ForEver
  EndIf
  
CompilerEndIf