detect USB Device arrive/remove : how to use with harbour / HMG

Discuss anything else that does not suite other forums.

Moderator: Rathinagiri

User avatar
AUGE_OHR
Posts: 802
Joined: Sun Aug 25, 2019 3:12 pm
DBs Used: DBF, PostgreSQL, MySQL, SQLite
Location: Hamburg, Germany
Has thanked: 113 times
Been thanked: 202 times

Re: detect USB Device arrive/remove : how to use with harbour / HMG

Post by AUGE_OHR »

hi,
edk wrote:
Sun Nov 10, 2019 10:21 pm
I'm sorry, but I've never had to use peekdword(), and I don't see the appropriate function in Harbour. I wonder if you can use PeekStr(), read 4 bytes and convert them :?:
thx for Answer, i will try

what about "Bit-shift" like this

Code: Select all

   FOR n := 0 TO 31
      IF lAnd( nLShift( 1, n ), nMask )
         ? "New    " , iif( lAnd(nFlags,1), "Media " , "Volume ") ,  Chr( 65 + n)
         nRet := n
      ENDIF
   NEXT
it test 8 Bit Mask where "0" (+65) = "A" Volumn
have fun
Jimmy

edk
Posts: 558
Joined: Thu Oct 16, 2014 11:35 am
Location: Poland
Has thanked: 146 times
Been thanked: 486 times

Post by edk »

:?: hb_BitShift(<nVal>, <nBits>) ➜ nResult
returns <nVal> shifted <nBits> bits positions, equivalent of << and >> operators in C language. If <nBits> is negative, bits will be shifted to the right, otherwise bits will be shifted to the left.

User avatar
AUGE_OHR
Posts: 802
Joined: Sun Aug 25, 2019 3:12 pm
DBs Used: DBF, PostgreSQL, MySQL, SQLite
Location: Hamburg, Germany
Has thanked: 113 times
Been thanked: 202 times

Post by AUGE_OHR »

edk wrote:
Tue Nov 12, 2019 3:31 pm
:?: hb_BitShift(<nVal>, <nBits>) ➜ nResult
returns <nVal> shifted <nBits> bits positions, equivalent of << and >> operators in C language. If <nBits> is negative, bits will be shifted to the right, otherwise bits will be shifted to the left.
THX
have fun
Jimmy

User avatar
AUGE_OHR
Posts: 802
Joined: Sun Aug 25, 2019 3:12 pm
DBs Used: DBF, PostgreSQL, MySQL, SQLite
Location: Hamburg, Germany
Has thanked: 113 times
Been thanked: 202 times

Post by AUGE_OHR »

hi,

i have try to use Thread and PUBLIC to show my Problem with this Working Sample.
USBAUTO.ZIP
(2.14 KiB) Downloaded 51 times
when try to run WMI direct after DBT_DEVICEARRIVAL it crash without Debugger. :o
as i say it is not a good place in "that" loop so i need to get "Information" out of the Event loop

now i have to use a PUBLIC to transfer Data but this is not (Thread) "safe"

Code: Select all

// use some PUBLIC ...
PUBLIC lPublic := .F.
PUBLIC aThread := { NIL, NIL }
PUBLIC aAction := { "", "","" }
under Xbase++ i "send" those Array via

Code: Select all

   PostAppEvent(MyEvent, aAction, , oMain)
so how to get that Code working without PUBLIC :?:
have fun
Jimmy

edk
Posts: 558
Joined: Thu Oct 16, 2014 11:35 am
Location: Poland
Has thanked: 146 times
Been thanked: 486 times

Post by edk »

AUGE_OHR wrote:
Thu Nov 14, 2019 6:45 am
hi,

i have try to use Thread and PUBLIC to show my Problem with this Working Sample.
USBAUTO.ZIP

when try to run WMI direct after DBT_DEVICEARRIVAL it crash without Debugger. :o
as i say it is not a good place in "that" loop so i need to get "Information" out of the Event loop
I will try tomorrow in my free time to look at it.
now i have to use a PUBLIC to transfer Data but this is not (Thread) "safe"

