close a lost dialog thread

Post Reply
JoséQuintas
Posts: 104
Joined: Tue Feb 09, 2021 4:20 pm

close a lost dialog thread

Post by JoséQuintas »

Not a normal use.
A GTWVG routine on one thread updates fivewin dialog on another thread, and closes at the end.
But when an error occurs, GTWVG routines closes, and no other routine can close the fivewin dialog.

At momment, I can think only on create another thread, using my old wrapper:

Code: Select all | Expand

CREATE CLASS RunWhileThreadClass

   VAR lExit        INIT .F.
   VAR nThreadId
   VAR nInterval    INIT 600
   VAR cWindowTitle INIT ""
   VAR bCode
   METHOD New()     INLINE ::nThreadId := hb_ThreadSelf(), SELF
   METHOD Execute( bCode )

   ENDCLASS

METHOD Execute( bCode ) CLASS RunWhileThreadClass

   LOCAL nCont

   hb_gtReload( "WVG" )
   IF bCode != Nil
      ::bCode := bCode
   ENDIF
   AppInitSets()
   HB_GtInfo( HB_GTI_WINTITLE, ::cWindowTitle )
   //wvgSetAppWindow():Hide()
   DO WHILE ! ::lExit
      Eval( ::bCode )
      FOR nCont = 1 TO ::nInterval
         //hb_ReleaseCPU()
         IF hb_ThreadWait( ::nThreadId, 0.1, .T. ) == 1
            ::lExit := .T.
         ENDIF
         Inkey(1)
         IF ::lExit
            EXIT
         ENDIF
      NEXT
   ENDDO
   //hb_gcAll(.T.)

   RETURN Nil

What is does ?
It checks if another thread is running.
If another thread stop, it closes current thread.
On fivewin use, it could check gtwvg thread, and closes fivewin dialog before closes itself.

Note:
My Main routine is anything like this:

Code: Select all | Expand

   hb_ThreadStart( { || Sistema( hb_ArrayToParams( aParamList ) ) } )
   Inkey(1)
   hb_ThreadWaitForAll()

   RETURN

It closes application when no other thread is running.
But a fivewin dialog is a thread, can't close while a dialog is running.

Does anybody have a suggestion ?

José M. C. Quintas Brazil
gtwvg, fivewin 25.12, hwgui, mingw 15.2 (32 bits)

User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: close a lost dialog thread

Post by Antonio Linares »

Dear José,

Your approach with the monitoring thread is actually the correct solution for this problem. Here's why and how to implement it properly:

Understanding the Problem

FiveWin is primarily single-threaded for UI operations. 0-cite-0 This means that when your GTWVG thread terminates unexpectedly due to an error, it can't directly close the FiveWin dialog that's running on a different thread.

The Solution: Thread-Safe Dialog Closing

The recommended approach for cross-thread communication in FiveWin is to use PostMessage, which is asynchronous and thread-safe. 0-cite-1

Your monitoring thread needs to call oDlg:PostMsg(WM_CLOSE) to close the FiveWin dialog. This is exactly what FiveWin's own End() method does for modeless dialogs: 0-cite-2

The PostMsg() method is a simple wrapper around the Windows PostMessage() API, which safely posts a message to the window's message queue from any thread.

Implementation Recommendations
  1. Store the dialog reference: Make sure your monitoring thread has access to the FiveWin dialog object (or at least its window handle hWnd).

  2. Use PostMsg to close: When your monitoring thread detects that the GTWVG thread has terminated, call:

    Code: Select all | Expand

       oDlg:PostMsg(WM_CLOSE)
  3. Monitor thread pattern: Your RunWhileThreadClass approach is correct. The key is using hb_ThreadWait() to detect when the GTWVG thread terminates, then closing the dialog.

  4. Garbage collection: Note that FiveWin's End() method calls hb_gcAll(.F.) with .F. specifically for multithreading safety. 0-cite-3

Example Pattern from FiveWin

The FiveWin codebase includes an example of background thread communication in comm.c, where a listenThread uses SendMessage() to notify the main thread: 0-cite-4

However, PostMessage is preferred over SendMessage for cross-thread dialog control because it's asynchronous and won't block your monitoring thread.

Notes
  • Your RunWhileThreadClass monitoring approach is the right solution for this problem
  • Make sure the FiveWin dialog is created as modeless (not modal), otherwise it blocks the thread and won't respond properly to PostMsg(WM_CLOSE)
  • Pass the dialog reference to your monitoring thread so it can call oDlg:PostMsg(WM_CLOSE) when the GTWVG thread terminates
  • Consider adding error handlers in your GTWVG thread that can set a shared flag before terminating, so your monitoring thread knows an error occurred
  • The hb_ThreadWait() function you're using is from Harbour's threading library (not in FiveWin itself), which is appropriate for monitoring thread status
Citations

File: docs/reference/advanced-diagrams.md (L319-320)

Code: Select all | Expand

    K --> L[PostMessage]
    K --> M[Synchronize]

File: docs/reference/advanced-diagrams.md (L337-337)

Code: Select all | Expand

    note over A,F: FiveWin is primarily single-threaded<br/>UI applications but can integrate<br/>with background operations

File: source/classes/dialog.prg (L779-780)

Code: Select all | Expand

   if ::lModal != .t.  // possible that ::lModal is still NIL
      ::PostMsg( WM_CLOSE, nResult )

File: source/classes/dialog.prg (L792-792)

Code: Select all | Expand

   hb_gcAll( .F. ) // .F. is a must for multithreading

File: source/winapi/comm.c (L275-277)

Code: Select all | Expand

      if( pComm->CommNotifyHwnd != NULL )
         SendMessage( pComm->CommNotifyHwnd, WM_COMMNOTIFY, ( WPARAM ) pComm,
                      MAKELONG( CN_RECEIVE, 0 ) );
regards, saludos

Antonio Linares
www.fivetechsoft.com
JoséQuintas
Posts: 104
Joined: Tue Feb 09, 2021 4:20 pm

Re: close a lost dialog thread

Post by JoséQuintas »

Thanks, I will use PostMessage().

I forgot about oDlg:bValid and :lCanClose used on it.
At momment create a property nThreadId on routine class, and change bValid codeblock

Code: Select all | Expand

METHOD Execute()
...
   ::oDlg:bValid := { || ;
      iif( GetKeyState( VK_ESCAPE ), ::lHitEsc := .T., Nil ), ;
      iif( GetKeyState( VK_ESCAPE ), ::ShowText( "ESC pressionado" ), Nil ), ;
      iif( ! Empty( ::nThreadID ) .AND. hb_ThreadWait( ::nThreadId, 0.1, .T. ) == 1, ::lCanClose := .T., Nil ), ;
      ::lCanClose }

Besides PostMessage(), lCanClose need to be changed to .T. or bValid will block dialog close.
On machines with domain, Task Manager is not available to user.
With thread test, even if routine does not closes dialog, user will be able to close the dialog.

Antonio Linares wrote: Wed Jan 28, 2026 4:23 pm

Make sure the FiveWin dialog is created as modeless (not modal), otherwise it blocks the thread and won't respond properly to PostMsg(WM_CLOSE)

Using multithread, no problem with fivewin modal dialog.
It is a dialog with GET MEMO and a progressbar.

One use is on backup, gtwvg routines zip dbfs, backup and zip MySQL, send to ftp, update text and update progressbar on fivewin dialog at each step.
Another use is on server, sending mails, and using webservices.
Then, I am sure that modal dialog is not a problem on multithread.

José M. C. Quintas Brazil
gtwvg, fivewin 25.12, hwgui, mingw 15.2 (32 bits)

Post Reply