FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour close a lost dialog thread
Posts: 104
Joined: Tue Feb 09, 2021 04:20 PM
close a lost dialog thread
Posted: Wed Jan 28, 2026 01:33 PM

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:

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:

   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)

Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: close a lost dialog thread
Posted: Wed Jan 28, 2026 04:23 PM

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 (harbour): Select all Collapse
       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 (markdown): Select all Collapse
    K --> L[PostMessage]
    K --> M[Synchronize]

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

Code (markdown): Select all Collapse
    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 (text): Select all Collapse
   if ::lModal != .t.  // possible that ::lModal is still NIL
      ::PostMsg( WM_CLOSE, nResult )

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

Code (text): Select all Collapse
   hb_gcAll( .F. ) // .F. is a must for multithreading

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

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

Antonio Linares
www.fivetechsoft.com
Posts: 104
Joined: Tue Feb 09, 2021 04:20 PM
Re: close a lost dialog thread
Posted: Thu Jan 29, 2026 01:57 AM

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

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:

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)

Continue the discussion