Code: Select all

// use some PUBLIC ...
PUBLIC lPublic := .F.
PUBLIC aThread := { NIL, NIL }
PUBLIC aAction := { "", "","" }
under Xbase++ i "send" those Array via

Code: Select all

   PostAppEvent(MyEvent, aAction, , oMain)
so how to get that Code working without PUBLIC :?:
I think the use of the mutex semaphore can be helpful.
Check this out: http://www.kresin.ru/en/hrbfaq_3.html#Doc11 /hb_mutexSubscribe, hb_mutexNotify/
Example from harbour:

Code: Select all

/*
 * $Id: mttest07.prg 14676 2010-06-03 16:23:36Z vszakats $
 */

/*
 * Harbour Project source code:
 *    demonstration/test code for using mutexes to send/receive
 *    messages between threads to synchronize divided jobs between
 *    threads.
 *
 * Copyright 2008 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
 * www - http://harbour-project.org
 *
 */

#define N_THREADS 5
#define N_JOBS    10000

static s_aCounters
static s_mtxJobs
static s_mtxResults

proc main()
   local aThreads, aResults, i, nDigit, nSum, nExpected

   ? Version()
   ? "Main start"

   s_aCounters := array( N_THREADS )
   aFill( s_aCounters, 0 )
   aThreads := {}
   aResults := {}
   s_mtxJobs := hb_mutexCreate()
   s_mtxResults := hb_mutexCreate()

   ? "Starting threads: "
   for i :=1 to N_THREADS
      aadd( aThreads, hb_threadStart( @thFunc() ) )
      ?? "<" + ltrim( str( i ) ) + ">"
   next

   ? "Sending jobs... "
   nDigit := 10
   for i := 1 to N_JOBS
      hb_mutexNotify( s_mtxJobs, nDigit )
      //?? "<" + ltrim( str( i ) ) + ">"
      nDigit++
   next

   ? "Sending terminate values..."
   for i := 1 to N_THREADS
      hb_mutexNotify( s_mtxJobs, NIL )
      ?? "<" + ltrim( str( i ) ) + ">"
   next

   ? "Collecting results... "
   for i :=1 to N_JOBS
      hb_mutexSubscribe( s_mtxResults,, @nDigit )
      //?? "<" + ltrim( str( i ) ) + ">"
      aadd( aResults, nDigit )
   next

   ? "Waiting for threads..."
   aEval( aThreads, { |x| hb_threadJoin( x ) } )
   ? "Threads joined"

   nSum := 0
   for each nDigit in aResults
      nSum += nDigit
   next

   nSum := round( nSum, 2 )
   nExpected := round( ( 10 + 10 + N_JOBS - 1 ) / 2 / 3 * N_JOBS, 2 )

   if round( nSum - nExpected, 2 ) == 0
      ? "OK, final sum:", ltrim( str( nSum ) )
   else
      ? "ERROR, final sum:", ltrim( str( nSum ) ), ;
        "expected:", ltrim( str( nExpected ) )
   endif
   ? "End of main"
return

proc thFunc()
   local xJob, xResult
   while .T.
      hb_mutexSubscribe( s_mtxJobs,, @xJob )
      if xJob == NIL
         exit
      endif
      xResult := xJob / 3
      hb_mutexNotify( s_mtxResults, xResult )
   enddo
return

User avatar
AUGE_OHR
Posts: 802
Joined: Sun Aug 25, 2019 3:12 pm
DBs Used: DBF, PostgreSQL, MySQL, SQLite
Location: Hamburg, Germany
Has thanked: 113 times
Been thanked: 202 times

Post by AUGE_OHR »

hi,
edk wrote:
Thu Nov 14, 2019 2:06 pm
I think the use of the mutex semaphore can be helpful.
Yes you are right ... but i use a PUBLIC for this Demo while i don't know other Way with harbour / HMG.

