Code:
' enum_threads2.bas ' ================================================================= ' demo enumeration of current threads in system for pb/cc 3.0 ' author: michael mattias racine wi ' placed in public domain by author 11/25/02 ' demonstration program to show how to enumerate the threads in the system and ' use a callback to identify child threads of current process. ' tested on win 98 only. ' ----------------------------------------------------------------- ' using with pb cc 2.0: ' thread create will not accept the 'to hthread(i)' and gives message long integer variable required ' if you want this to work under pb/cc 2.0 you can make modifications yourself. ' ================================================================ #compile exe #register none #debug error on #include "win32api.inc" function winmain( byval hinstance as long , _ byval hprevinst as long , _ lpszcmdline as asciiz ptr, _ byval ncmdshow as long ) as long print "enumerate threads..." print "another cool demonstration and learning program courtesy michael mattias" call testenumthreads print "end of demo, any key to exit..." waitkey$ end function '=============================================================== ' structures, equates and declares not found in pb-supplied ' win32api.inc through version dated 10/30/02 ' =============================================================== type threadentry32 dwsize as dword cntusage as dword th32threadid as dword th32ownerprocessid as dword tpbasepri as long todeltapri as long dwflags as dword end type %th32cs_snapheaplist = &h00000001 %th32cs_snapprocess = &h00000002 %th32cs_snapthread = &h00000004 %th32cs_snapmodule = &h00000008 %th32cs_snapall = %th32cs_snapheaplist or %th32cs_snapprocess _ or %th32cs_snapthread or %th32cs_snapmodule %th32cs_inherit = &h080000000 ' flags used in next any bitwise combination of %th32cs_xxxxx declare function createtoolhelp32snapshot lib "kernel32.dll" alias "createtoolhelp32snapshot" _ (byval dwflags as dword, byval th32processid as dword) as long declare function thread32first lib "kernel32.dll" alias "thread32first" _ (byval hsnap as dword, te32 as threadentry32) as long declare function thread32next lib "kernel32.dll" alias "thread32next" _ (byval hsnap as dword, te32 as threadentry32) as long ' ======[end of missing structures, equates and declares ]================= ' callback prototype for enumsystemthreads: declare function enumthreads_callback (byval userdata as long, te32 as threadentry32, byval currentpid as dword, byval callingthreadid as dword) as long ' ================================================================== ' function to enumerate all threads in system at any given moment ' ================================================================== function enumsystemthreads (byval cbaddr as dword, dwuserdata as long ) as long local hsnapshot as dword, lresult as dword, enumreturn as long local thread_id as dword, te32 as threadentry32 local current_process_id as dword, calling_thread_id as dword ' ================================================================================ ' create a snapshot of all threads in the system. parameter two (pid) ' ignored unless th32cs_snapheaplist or tc32cs_snapmodule are specified. ' ================================================================================ ' test code: deliberate error in parameter to verify function fails when bad parm passed ' hsnapshot =createtoolhelp32snapshot (-123456, 0) << fails correctly (oxymoronic?) hsnapshot =createtoolhelp32snapshot (%th32cs_snapthread, 0) ' <<< correct call! if hsnapshot <> %invalid_handle_value then current_process_id = getcurrentprocessid ' get current process id and calling calling_thread_id = getcurrentthreadid ' thread id for use in callback. te32.dwsize = sizeof(te32) ' must be set. lresult = thread32first (hsnapshot,te32) while istrue lresult ' we found a thread, so send it to the user-defined callback function: call dword cbaddr using enumthreads_callback _ (dwuserdata, te32, current_process_id, calling_thread_id)_ to enumreturn if isfalse enumreturn then ' terminate the enumeration lresult = %false else ' no, no, true means keep going! lresult = thread32next (hsnapshot, te32) end if wend closehandle hsnapshot function = 0 else ' could not get thread snapshot..invalid_handle_value function = -1& end if end function ' ====================================================================== ' for demo purposes, global arrays to hold handles and ids ' real application might use windows event to get/save thread ids. ' for example see: ' [url="http://www.powerbasic.com/support/pbforums/showthread.php?t=23385"]http://www.powerbasic.com/support/pbforums/showthread.php?t=23385[/url] ' (also by author). ' ====================================================================== global hthread() as dword, tid() as dword function testenumthreads () as long ' create some threads which spit out their thread id and go to sleep... local nthreads as long, enumresult as long local i as dword, j as long nthreads = 5 ' five fit on screen nicely redim hthread(nthreads), tid(nthreads) ' these are global arrays for i = 1 to nthreads thread create threadfunction (i) to hthread(i) sleep 500 ' allow stack to clear. should use event, but not worth effort ' for test/demo. see comments above next ' at this point tid() is filled, so show them on the screen print "child thread ids for this process as stored when created:" for i = 1 to nthreads print "thread #" & str$(i) & " threadid=" & str$(tid(i)) next ' call the thread enumeration function and compare visually: print "child thread ids for this process returned by enumeration:" local cbaddr as dword, dwuser as long cbaddr = codeptr (enumcallbackproc) ' this callback looks only for child threads of current process.. dwuser = 999 ' could be anything meaningful ' call the enumerator: call enumsystemthreads (cbaddr, dwuser) to enumresult ' all done, make sure we close our thread handles. we could have done this earlier ' because this function is not using the thread handle. ' note that callback function could obtain a handle itself if needed using openthread. for i = 1 to nthreads thread close hthread(i) to j ' why pb/cc requires the "to" is a true mystery next print "child threads enumerated..."; if isfalse enumresult then print "successfully" else print " with error! could not get thread snapshot." end if end function ' ============================================================================= ' callback function.. called once for each current thread in the system at ' the time of the snapshot. return true to continue enumeration, false to terminate '============================================================================== ' callback for test/demo.. finds all threads of current process other than the calling thread. function enumcallbackproc (byval userdata as long, te32 as threadentry32, byval currentpid as dword, byval callingthreadid as dword) as long if te32.th32ownerprocessid = currentpid then if te32.th32threadid <> callingthreadid then print "enum: child threadid =" & str$(te32.th32threadid) & " userdata=" & str$(userdata) end if end if function = 1 ' set to zero for early termination test. works ok. end function function threadfunction (byval threadno as long) as long local dwtid as dword dwtid = getcurrentthreadid ' save tid of this thread in global array tid(threadno) = dwtid print "thread #:" & str$(threadno) & " id=" & str$(dwtid) & " started and sleeping" sleep 20000 print "thread #:" & str$(threadno) & " done sleeping and terminating" end function ' ==== end of thread enumeration demo program code ==================
------------------
michael mattias
tal systems inc.
racine wi usa
mailto:[email protected][email protected]</a>
www.talsystems.com