Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Enumerate System Threads To Callback

  • Filter
  • Time
  • Show
Clear All
new posts

  • Enumerate System Threads To Callback

    ' 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 ""
    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..."
    end function
    '  structures, equates and declares not found in pb-supplied
    ' 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
                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=""][/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
     ' 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))
     ' 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
     print "child threads enumerated...";
     if isfalse enumresult then
         print "successfully"
         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>
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]