my "Problem" with HMG , FW or Express++ (for Xbase++) are #xCommand Syntax.
i like OOP Style and Event like Windows have.

as i understand HMG use DOEVENTS() but i don't understand how to "use" it :?:
is there a "internal" harbour / HMG "Message" Queue :?:

---

from FUNCTION USB_Detect() i got a Drive-Letter but i want more Information.
now a Threat is waiting for "Action" ... in a DO WHILE .T. loop :roll:

i use other PUBLIC as "Action-Flag" so when lPublic = .T. it begin to "read" transfer data
now i call WMI or use GetVolumeInformation() API to get more Information like "VolumeSerialNumber"

---

PUBLIC and DO WHILE .T. loop both i don't want to use.

under Xbase++ my Dialog (Form) have a Eventloop ( DOEVENTS() ? )
here i can "grab" a Event which i can define.
i can send it with PostAppEvent() (PostMessage) from Child to Parent

Code: Select all

#define xbeMyUSB_Base           0x79170000
#define xbeMyUSB_Arrive         (xbeMyUSB_Base + 1)
#define xbeMyUSB_Remove         (xbeMyUSB_Base + 2)

FUNCTION USB_Detect()
...
   PostAppEvent(xbeMyUSB_Arrive,nRet,,oMain)

FUNCTION MAIN
... 
   nEvent := 0
   DO WHILE !lExit
      nEvent := APPEVENT( @mp1, @mp2, @oXbp, nTime )
      DO CASE
         CASE nEvent == xbeMyUSB_Arrive              
            oDlg:FillDrive()
so is there a Way with harbour / HMG or do i need "more" like \contrib\hbxbp\

thx for help
have fun
Jimmy

edk
Posts: 558
Joined: Thu Oct 16, 2014 11:35 am
Location: Poland
Has thanked: 146 times
Been thanked: 486 times

Post by edk »

when try to run WMI direct after DBT_DEVICEARRIVAL it crash without Debugger. :o
as i say it is not a good place in "that" loop so i need to get "Information" out of the Event loop
You're right, there is a problem with the outgoing call because an incoming synchronous call is being made at this time.
is there a "internal" harbour / HMG "Message" Queue :?:
Yeap.
from FUNCTION USB_Detect() i got a Drive-Letter but i want more Information.
now a Threat is waiting for "Action" ... in a DO WHILE .T. loop :roll:

i use other PUBLIC as "Action-Flag" so when lPublic = .T. it begin to "read" transfer data
now i call WMI or use GetVolumeInformation() API to get more Information like "VolumeSerialNumber"

PUBLIC and DO WHILE .T. loop both i don't want to use.
I prepared something like that, got rid of some public variables, I used mutex, sending the task and sending the result back, maybe it will be helpful.

Code: Select all

/*
* HMG This Demo
*
* USB Stick Arrive / Remove Demo
*
* (c) 2019 Auge & Ohr
*/

#include "hmg.ch"
#include "hbthread.ch"

STATIC s_mtxUSB
STATIC s_mtxReturn

FUNCTION Main
Local nIndex

   IF !hb_mtvm()
      MSGSTOP("There is no support for multi-threading")
      QUIT
   ENDIF

   // use some PUBLIC ...
   PUBLIC aThread := { NIL, NIL }

   s_mtxUSB := hb_mutexCreate()		//Mutex for Wait4Action thread
   s_mtxReturn := hb_mutexCreate()		//Return mutex for event USB_Detect main thread
   
   aThread[ 1 ] := hb_threadStart( @Wait4Action() )
   aThread[ 2 ] := hb_threadStart( @DoNothing() )

   DEFINE WINDOW Form_1 ;
      AT 0,0 ;
      WIDTH 400 ;
      HEIGHT 200 ;
      TITLE 'This Demo' ;
      MAIN ;
      NOMAXIMIZE ;
      ON INIT ThisWindow.Title := 'USB Stick Demo'

      @ 10,10 BUTTON Button_1 ;
         CAPTION 'Exit' ;
         ACTION IF ( MsgYesNo("Are you sure?", , .T.), ThisWindow.Release, Nil )

      @ 100,10 TEXTBOX Text_1 ;
         VALUE "insert / remove USB Stick" ;
         HEIGHT 40 ;
         WIDTH 360 ;
         FONT "Arial" SIZE 22 ;
         READONLY

   END WINDOW

   CREATE EVENT PROCNAME USB_Detect() HWND Form_1.HANDLE STOREINDEX nIndex

   CENTER WINDOW Form_1

   ACTIVATE WINDOW Form_1

   CloseThread()

RETURN nil

/*********************************************************************/

#define WM_DEVICECHANGE             0x0219
#define DBT_DEVICEARRIVAL           0x8000
#define DBT_DEVICEQUERYREMOVE       0x8001
#define DBT_DEVICEQUERYREMOVEFAILED 0x8002
#define DBT_DEVICEREMOVEPENDING     0x8003
#define DBT_DEVICEREMOVECOMPLETE    0x8004
#define DBT_DEVTYP_VOLUME           2


FUNCTION USB_Detect()
LOCAL nHWnd    := EventHWND()
LOCAL nMsg     := EventMSG()
LOCAL nWParam  := EventWPARAM()
LOCAL nLParam  := EventLPARAM()
LOCAL nMask, cDevice := ""
Local xRet
Local lThreatRet := hb_mutexSubscribe( s_mtxReturn, 0.00000001, @xRet ) 

DO CASE

   CASE lThreatRet .AND. hb_isArray ( xRet )
   	 //return message from Wait4Action thread
   	 Msginfo( xRet[1], STR( xRet[2] ) )

   CASE nMsg == WM_DEVICECHANGE
      DO CASE
         CASE nWParam == DBT_DEVICEARRIVAL
            nMask    := DeviceChangeInfo( nWParam, nLParam )
            if !Empty( nMask ) .and. nMask > 0
               cDevice := GetDrive( nMask )
            endif
            //send job
            hb_mutexNotify( s_mtxUSB, { "INSERT", cDevice, nMask, nHWnd } )

         CASE nWParam == DBT_DEVICEREMOVECOMPLETE
            nMask    := DeviceChangeInfo( nWParam, nLParam )
            if !Empty( nMask ) .and. nMask > 0
               cDevice := GetDrive( nMask )
            endif
            //send job
            hb_mutexNotify( s_mtxUSB, { "REMOVE", cDevice, nMask, nHWnd } )
      End CASE
End Case
RETURN cDevice

/*********************************************************************/
STATIC FUNCTION Wait4Action()

LOCAL xUSB
LOCAL cAction := ""
LOCAL cDevice := ""
LOCAL cInfo   := ""
LOCAL cText   := ""
LOCAL nInfo   := 0
LOCAL ParrentHWnd
Local lExit :=  .F.

DO While !lExit
      hb_mutexSubscribe( s_mtxUSB,, @xUSB )		//wait for job with params
      IF xUSB == NIL
         lExit := .T.
      ENDIF
      IF hb_IsArray (xUSB)
      	cAction     := xUSB[1]
      	cDevice     := xUSB[2]
      	nInfo       := xUSB[3]
      	ParrentHWnd := xUSB[4]
      	cInfo   := WMI_Info(cDevice)      	
      	IF !EMPTY(cAction) .AND. !EMPTY(cDevice)
      		cText := cAction + " " + cDevice + CRLF
      		cText += "S/N " + IF(cInfo = "N/A","???",cInfo)
      		//send return message
      		hb_mutexNotify( s_mtxReturn, { cText, nInfo } )
      		SendMessage (ParrentHWnd, 0x0000, 0, 0) 	//force event
         ENDIF
      ENDIF
EndDo

RETURN nil

/*********************************************************************/
STATIC FUNCTION DoNothing()
   DO WHILE .T.
      hb_idleSleep( .5 )
   ENDDO
RETURN nil

/*********************************************************************/
STATIC FUNCTION CloseThread()
LOCAL i
   FOR i := 1 TO LEN( aThread )
      IF aThread[ i ] <> NIL
         hb_threadDetach( aThread[ i ] )   // close thread handle
         hb_threadQuitRequest( aThread[ i ] )   // terminate thread
         aThread[ i ] := NIL
      ENDIF
   NEXT
RETURN NIL

/*********************************************************************/
STATIC FUNCTION GetDrive( nMask )
Local cBin := NToC ( nMask, 2 )
Local nBit:= Len ( cBin ) - hb_At( '1', cBin )
RETURN Chr( nBit + 65 ) + ":"

/*********************************************************************/
STATIC FUNCTION WMI_Info(cDrive)
Local oProcesses
Local oProcess
Local lIsRunning
LOCAL cSN := "N/A"
LOCAL cID := SUBSTR(cDrive,1,2)
LOCAL oWMI

   oWMI := WMIService()

   IF !EMPTY(oWMI)
      oProcesses = oWMI:ExecQuery("SELECT * FROM Win32_LogicalDisk")

      IF oProcesses:Count > 0
         FOR EACH oProcess in oProcesses
            IF oProcess:DeviceID = cID
               cSN := oProcess:VolumeSerialNumber
               EXIT
            ENDIF
         NEXT
      ENDIF
   ENDIF
   
RETURN cSN


/*********************************************************************/
STATIC FUNCTION WMIService()
STATIC oWMI
LOCAL oLocator

   if oWMI == NIL
      oLocator := CreateObject( "wbemScripting.SwbemLocator" )
      IF EMPTY(oLocator)
         msginfo("can not create wbemScripting.SwbemLocator")
      ELSE
         oWMI := oLocator:ConnectServer()
      ENDIF
   endif

RETURN oWMI


/************************** C-Code ***************************************/

#pragma BEGINDUMP

#include <windows.h>
#include <hbapi.h>
#include "hbapiitm.h"
#include "dbt.h"


HB_FUNC (DEVICECHANGEINFO) // DeviceChangeInfo( wParam, lParam )
{
//   WPARAM wParam = hb_parnl( 1 );
   PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR) hb_parnl( 2 );
//   TCHAR szMsg[80];

   if ( lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME )
   {
      PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME) lpdb;
      hb_retnl( lpdbv->dbcv_unitmask );
   } else hb_retnl( 0 );

}

#pragma ENDDUMP

*
* eof
*
Last edited by edk on Mon Nov 18, 2019 3:36 pm, edited 1 time in total.

edk
Posts: 558
Joined: Thu Oct 16, 2014 11:35 am
Location: Poland
Has thanked: 146 times
Been thanked: 486 times

Post by edk »

Another version without multi-Threading, but with an error trap waiting for the synchronous call to complete with input for the main thread:

Code: Select all

/*
* HMG This Demo
*
* USB Stick Arrive / Remove Demo
*
* (c) 2019 Auge & Ohr
*/

#include "hmg.ch"

FUNCTION Main
Local nIndex

   DEFINE WINDOW Form_1 ;
      AT 0,0 ;
      WIDTH 400 ;
      HEIGHT 200 ;
      TITLE 'This Demo' ;
      MAIN ;
      NOMAXIMIZE ;
      ON INIT ThisWindow.Title := 'USB Stick Demo'

      @ 10,10 BUTTON Button_1 ;
         CAPTION 'Exit' ;
         ACTION IF ( MsgYesNo("Are you sure?", , .T.), ThisWindow.Release, Nil )

      @ 100,10 TEXTBOX Text_1 ;
         VALUE "insert / remove USB Stick" ;
         HEIGHT 40 ;
         WIDTH 360 ;
         FONT "Arial" SIZE 22 ;
         READONLY

   END WINDOW

   CREATE EVENT PROCNAME USB_Detect() HWND Form_1.HANDLE STOREINDEX nIndex

   CENTER WINDOW Form_1

   ACTIVATE WINDOW Form_1

RETURN nil

/*********************************************************************/

#define WM_DEVICECHANGE             0x0219
#define DBT_DEVICEARRIVAL           0x8000
#define DBT_DEVICEQUERYREMOVE       0x8001
#define DBT_DEVICEQUERYREMOVEFAILED 0x8002
#define DBT_DEVICEREMOVEPENDING     0x8003
#define DBT_DEVICEREMOVECOMPLETE    0x8004
#define DBT_DEVTYP_VOLUME           2


FUNCTION USB_Detect()
LOCAL nHWnd    := EventHWND()
LOCAL nMsg     := EventMSG()
LOCAL nWParam  := EventWPARAM()
LOCAL nLParam  := EventLPARAM()
LOCAL nMask, cDevice := ""

DO CASE

   CASE nMsg == WM_DEVICECHANGE
      DO CASE
         CASE nWParam == DBT_DEVICEARRIVAL
            nMask    := DeviceChangeInfo( nWParam, nLParam )
            if !Empty( nMask ) .and. nMask > 0
               cDevice := GetDrive( nMask )
            endif
            MSGINFO ("INSERT "+cDevice+" S/N "+WMI_Info(cDevice))
            
         CASE nWParam == DBT_DEVICEREMOVECOMPLETE
            nMask    := DeviceChangeInfo( nWParam, nLParam )
            if !Empty( nMask ) .and. nMask > 0
               cDevice := GetDrive( nMask )
            endif
            MSGINFO ("REMOVE "+cDevice)
      End CASE
End Case
RETURN cDevice

/*********************************************************************/
STATIC FUNCTION GetDrive( nMask )
Local cBin := NToC ( nMask, 2 )
Local nBit:= Len ( cBin ) - hb_At( '1', cBin )
RETURN Chr( nBit + 65 ) + ":"

/*********************************************************************/
STATIC FUNCTION WMI_Info(cDrive)
Local oProcesses
Local oProcess
Local lIsRunning
LOCAL cSN := "N/A"
LOCAL cID := SUBSTR(cDrive,1,2)
LOCAL oWMI, lSuccess := .F.

   oWMI := WMIService()

   IF !EMPTY(oWMI)
   	DO WHILE !lSuccess
     	BEGIN SEQUENCE WITH {|o| break(o)}
     	 	oProcesses = oWMI:ExecQuery("SELECT * FROM Win32_LogicalDisk")
     	     lSuccess := .T.
      	     
      	RECOVER USING o
      	     DO EVENTS
      	END
     ENDDO


     IF oProcesses:Count > 0
         FOR EACH oProcess in oProcesses
            IF oProcess:DeviceID = cID
               cSN := oProcess:VolumeSerialNumber
               EXIT
            ENDIF
         NEXT
     ENDIF
   ENDIF
   
RETURN cSN


/*********************************************************************/
STATIC FUNCTION WMIService()
STATIC oWMI
LOCAL oLocator, lSuccess := .F.
//ALTD()
//hb_idleSleep(10)

   if oWMI == NIL
      oLocator := CreateObject( "wbemScripting.SwbemLocator" )
      IF EMPTY(oLocator)
         msginfo("can not create wbemScripting.SwbemLocator")
      ELSE
      
      	DO WHILE !lSuccess
      		BEGIN SEQUENCE WITH {|o| break(o)}
      	         oWMI := oLocator:ConnectServer()
      	         lSuccess := .T.
      	     
      	     RECOVER USING o
      	     	DO EVENTS
      	     END
      	ENDDO
      ENDIF
   endif

RETURN oWMI


/************************** C-Code ***************************************/

#pragma BEGINDUMP

#include <windows.h>
#include <hbapi.h>
#include "hbapiitm.h"
#include "dbt.h"


HB_FUNC (DEVICECHANGEINFO) // DeviceChangeInfo( wParam, lParam )
{
//   WPARAM wParam = hb_parnl( 1 );
   PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR) hb_parnl( 2 );
//   TCHAR szMsg[80];

   if ( lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME )
   {
      PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME) lpdb;
      hb_retnl( lpdbv->dbcv_unitmask );
   } else hb_retnl( 0 );

}

#pragma ENDDUMP

*
* eof
*

User avatar
AUGE_OHR
Posts: 802
Joined: Sun Aug 25, 2019 3:12 pm
DBs Used: DBF, PostgreSQL, MySQL, SQLite
Location: Hamburg, Germany
Has thanked: 113 times
Been thanked: 202 times

Post by AUGE_OHR »

hi,

YES, your Code is much better than my Workaround.
i will study it and learn from your Code , THX
have fun
Jimmy

User avatar
AUGE_OHR
Posts: 802
Joined: Sun Aug 25, 2019 3:12 pm
DBs Used: DBF, PostgreSQL, MySQL, SQLite
Location: Hamburg, Germany
Has thanked: 113 times
Been thanked: 202 times

Post by AUGE_OHR »

hi,

i have some working Sample to react on WM_DEVICECHANGE but both fail in "Main" App

Code: Select all

   CREATE EVENT PROCNAME USB_Detect() HWND Form_1.HANDLE STOREINDEX nIndex
it does use Form_1.HANDLE which is correct but

a.) it fired Event only when Form_1 have focus
b.) Form_1 only can receive Event when have focus

not clear what the Problem is but the other Problem have to do with it : Thread

if i can`t receive Event i have to "ask" for it so i want to use Thread / Timer
like above in USB_Detect() i can´t access "Main" when using EVENT or Thread :?:

---

i have read in c:\hmg.3.4.4\SAMPLES\MultiThread\MT_Notifier\MT_Notifier.prg

Code: Select all

#define WAY_ONE 1

// set inter-thread data exchange, this is the way because vars PUBLIC are not INHERITED
#if WAY_ONE
   s_hWnd_Form1 := Form_1.HANDLE
#else
   HMG_ThreadShareData( 1, Form_1.HANDLE )
#endif

   //                             Notifier( cMsg, ERROR, nSeconds, lCenter, nTransparency )
   pThID[ 1 ] := hb_threadStart( @Notifier(), "Thread Count "+ hb_NtoS( ++nThreadCount ) + CRLF + "Printing file xxxxx.xxx sent to EPSON LX-300", NIL,   3, NIL, NIL )
   pThID[ 2 ] := hb_threadStart( @Notifier(), "Thread Count "+ hb_NtoS( ++nThreadCount ) + CRLF + "Printing file xxxxx.xxx sent to EPSON LX-300", NIL,   3, NIL, NIL )
   pThID[ 3 ] := hb_threadStart( @Notifier(), "Thread Count "+ hb_NtoS( ++nThreadCount ) + CRLF + "File not found!",                           1, NIL, NIL, NIL )
   pThID[ 4 ] := hb_threadStart( @Notifier(), "Thread Count "+ hb_NtoS( ++nThreadCount ) + CRLF + "Printing file xxxxx.xxx sent to EPSON LX-300", NIL,   3, NIL, 128 )
   pThID[ 5 ] := hb_threadStart( @Notifier(), "Thread Count "+ hb_NtoS( ++nThreadCount ) + CRLF + "File not found!",                           1, NIL, NIL, 100 )

   Form_1.Label_1.VALUE := "Total Thread Count: "+ hb_NtoS( nThreadCount )
and there is a comment
// NOTE: Because when you create a GUI control inside a Thread each thread take a local Windows Message Queue,
// is necessary you attach all Message Queue to the main thread Message Queue to allow
// invoke DO EVENTS in any thread for empty the Windows Message Queue of all thread.
so where can i read more about hb_thread :?:

---

i have read about "hb_setListenerAdd"

Question : is "Listener" -> "look for Event" :?:

i´m stuck with this Problem. please help if you got a Idea :idea:
have fun
Jimmy

Post Reply