This program is a work-in-progress demonstrating the use the undocumented API calls to the ntdll.dll file to get a list of PID and information about them.

Information like the handle id, granted access, object name,
PID flags, filename and object type.

It is a combination of code from many contributions to mimic some function of the HandleEx.exe and ProceXP.exe from Mark Russinovich at Sysinternals.

Many Thanks to Pierre Bellisle, Semen Matusovski, Nathan Evans, and many others that have contributed snippets and ideas

As usual, use at your own risk. Comments, questions, and discussion can be found in the PowerBasic for Windows forum under Process Handles? via NtDll or PsApi?

NOTE: Named-Pipes that are in a "wait" state will lock-up a thread causing a memory-leak when the program is closed, so I added a work-around to skip asking these items if I can determine that it is a named pipe. (Still not perfect, but stops the leaks)

I commented practically anything I could think of (including stuff I do not understand yet) so it should be pretty easy to follow
Code:
#COMPILE EXE                       '#Win 8.03#
#INCLUDE "win32api.inc"            '#2005-01-27#
#OPTION VERSION5                   'Windows 2000 or higher
'---------------------------------------------------------------------------
' GLOBALS
'---------------------------------------------------------------------------
GLOBAL hDlg     AS DWORD           'Handle for the dialog
GLOBAL hList    AS DWORD           'Handle for the listbox to show results
GLOBAL hProcess AS DWORD           'Handle for process

GLOBAL sObjName AS STRING          'Object name <-- Core Point of demo to find the correct results without lockup or memory leaks

'---------------------------------------------------------------------------
' APPLICATION TITLE
'---------------------------------------------------------------------------
$Title = "Enum Processes, Get Handles, Get Object Names"
'---------------------------------------------------------------------------
' DIALOG CONSTANTS
'---------------------------------------------------------------------------
%Grip         = 101
%Listbox      = 201
'%Checkbox     = 301
%Combobox     = 401
%ButtonSearch = 501
%ButtonQuery  = 502
%ButtonQuit   = 503
'---------------------------------------------------------------------------
' UN-DOCUMENTED CONSTANTS FOR NTDLL
'---------------------------------------------------------------------------
%ObjectNameInformation       = &h01           '<--- Leading 0 ensures that this is an unsigned value
%SystemHandleInformation     = &h010          '<--- Leading 0 ensures that this is an unsigned value
%STATUS_SUCCESS              = &h00000000     '<--- Leading 0 ensures that this is an unsigned value
%STATUS_MORE_ENTRIES         = &h00000105     '<--- Leading 0 ensures that this is an unsigned value
%STATUS_INFO_LENGTH_MISMATCH = &h0C0000004    '<--- Leading 0 ensures that this is an unsigned value
%STATUS_BUFFER_OVERFLOW      = &h080000005    '<--- Leading 0 ensures that this is an unsigned value
%STATUS_SEVERITY_ERROR       = &h00000003     '<--- Leading 0 ensures that this is an unsigned value

%IOCTL_KERNELMEMORY_GETOBJECTNAME = &H080002004   '<--- Leading 0 ensures that this is an unsigned value
'---------------------------------------------------------------------------
' UN-DOCUMENTED USER DEFINED TYPES (UDT's) FOR NTDLL
'---------------------------------------------------------------------------
TYPE SYSTEM_HANDLE_INFORMATION          'System Handle Information Class is &h10     <--- If my guess is right Object Information is &h01
     ProcessID        AS DWORD          'ID of the Process
     ObjectTypeNumber AS BYTE           'Number to indicate the type of Object
     Flags            AS BYTE           'Flags (0x00 = None, 0x01 = Protect_from_close, 0x02 = Inherit)
'     HANDLE           AS WORD          '<--- HANDLE is a PB reserved word (but not documented in WinHelp2000) use another variable
'     OBJECT           AS DWORD         '<--- OBJECT is a PB reserved word (WinHelp2000 says for COM (activex) use), use another variable
     SysHandle        AS WORD           '<--- To replace HANDLE above
     SysObjectAddr    AS DWORD          '<--- To replace OBJECT above
     GrantedAccess    AS DWORD          'User Permissions
END TYPE

TYPE SYSTEM_HANDLE_TABLE_ENTRY_INFO
     NumberOfHandles AS DWORD                          'Number of Handles in the system (the WHOLE SYSTEM)
'     HANDLES(0 TO 0) AS SYSTEM_HANDLE_INFORMATION     'HANDLES is a PB reserved word, use another (see PB Help-File for SHELL commands)
     SysHandles(0 TO 0) AS SYSTEM_HANDLE_INFORMATION   'To replace HANDLES above
END TYPE

TYPE UNICODE_STRING
     Length        AS WORD                             'Length in bytes of string in Buffer
     MaximumLength AS WORD                             'Maximum length in bytes of Buffer
     pBuffer       AS DWORD                            'Pointer to unicode string
END TYPE

'---------------------------------------------------------------------------
' UN-DOCUMENTED NTDLL FUNCTION CALLS
'---------------------------------------------------------------------------
DECLARE FUNCTION NtQuerySystemInformation LIB "NtDLL.DLL" ALIAS "NtQuerySystemInformation"( _
                         BYVAL SystemInformationClass  AS DWORD, _
                         BYVAL SystemInformation       AS DWORD, _
                         BYVAL SystemInformationLength AS DWORD, _
                         BYREF ReturnLength            AS DWORD) AS LONG

DECLARE FUNCTION NtQueryObject LIB "NtDLL.DLL" ALIAS "NtQueryObject"( _
                         BYVAL hndl                    AS DWORD, _
                         BYVAL ObjectInformationClass  AS DWORD, _
                         BYVAL ObjectInformation       AS DWORD, _
                         BYVAL ObjectInformationLength AS DWORD, _
                         BYREF ReturnLength            AS DWORD) AS LONG

'NtClose issuperseded by CloseHandle
'DECLARE FUNCTION NtClose LIB "NtDLL.DLL" ALIAS "NtClose"(BYVAL hndl AS DWORD) AS LONG  'STATUS_SUCCESS if handle was closed.

'---------------------------------------------------------------------------
' PSAPI FUNCTION CALLS
'---------------------------------------------------------------------------
DECLARE FUNCTION EnumProcessModules LIB "PsApi.DLL" ALIAS "EnumProcessModules"( _
                         BYVAL hProcess  AS DWORD, _
                         BYVAL lphModule AS DWORD, _
                         BYVAL cb        AS DWORD, _
                         BYREF cbNeeded  AS DWORD) AS LONG

DECLARE FUNCTION GetModuleFileNameEx LIB "PsApi.DLL" ALIAS "GetModuleFileNameExA"( _
                         BYVAL hProcess AS DWORD, _
                         BYVAL hModule  AS DWORD, _
                         lpFilename     AS ASCIIZ, _
                         BYVAL nSize    AS DWORD) AS LONG

'---------------------------------------------------------------------------
' WRAPPER FUNCTIONS
'---------------------------------------------------------------------------
'DECLARE FUNCTION CancelIo LIB "KERNEL32.DLL" ALIAS "CancelIo" (BYVAL hFile AS DWORD) AS LONG       '<--- Wound up not using this API missing from WinHlp32.hlp
DECLARE FUNCTION pidEnum AS LONG
DECLARE FUNCTION pidGetFileName(PID AS DWORD) AS STRING
DECLARE FUNCTION pidGetObjectNameThread(hPort AS DWORD) AS LONG
DECLARE FUNCTION pidGetObjectName(ProcessId AS DWORD, Hndl AS WORD) AS LONG
'DECLARE FUNCTION LoadPrivilege(BYVAL sPrivilege AS STRING) AS LONG                                 '<--- Uncomment if found it is later needed
DECLARE FUNCTION SetHorizontalListboxBar() AS LONG
DECLARE FUNCTION ListAdd(AddToList AS STRING) AS LONG
DECLARE CALLBACK FUNCTION DlgProc
DECLARE FUNCTION PBMAIN AS LONG
'---------------------------------------------------------------------------
' EXTRA WRAPPER FUNCTIONS (MOSTLY FOR SORTING DATA)
'---------------------------------------------------------------------------
DECLARE FUNCTION GetProcessID(ProcessId AS DWORD) AS STRING
DECLARE FUNCTION GetProcessHandle(ProcessHandle AS WORD) AS STRING

DECLARE FUNCTION GetProcessAccess(ProcessAccess AS DWORD) AS STRING
DECLARE FUNCTION SortAccessGranted(GrantedAccessValue AS LONG) AS STRING

DECLARE FUNCTION GetProcessObjAddress(ProcessObjAddress AS DWORD) AS STRING

DECLARE FUNCTION GetProcessObjFlags(ProcessObjFlags AS BYTE) AS STRING
DECLARE FUNCTION SortObjectFlags(ObjectFlags AS BYTE) AS STRING

DECLARE FUNCTION GetProcessObjType(ProcessObjType AS BYTE) AS STRING
DECLARE FUNCTION SortObjectTypeName(BYVAL ObjectType AS LONG) AS STRING

FUNCTION pidEnum AS LONG                                                        'Main function to get data
     LOCAL pInfoTable  AS SYSTEM_HANDLE_TABLE_ENTRY_INFO POINTER                'System holds a table of each process and whats involved in that process
     LOCAL sBuffer     AS STRING
     LOCAL sObjectType AS STRING
     LOCAL sFileName   AS STRING
     LOCAL pBuffer     AS DWORD PTR
     LOCAL LenBuffer   AS DWORD
     LOCAL ByteNeeded  AS DWORD
     LOCAL InfoCount   AS DWORD
     LOCAL Looper      AS DWORD
     LOCAL AllHandle   AS LONG
     LOCAL Retval      AS LONG

     LOCAL ProcNumber         AS STRING
     LOCAL ProcId             AS STRING
     LOCAL ProcHandle         AS STRING
     LOCAL ProcAccess         AS STRING
     LOCAL ProcObjAddress     AS STRING
     LOCAL ProcObjFlags       AS STRING
     LOCAL ProcObjTypeName    AS STRING
     LOCAL ProcObjAttrib      AS STRING
     LOCAL ProcObjName        AS STRING

LOCAL ShowPort AS LONG

     ByteNeeded = SIZEOF(SYSTEM_HANDLE_TABLE_ENTRY_INFO)                        'Minimum buffer size for a valid ByteNeeded
     FOR Looper = 1 TO 2                                                        'Call once to get the bytes needed, call again to get actual info
          LenBuffer = ByteNeeded
          sBuffer = NUL$(ByteNeeded)
          pBuffer = STRPTR(sBuffer)
          Retval = NtQuerySystemInformation(%SystemHandleInformation, pBuffer, LenBuffer, ByteNeeded)
     NEXT
'*** Get needed info
     pInfoTable = pBuffer                                                       'Fill my table with the info in the pointer to the real table
     InfoCount  = @pInfoTable.NumberOfHandles                                   'Get the Number of handles in the system
'*** Display purposes
     Retval = SendMessage(hList, %LB_INITSTORAGE, InfoCount * 4, InfoCount * 200) 'Faster listbox filling
     DIM Info(1 TO InfoCount) AS SYSTEM_HANDLE_INFORMATION AT pInfoTable + 4    '+ 4 to start just after .NumberOfHandles <--- Not sure what the AT part means yet (unless a pointer offset?)
     FOR Looper = 1 TO InfoCount                                                'For each Handle found in the system
          sFileName = pidGetFileName(Info(Looper).ProcessID)                    'Get the file name of what owns the handle
          IF INSTR(UCASE$(sFileName), UCASE$("Process")) THEN ITERATE        '<--- Do NOT iterate any copies of this program (exponentially grows each copy)

'************** Comment out the below, if you wish to see these files **********
          IF INSTR(UCASE$(sFileName), UCASE$("SYSTEM")) THEN ITERATE            '<--- Nothing returns from System anyways when getting object name
          IF INSTR(UCASE$(sFileName), UCASE$("WINLOGON")) THEN ITERATE          '<--- Nothing returns from WinLogon anyways when getting object name
          IF INSTR(UCASE$(sFileName), UCASE$("SERVICES")) THEN ITERATE          '<--- Nothing returns from Services anyways when getting object name
          IF INSTR(UCASE$(sFileName), UCASE$("LSASS")) THEN ITERATE             '<--- Nothing returns from Lsass anyways when getting object name
          IF INSTR(UCASE$(sFileName), UCASE$("SVCHOST")) THEN ITERATE           '<--- Nothing returns from SvcHost anyways when getting object name
          IF INSTR(UCASE$(sFileName), UCASE$("TASKMGR")) THEN ITERATE           '<--- Why get handles from Windows Task Manager?
'************************************ END COMMENT-OUT **************************

'*** Process Info
          ProcNumber = "Number: "    & FORMAT$(Looper)
'IF Info(Looper).ProcessID = 109996 THEN MSGBOX STR$(Info(Looper).ProcessID)
          ProcId = GetProcessId(Info(Looper).ProcessID)
          ProcHandle = GetProcessHandle(Info(Looper).SysHandle)
          ProcAccess = GetProcessAccess(Info(Looper).GrantedAccess)
'*** Object Info
          ProcObjAddress = GetProcessObjAddress(Info(Looper).SysObjectAddr)
          ProcObjFlags = GetProcessObjFlags(Info(Looper).Flags)                                        '0x00 = None, 0x01 = Protect_from_close, 0x02 = Inherit
          ProcObjTypeName = GetProcessObjType(Info(Looper).ObjectTypeNumber)
'*** Originally I thought one of the below commented cases was causing the memory leak
'          IF INSTR(UCASE$(ProcObjTypeName), UCASE$("Semaphore")) THEN ITERATE
'          IF INSTR(UCASE$(ProcObjTypeName), UCASE$("Thread")) THEN ITERATE
'          IF INSTR(UCASE$(ProcObjTypeName), UCASE$("IoCompletion")) THEN ITERATE
'          IF INSTR(UCASE$(ProcObjTypeName), UCASE$("Timer")) THEN ITERATE
'          IF INSTR(UCASE$(ProcObjTypeName), UCASE$("Event")) THEN ITERATE
'
'
'''*** In My case I am only after what Windows reports as "Files" but may really be a Serial Port or a USB port
''          IF INSTR(UCASE$(ProcObjTypeName), UCASE$("File")) THEN
''               IF INSTR(UCASE$(ProcAccess), UCASE$("%SYNCHRONIZE")) THEN
''                    IF INSTR(UCASE$(ProcAccess), UCASE$("%PROCESS_DUP_HANDLE")) THEN
''                         'Do Nothing
''                    ELSEIF INSTR(UCASE$(ProcAccess), UCASE$("%PROCESS_VM_READ")) THEN
''                         'Do Nothing
''                    ELSE
''                         ITERATE
''                    END IF
''               ELSEIF INSTR(UCASE$(ProcAccess), UCASE$("%PROCESS_ALL_ACCESS")) THEN
'''                    IF INSTR(UCASE$(ProcAccess), UCASE$("%PROCESS_DUP_HANDLE")) THEN
''                    IF INSTR(UCASE$(ProcObjFlags), UCASE$("(Inherit)")) THEN
''                         'Do Nothing
''                    ELSEIF INSTR(UCASE$(ProcAccess), UCASE$("%PROCESS_DUP_HANDLE")) THEN
''                         'Do Nothing
''                    ELSEIF INSTR(UCASE$(ProcAccess), UCASE$("%PROCESS_VM_READ")) THEN
''                         'Do Nothing
''
'''*** No memory leak if commented out, so currently I believe that the following holds true
'''*** 1.) Named pipes that lock-up just asking what the object name is due to one (or more) of the access flags except %PROCESS_DUP_HANDLE
'''*** 2.) Files that are Inherited do not seem to lock-up, so for the time being I have to assume named-pipes are not inherited
'''*** 3.) Odd how my own program can be no flags on one computer and inherited on another <--- Need to research this
'''*** 4.) Whatever named pipe(s) that are locking have the same access flags as files that do not lock <--- Need to find a workaround for this
'''                    ELSEIF INSTR(UCASE$(ProcAccess), UCASE$("%PROCESS_VM_READ")) THEN
''                         'Do Nothing
''                    ELSE
''                         ITERATE        'If a possible lock-up file (like named-pipes) then skip gathering info on it
''                    END IF
''               ELSE
''                    ITERATE             'If a combination of access flags that I have not run into yet, then skip asking for info
''               END IF
''          ELSE
''               ITERATE                  'If not a "File" (only after files at the moment), then skip asking for info
''          END IF

''*** Get the object name if passed the above checks if possibly a named-pipe that will lock just by asking if a named pipe
          pidGetObjectName(Info(Looper).ProcessID, Info(Looper).SysHandle)      'Get the object name of each handle contained in each process'*** Display Results

'*************************** Uncomment if looking for only certain results *********************************
''*** Since I am after Serial Ports, USB Ports, and USB-RS232 Adapters I added the below filters
'          SELECT CASE INSTR(UCASE$(sObjName), UCASE$("SERIAL"))
'               CASE 0
'                    ShowPort = %False
'                    SELECT CASE INSTR(UCASE$(sObjName), UCASE$("edgeser"))
'                         CASE 0
'                              ShowPort = %False
'                              SELECT CASE INSTR(UCASE$(sObjName), UCASE$("USBPDO"))
'                                   CASE 0
'                                        ShowPort = %False
'                                   CASE ELSE
'                                        ShowPort = %True
'                              END SELECT
'                         CASE ELSE
'                              ShowPort = %True
'                    END SELECT
'               CASE ELSE
'                    ShowPort = %True
'          END SELECT
'*************************** END UNCOMMENTED BLOCK *********************************

''*** If it matches one of the above filters, then show the information
          SELECT CASE ShowPort
               CASE %False
               CASE %True
'*** Display Process Info
                    ListAdd   ProcNumber     & $TAB & _
                              ProcId         & $TAB & _
                              ProcHandle     & $TAB & _
                              UCASE$(MID$(sFileName , INSTR(-1, sFileName, ANY ":/\") + 1))    'Process Name without path
'*** Display Handle Object Info
                    ListAdd   $TAB & ProcAccess
                    ListAdd   $TAB & ProcObjAddress & $TAB & _
                              ProcObjFlags   & $TAB & _
                              ProcObjTypeName
                    IF LEN(sFileName) THEN ListAdd "   " & sFileName
                    IF LEN(sObjName) THEN
                         ListAdd "   " & sObjName
                    ELSE
                         ListAdd "   ObjName: Unknown"
                    END IF
'*** Display a line and a blank line for readabilty sake
                    ListAdd STRING$(255,"-")
                    ListAdd ""
          END SELECT
     NEXT Looper
'*** Display total found so you know enumeration is complete
     DIALOG SET TEXT hDlg, $Title & " -" & STR$(InfoCount) & " handles found"
END FUNCTION
'______________________________________________________________________________

'______________________________________________________________________________
FUNCTION pidGetFileName(PID AS DWORD) AS STRING
     LOCAL ModuleName  AS STRING
     LOCAL PidPath     AS STRING
     LOCAL sBuffer     AS STRING
     LOCAL pBuffer     AS DWORD PTR
     LOCAL LenBuffer   AS DWORD
'     LOCAL hProcess    AS DWORD        'Moved to global variable for use in other functions
     LOCAL ByteNeeded  AS DWORD
     LOCAL HandleCount AS DWORD
     LOCAL Looper      AS LONG
     LOCAL Retval      AS LONG

     hProcess = OpenProcess(%PROCESS_QUERY_INFORMATION OR %PROCESS_VM_READ, 0, Pid)
     IF hProcess THEN
          ByteNeeded = SIZEOF(ByteNeeded)              'SIZEOF(ByteNeeded) = 4 = SIZEOF(DWORD)
          FOR Looper = 1 TO 2                          'Call once to get bytes needed, call again to get actual info
               LenBuffer = ByteNeeded
               sBuffer = NUL$(ByteNeeded)
               pBuffer = STRPTR(sBuffer)
               Retval = EnumProcessModules(hProcess, pBuffer, LenBuffer, ByteNeeded)      'Get number of modules contained in process
          NEXT Looper
          IF Retval THEN
               HandleCount = LenBuffer \ SIZEOF(ByteNeeded)                'LenBuffer \ SIZEOF(ByteNeeded) = LenBuffer \ 4
               DIM ModulesHandles(1 TO HandleCount) AS DWORD AT pBuffer
               ModuleName = "Unknown" & NUL$(%MAX_PATH)
               Retval = GetModuleFileNameEx(hProcess, ModulesHandles(1), BYVAL STRPTR(ModuleName), %MAX_PATH)
               PidPath = "FileName: " & LEFT$(ModuleName, Retval)
          ELSE
     '          ListAdd  "Bad EnumProcessModules"
          END IF
          CloseHandle hProcess
     END IF
     IF PidPath = "" THEN PidPath = "FileName: SYSTEM"           '<--- System files try to protect themselves from queries
     FUNCTION = PidPath
END FUNCTION
'______________________________________________________________________________

FUNCTION pidGetObjectNameThread(hPort AS DWORD) AS LONG
     LOCAL puString   AS UNICODE_STRING POINTER
     LOCAL sBuffer    AS STRING
     LOCAL pzBuffer   AS ASCIIZ POINTER
     LOCAL psBuffer   AS DWORD POINTER
     LOCAL LenBuffer  AS DWORD
     LOCAL ByteNeeded AS DWORD
     LOCAL ByteCount  AS DWORD
     LOCAL Looper     AS LONG
     LOCAL Retval     AS LONG

     DIM lResult AS LONG
     DIM ErrorBuff AS ASCIIZ * %MAX_PATH

     LOCAL OverlappedFlags AS OVERLAPPED          '<--- Used in DeviceIoControl to get ring 0 driver information

     ByteNeeded = SIZEOF(UNICODE_STRING)
'     CancelIo hPort
     FOR Looper = 1 TO 2                          'Call once to get bytes needed, call again to get actual info
          LenBuffer = ByteNeeded
          sBuffer = NUL$(ByteNeeded)
          psBuffer = STRPTR(sBuffer)
'          Retval = NtQueryObject(hPort, %ObjectNameInformation, psBuffer, LenBuffer, ByteNeeded)   '<--- Will lock up Named-Pipe
          IF PeekNamedPipe (hPort, BYVAL 0, 0, pzBuffer, LenBuffer, ByteNeeded) = 0 THEN            'If not a named pipe
               Retval = NtQueryObject(hPort, %ObjectNameInformation, psBuffer, LenBuffer, ByteNeeded)    'Get the object name
          ELSE
               sObjName = "Named-Pipe data: " & @pzBuffer + " at " + STR$(hPort)        'Do not query if a named pipe (named pipes return a nonzero reply to PeekNamedPipe)
          END IF
     NEXT
     IF Retval = %STATUS_SUCCESS THEN        'If success then format reply
          puString = psBuffer
          IF @puString.Length > 0 THEN
               sObjName = NUL$(@puString.Length \ 2)
               WideCharToMultiByte %CP_ACP, %NULL, BYVAL @puString.pBuffer, @puString.Length, _
                         BYVAL STRPTR(sObjName), LEN(sObjName), BYVAL %NULL, BYVAL %NULL            '<--- Learn what this does, and do I need it? (1 char = 2 bytes instead of 1 byte)
               sObjName = "ObjName: " & sObjName
          ELSE      'No error but no response?
               lResult = GetLastError()
               FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, lResult, %NULL, ErrorBuff, SIZEOF(ErrorBuff), BYVAL %NULL
               sObjName = "ObjName: Error Code - " & STR$(lResult) & " - " & ErrorBuff
          END IF
     ELSE                                    'If failure, then try getting the info from ring 0 driver
          RetVal = DeviceIoControl(hProcess, %IOCTL_KERNELMEMORY_GETOBJECTNAME,  hPort, SIZEOF(hPort), psBuffer, LenBuffer, ByteNeeded, OverlappedFlags)
          IF Retval = %STATUS_SUCCESS THEN
               puString = psBuffer
               IF @puString.Length > 0 THEN
                    sObjName = NUL$(@puString.Length \ 2)
                    WideCharToMultiByte %CP_ACP, %NULL, BYVAL @puString.pBuffer, @puString.Length, _
                              BYVAL STRPTR(sObjName), LEN(sObjName), BYVAL %NULL, BYVAL %NULL            '<--- Learn what this does, and do I need it? (1 char = 2 bytes instead of 1 byte)
                    sObjName = "ObjName from DeviceIoControl: " & sObjName
               END IF
          ELSE
               lResult = GetLastError()
               FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, lResult, %NULL, ErrorBuff, SIZEOF(ErrorBuff), BYVAL %NULL
               sObjName = "ObjName from DeviceIoControl: Error Code - " & STR$(lResult) & " - "  & ErrorBuff
          END IF
     END IF
END FUNCTION
'______________________________________________________________________________

FUNCTION pidGetObjectName(ProcessId AS DWORD, Hndl AS WORD) AS LONG
     LOCAL hPort      AS DWORD
     LOCAL hProc      AS DWORD
     LOCAL idThread   AS DWORD
     LOCAL hThread    AS DWORD
     LOCAL Retval     AS LONG

     DIM lResult AS LONG
     DIM ErrorBuff AS ASCIIZ * %MAX_PATH

     sObjName = ""
     IF ProcessId THEN
          hProc = OpenProcess(%PROCESS_DUP_HANDLE, 0, ProcessId)
          IF (hProc <> %INVALID_HANDLE_VALUE) AND (hProc <> 0) THEN
               IF DuplicateHandle(hProc, BYVAL Hndl, -1, hPort, 0, %PROCESS_ALL_ACCESS, %DUPLICATE_SAME_ACCESS) THEN
                    hThread = CreateThread(BYVAL %NULL, 0, CODEPTR(pidGetObjectNameThread), BYREF hPort, _
                              %THREAD_TERMINATE OR %THREAD_QUERY_INFORMATION, BYVAL VARPTR(idThread))
                    Retval = WaitForSingleObjectEx(hThread, 50, %TRUE) 'Adjust TimeOut Time as needed to ensure reply from thread
                    SELECT CASE RetVal
                         CASE %WAIT_FAILED
                              lResult = GetLastError()
                              FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, lResult, %NULL, ErrorBuff, SIZEOF(ErrorBuff), BYVAL %NULL
                              sObjName = "ObjName: %WAIT_FAILED Error Code - " & STR$(lResult) & " - " & ErrorBuff
                         CASE %WAIT_ABANDONED
                              lResult = GetLastError()
                              FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, lResult, %NULL, ErrorBuff, SIZEOF(ErrorBuff), BYVAL %NULL
                              sObjName = "ObjName: %WAIT_ABANDONED Error Code - " & STR$(lResult) & " - " & ErrorBuff
                         CASE %WAIT_OBJECT_0                          'Success I think?
                         CASE %WAIT_TIMEOUT                           'Failure            <--- Check into the other timeout values
                              CloseHandle hThread                          'Close the thread
                              lResult = GetLastError()
                              FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, lResult, %NULL, ErrorBuff, SIZEOF(ErrorBuff), BYVAL %NULL
                              sObjName = "ObjName: %WAIT_TIMEOUT Error Code - " & STR$(lResult) & " - " & ErrorBuff
                         CASE ELSE
                              lResult = GetLastError()
                              FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, lResult, %NULL, ErrorBuff, SIZEOF(ErrorBuff), BYVAL %NULL
                              sObjName = "ObjName: Unknow Wait Error - Error Code - " & STR$(lResult) & " - " & ErrorBuff
                    END SELECT
                    Retval = TerminateThread(hThread, 0)              'Terminate the thread now that I am done with it
                    CloseHandle hPort                                 'Close the handle
               ELSE
                    lResult = GetLastError()
                    FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, lResult, %NULL, ErrorBuff, SIZEOF(ErrorBuff), BYVAL %NULL
                    sObjName = "ObjName: Error Code - " & STR$(lResult) & " - " & ErrorBuff
               END IF
               CloseHandle hProc                                      'Close the process
          ELSE
               lResult = GetLastError()
               FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, lResult, %NULL, ErrorBuff, SIZEOF(ErrorBuff), BYVAL %NULL
               sObjName = "ObjName: Error Code - " & STR$(lResult) & " - " & ErrorBuff
          END IF
     END IF
END FUNCTION
'______________________________________________________________________________

'*** Re-Enable if needed later
'FUNCTION LoadPrivilege(BYVAL sPrivilege AS STRING) AS LONG
' LOCAL  TokenPrivilege   AS TOKEN_PRIVILEGES
' LOCAL  SEDebugNameValue AS LUID
' LOCAL  hToken           AS DWORD
' LOCAL  hProcessHandle   AS DWORD
'
' hProcessHandle = GetCurrentProcess()
' IF hProcessHandle THEN
'   OpenProcessToken hProcessHandle, (%TOKEN_ADJUST_PRIVILEGES OR %TOKEN_QUERY), hToken
'   IF hToken THEN
'     IF LookupPrivilegeValue("", BYCOPY sPrivilege, SEDebugNameValue) THEN
'       TokenPrivilege.PrivilegeCount = 1
'       TokenPrivilege.Privileges(0).pLuid = SEDebugNameValue
'       TokenPrivilege.Privileges(0).Attributes = %SE_PRIVILEGE_ENABLED
'       IF AdjustTokenPrivileges(hToken, %False, TokenPrivilege, SIZEOF(TokenPrivilege), _
'                                BYVAL 0, BYVAL 0) THEN
'         FUNCTION = %TRUE
'       ELSE
'         MSGBOX "AdjustTokenPrivileges, Error: " & FORMAT$(GetLastError())
'       END IF
'     ELSE
'       MSGBOX "LookupPrivilegeValue, Error: " & FORMAT$(GetLastError())
'     END IF
'   ELSE
'     MSGBOX "OpenProcessToken, Error: " & FORMAT$(GetLastError())
'   END IF
' ELSE
'   MSGBOX "GetCurrentProcess, Error: " & FORMAT$(GetLastError())
' END IF
'
'END FUNCTION
''______________________________________________________________________________

CALLBACK FUNCTION DlgProc
     LOCAL MinMaxInfoPtr AS MINMAXINFO POINTER
     LOCAL sBuffer       AS STRING
     LOCAL sTextbox      AS STRING
     LOCAL ListTabStop() AS LONG
     LOCAL Counter       AS LONG
     LOCAL Retval        AS LONG
     LOCAL LastItem      AS LONG
     LOCAL TextLen       AS LONG
     LOCAL Looper        AS LONG
     LOCAL Found         AS LONG
     STATIC Index        AS LONG

     SELECT CASE CBMSG
          CASE %WM_INITDIALOG
               CONTROL HANDLE hDlg, %Listbox TO hList
          CASE %WM_COMMAND
               SELECT CASE LOWRD(CBWPARAM)
                    CASE %ButtonQuery
                         IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
'                              CONTROL DISABLE hDlg, %Checkbox
                              CONTROL DISABLE hDlg, %Combobox
                              CONTROL DISABLE hDlg, %ButtonQuit
                              CONTROL DISABLE hDlg, %ButtonQuery
                              CONTROL DISABLE hDlg, %ButtonSearch
                              LISTBOX RESET CBHNDL, %Listbox
                              DIALOG SET TEXT CBHNDL, $Title & " - Please wait..."
                              CONTROL REDRAW CBHNDL, %Listbox
                              SLEEP 300
                              pidEnum             'Start the process to enum all processes and handles
                              SetHorizontalListboxBar  'Set the scrollbar when done
                              CONTROL ENABLE hDlg, %ButtonSearch
                              CONTROL ENABLE hDlg, %ButtonQuery
                              CONTROL ENABLE hDlg, %ButtonQuit
                              CONTROL ENABLE hDlg, %Combobox
'                              CONTROL ENABLE hDlg, %Checkbox
                         END IF

                    CASE %ButtonSearch, %IDOK
                         IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                              CONTROL GET TEXT CBHNDL, %Combobox TO sTextbox
                              IF LEN(sTextbox) THEN
                                   sTextbox = UCASE$(sTextbox)
                                   LastItem = SendMessage(hList, %LB_GETCOUNT, 0, 0) - 1
                                   IF LastItem > 0 THEN
                                        IF Index = LastItem THEN Index = -1
                                        INCR Index
                                        FOR Looper = Index TO LastItem
                                             TextLen = SendMessage(hList, %LB_GETTEXTLEN, Looper, 0)
                                             IF TextLen THEN
                                                  sBuffer = NUL$(TextLen)
                                                  SendMessage hList, %LB_GETTEXT, Looper, STRPTR(sBuffer)
                                                  sBuffer = UCASE$(sBuffer)
                                                  IF INSTR(sBuffer, sTextbox) THEN
                                                       Index = Looper
                                                       Found = %TRUE
                                                       SendMessage hList, %LB_SETCURSEL, Index, 0
                                                       EXIT FOR
                                                  END IF
                                             END IF
                                        NEXT
                                        IF Found = %FALSE THEN
                                             FOR Looper = 0 TO Index
                                                  TextLen = SendMessage(hList, %LB_GETTEXTLEN, Looper, 0)
                                                  IF TextLen THEN
                                                       sBuffer = NUL$(TextLen)
                                                       SendMessage hList, %LB_GETTEXT, Looper, STRPTR(sBuffer)
                                                       sBuffer = UCASE$(sBuffer)
                                                       IF INSTR(sBuffer, sTextbox) THEN
                                                            Index = Looper
                                                            Found = %TRUE
                                                            SendMessage hList, %LB_SETCURSEL, Index, 0
                                                            EXIT FOR
                                                       END IF
                                                  END IF
                                             NEXT
                                        END IF
                                        IF Found = %FALSE THEN BEEP
                                   END IF
                              END IF
                         END IF
                    CASE %ButtonQuit, %IDCANCEL
                         IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN DIALOG END CBHNDL
                    CASE %Listbox
                         IF CBCTLMSG = %LBN_SELCHANGE THEN
                              Retval = SendMessage(hList, %LB_GETCURSEL, 0, 0)
                              IF Retval > -1 THEN
                                   Index = Retval
                              END IF
                         END IF
               END SELECT
          CASE %WM_SIZE 'Resize and repos controls if parent is resized
               MoveWindow hList, 10, 10, LOWRD(CBLPARAM) - 20, HIWRD(CBLPARAM) - 50, %TRUE
'               MoveWindow GetDlgItem(CBHNDL, %Checkbox), LOWRD(CBLPARAM) - 490, _      'Hor,
'                                   HIWRD(CBLPARAM) - 34, 115, 24, %TRUE              'Vert, W, H
               MoveWindow GetDlgItem(CBHNDL, %Combobox), LOWRD(CBLPARAM) - 365, _      'Hor,
                                     HIWRD(CBLPARAM) - 33, 120, 225, %TRUE             'Vert, W, H
               MoveWindow GetDlgItem(CBHNDL, %ButtonSearch), LOWRD(CBLPARAM) - 230, _  'Hor,
                                     HIWRD(CBLPARAM) - 33, 60, 24, %TRUE               'Vert, W, H
               MoveWindow GetDlgItem(CBHNDL, %ButtonQuery), LOWRD(CBLPARAM) - 155, _   'Hor,
                                     HIWRD(CBLPARAM) - 33, 60, 24, %TRUE               'Vert, W, H
               MoveWindow GetDlgItem(CBHNDL, %ButtonQuit), LOWRD(CBLPARAM) - 80, _     'Hor,
                                     HIWRD(CBLPARAM) - 33, 60, 24, %TRUE               'Vert, W, H
               MoveWindow GetDlgItem(CBHNDL, %Grip), LOWRD(CBLPARAM) - 15, _           'Hor,
                                     HIWRD(CBLPARAM) - 15, 15, 15, %TRUE               'Vert, W, H
               SetHorizontalListboxBar
               DIALOG REDRAW hDlg
               FUNCTION = 0
               EXIT FUNCTION
          CASE %WM_GETMINMAXINFO
               MinMaxInfoPtr = CBLPARAM
               @MinMaxInfoPtr.ptMinTrackSize.x = 402
               @MinMaxInfoPtr.ptMinTrackSize.y = 180
     END SELECT
END FUNCTION
'______________________________________________________________________________

FUNCTION PBMAIN AS LONG
LOCAL PrivilegeOk AS LONG
'*** Figure out what priviledges there are                                 <--- Next step in beefing up the sample code
'PrivilegeOk = LoadPrivilege($SE_DEBUG_NAME) 'Debug privileges
'PrivilegeOk = LoadPrivilege($SE_LOAD_DRIVER_NAME) 'Load driver privileges

     DIALOG NEW %HWND_DESKTOP, "QuerySystemInformation", , , 600, 300, _
                              %WS_VISIBLE OR %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_CAPTION OR _
                              %WS_SYSMENU OR %WS_THICKFRAME OR %WS_MINIMIZEBOX OR _
                              %WS_MAXIMIZEBOX, %WS_EX_WINDOWEDGE TO hDlg

     CONTROL ADD LISTBOX, hdlg, %Listbox , , 10, 10, 580, 280, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_BORDER OR %WS_VSCROLL OR %WS_HSCROLL OR _
                              %LBS_NOTIFY OR %WS_TABSTOP OR %LBS_USETABSTOPS, %WS_EX_CLIENTEDGE

'     CONTROL ADD CHECKBOX, hDlg, %Checkbox, "Only with ObjName", 270, 281, 75, 12, _
'                              %BS_LEFT OR %BS_VCENTER OR %WS_TABSTOP, %WS_EX_RIGHT
'     CONTROL SET CHECK hDlg, %Checkbox, %TRUE

     CONTROL ADD COMBOBOX, hDlg, %Combobox, , 338, 281, 100, 50,%CBS_DROPDOWN OR _
                              %WS_TABSTOP OR %CBS_HASSTRINGS OR %CBS_AUTOHSCROLL, %WS_EX_CLIENTEDGE OR %WS_EX_LEFT
     COMBOBOX ADD hDlg, %Combobox, "Serial"
     COMBOBOX ADD hDlg, %Combobox, "Serial0"
     COMBOBOX ADD hDlg, %Combobox, "\Device\Tcp"
     COMBOBOX ADD hDlg, %Combobox, "\Device\Udp"
     COMBOBOX ADD hDlg, %Combobox, "COM"
     COMBOBOX ADD hDlg, %Combobox, "COM1"
     COMBOBOX ADD hDlg, %Combobox, "UltraEdit"
     COMBOBOX ADD hDlg, %Combobox, "PbEdit"
     COMBOBOX ADD hDlg, %Combobox, "Registry"
     COMBOBOX ADD hDlg, %Combobox, "Type 2:"
     COMBOBOX SELECT hDlg, %Combobox, 1

     CONTROL ADD BUTTON, hDlg, %ButtonSearch, "&Search", 418, 280, 45, 15, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
                              %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR %WS_EX_LTRREADING
     CONTROL DISABLE hDlg, %ButtonSearch

     CONTROL ADD BUTTON, hDlg, %ButtonQuery, "&Query", 478, 280, 45, 15, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
                              %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR %WS_EX_LTRREADING

     CONTROL ADD BUTTON, hDlg, %ButtonQuit, "Quit", 538, 280, 45, 15, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_PUSHBUTTON OR _
                              %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR %WS_EX_LTRREADING

     CONTROL ADD SCROLLBAR, hDlg, %Grip, "", 590, 290, 10, 10, %WS_CHILD OR %WS_VISIBLE OR _
                              %SBS_SIZEGRIP OR %SBS_SIZEBOXBOTTOMRIGHTALIGN 'Class: ScrollBar

     SetClassLong hDlg, %GCL_HICON, LoadIcon(BYVAL %NULL, BYVAL %IDI_INFORMATION)
     DIALOG SHOW MODAL hDlg CALL DlgProc
END FUNCTION
'______________________________________________________________________________
FUNCTION GetProcessID(ProcessId AS DWORD) AS STRING
     FUNCTION = " - Pid: "    & FORMAT$(ProcessId)
'     FUNCTION = " - Pid: "    & str$(ProcessId)
END FUNCTION
'______________________________________________________________________________

FUNCTION GetProcessHandle(ProcessHandle AS WORD) AS STRING
     FUNCTION = " - Handle: " & HEX$(ProcessHandle, 16)
END FUNCTION
'______________________________________________________________________________

FUNCTION GetProcessAccess(ProcessAccess AS DWORD) AS STRING
     FUNCTION = " - Access: " &  SortAccessGranted(ProcessAccess)
END FUNCTION

'______________________________________________________________________________
FUNCTION GetProcessObjAddress(ProcessObjAddress AS DWORD) AS STRING
     FUNCTION = " - Object Address: " & HEX$(ProcessObjAddress, 8)
END FUNCTION

'______________________________________________________________________________
FUNCTION GetProcessObjFlags(ProcessObjFlags AS BYTE) AS STRING
     FUNCTION = " - Flags "   & SortObjectFlags(ProcessObjFlags)
END FUNCTION

'______________________________________________________________________________
FUNCTION GetProcessObjType(ProcessObjType AS BYTE) AS STRING
     FUNCTION = " - Type: "    &  SortObjectTypeName(ProcessObjType)
END FUNCTION

'______________________________________________________________________________

FUNCTION SortAccessGranted(GrantedAccessValue AS DWORD) AS STRING
     LOCAL ProcessAccessVal AS DWORD
     LOCAL ProcessAccess AS STRING
     LOCAL TempProcessAccess AS STRING
     LOCAL i AS LONG
'*** Below tables are a sample of the permissions in each Info(Looper).GrantedAccess
'--------------------------------------------------
'    Lo-Byte Lo-Word
'--------------------------------------------------
'*** Pos       8    7    6    5    4    3    2    1
'*** Bit       7    6    5    4    3    2    1    0
'*** Value     128  64   32   16   8    4    2    1
'*** ----------------------------------------------
'              0    0    0    0    0    0    0    1    = &H01 = 1 = %PROCESS_TERMINATE
'              0    0    0    0    0    0    1    0    = &H02 = 2 = %PROCESS_CREATE_THREAD
'              0    0    0    0    0    1    0    0    = &H04 = 4 = %PROCESS_SET_SESSIONID
'              0    0    0    0    1    0    0    0    = &H08 = 8 = %PROCESS_VM_OPERATION
'              0    0    0    1    0    0    0    0    = &H010 = 16 = %PROCESS_VM_READ
'              0    0    1    0    0    0    0    0    = &H020 = 32 = %PROCESS_VM_WRITE
'              0    1    0    0    0    0    0    0    = &H040 = 64 = %PROCESS_DUP_HANDLE
'              1    0    0    0    0    0    0    0    = &H080 = 128 = %PROCESS_CREATE_PROCESS

'              0    0    0    0    0    0    1    1    = &H03 = 3 = %PROCESS_TERMINATE OR %PROCESS_CREATE_THREAD
'              0    0    0    0    0    1    1    1    = &H07 = 7 = %PROCESS_TERMINATE OR %PROCESS_CREATE_THREAD OR %PROCESS_SET_SESSIONID
'              0    0    0    0    1    1    1    1    = &H0F = 15 = %PROCESS_TERMINATE OR %PROCESS_CREATE_THREAD OR %PROCESS_SET_SESSIONID OR %PROCESS_VM_OPERATION
'              0    0    0    1    1    1    1    1    = &H1F = 31 = %PROCESS_TERMINATE OR %PROCESS_CREATE_THREAD OR %PROCESS_SET_SESSIONID OR %PROCESS_VM_OPERATION OR %PROCESS_VM_READ

'              0    0    1    1    1    1    1    1    = &H3F = 63 = %PROCESS_TERMINATE OR %PROCESS_CREATE_THREAD OR %PROCESS_SET_SESSIONID OR %PROCESS_VM_OPERATION OR %PROCESS_VM_READ
'                                                               OR %PROCESS_VM_WRITE
'              0    1    1    1    1    1    1    1    = &H7F = 127 = %PROCESS_TERMINATE OR %PROCESS_CREATE_THREAD OR %PROCESS_SET_SESSIONID OR %PROCESS_VM_OPERATION OR %PROCESS_VM_READ
'                                                               OR %PROCESS_VM_WRITE OR %PROCESS_DUP_HANDLE
'              1    1    1    1    1    1    1    1    = &HFF = 255 = %PROCESS_TERMINATE OR %PROCESS_CREATE_THREAD OR %PROCESS_SET_SESSIONID OR %PROCESS_VM_OPERATION OR %PROCESS_VM_READ
'                                                               OR %PROCESS_VM_WRITE OR %PROCESS_DUP_HANDLE OR %PROCESS_CREATE_PROCESS

'----------------------------------------------------------------------------------------------------
'    Hi-Byte Lo-Word
'----------------------------------------------------------------------------------------------------
'*** Pos       16        15        14        13        12        11        10        9
'*** Bit       15        14        13        12        11        10        9         8
'*** Value     32768     16384     8192      4096      2048      1024      512       256
'*** --------------------------------------------------------------------------------------------
'              0         0         0         0         0         0         0         1    = &H0100 = 256 = %PROCESS_SET_QUOTA
'              0         0         0         0         0         0         1         0    = &H0200 = 512 = %PROCESS_SET_INFORMATION
'*** MANY MORE COMBINATIONS TO FIGURE OUT
'
'
'*** Default the variables used
     ProcessAccessVal = GrantedAccessValue
     ProcessAccess = ""
     TempProcessAccess = ""
'*** Determine Granted Access
'     ProcessAccess = BIN$(Info(Looper).GrantedAccess, 8)   '<--Not 8 but 32 bits in DWORD
     ProcessAccess = BIN$(ProcessAccessVal, 32)             '<--Not 8 but 32 bits in DWORD
     FOR i = 1 TO LEN(ProcessAccess)
          SELECT CASE VAL((MID$(ProcessAccess, i, 1)))       '
               CASE 0    'Bit Not Set
               CASE 1    'Bit Set
                    SELECT CASE i
'*** Hi Byte Hi Word
                         CASE 1         'Bit 31
                         CASE 2         'Bit 30
                         CASE 3         'Bit 29
                         CASE 4         'Bit 28
                         CASE 5         'Bit 27
                         CASE 6         'Bit 26
                         CASE 7         'Bit 25
                         CASE 8         'Bit 24
'*** Lo Byte Hi Word
                         CASE 9         'Bit 23
                         CASE 10        'Bit 22
                         CASE 11        'Bit 21
                         CASE 12        'Bit 20 = &H00100000 = 1048576
                              TempProcessAccess = TempProcessAccess + " %PROCESS_ALL_ACCESS, " '%PROCESS_ALL_ACCESS = %STANDARD_RIGHTS_REQUIRED OR %SYNCHRONIZE OR &H0FFF (4095) = 2035711 = &H01F0FFF
                         CASE 13        'Bit 19 = &H000F0000 = 983040
                              TempProcessAccess = TempProcessAccess + " %SYNCHRONIZE, " '%SYNCHRONIZE
                         CASE 14        'Bit 18
                         CASE 15        'Bit 17 = UNKNOWN
                         CASE 16        'Bit 16 = UNKNOWN
'*** Hi Byte Lo Word
                         CASE 17        'Bit 15 = UNKNOWN
                         CASE 18        'Bit 14 = UNKNOWN
                         CASE 19        'Bit 13 = UNKNOWN
                         CASE 20        'Bit 12 = UNKNOWN
                         CASE 21        'Bit 11 = UNKNOWN
'*** Do NOT look for whatever &H0FFF is because it could be a combo of below
                         CASE 22        'Bit 10 = %PROCESS_QUERY_INFORMATION = &H0400 = 1024
                              TempProcessAccess = TempProcessAccess + " %PROCESS_QUERY_INFORMATION, "
                         CASE 23        'Bit 9 = %PROCESS_SET_INFORMATION = &H0200 = 512
                              TempProcessAccess = TempProcessAccess + " %PROCESS_SET_INFORMATION, "
                         CASE 24        'Bit 8 = %PROCESS_SET_QUOTA = &H0100 = 256
                                   TempProcessAccess = TempProcessAccess + " %PROCESS_SET_QUOTA, "
'*** Lo Byte Lo Word
                         CASE 25        'Bit 7 = %PROCESS_CREATE_PROCESS = &H0080 = 128
                                   TempProcessAccess = TempProcessAccess + " %PROCESS_CREATE_PROCESS, "
                         CASE 26        'Bit 6 = %PROCESS_DUP_HANDLE = &H0040 = 64
                                   TempProcessAccess = TempProcessAccess + " %PROCESS_DUP_HANDLE, "
                         CASE 27        'Bit 5 = %PROCESS_VM_WRITE = &H0020 = 32
                                   TempProcessAccess = TempProcessAccess + " %PROCESS_VM_WRITE, "
                         CASE 28        'Bit 4 = %PROCESS_VM_READ = &H0010 = 16
                                   TempProcessAccess = TempProcessAccess + " %PROCESS_VM_READ, "
                         CASE 29        'Bit 3 = %PROCESS_VM_OPERATION = &H0008 = 8
                                   TempProcessAccess = TempProcessAccess + " %PROCESS_VM_OPERATION, "
                         CASE 30        'Bit 2 = %PROCESS_SET_SESSIONID = &H0004 = 4
                                   TempProcessAccess = TempProcessAccess + " %PROCESS_SET_SESSIONID, "
                         CASE 31        'Bit 1 = %PROCESS_CREATE_THREAD = &H0002 = 2
                                   TempProcessAccess = TempProcessAccess + " %PROCESS_CREATE_THREAD, "
                         CASE 32        'Bit 0 = %PROCESS_TERMINATE = &H0001 = 1
                                   TempProcessAccess = TempProcessAccess + " %PROCESS_TERMINATE, "
                    END SELECT
          END SELECT
     NEXT i
     FUNCTION = "0x" + HEX$(ProcessAccessVal, 32) + " =" + TempProcessAccess    '<--- Cant remember what the signed symbol for hex is but 0x is unsigned
END FUNCTION
'______________________________________________________________________________

FUNCTION SortObjectFlags(ObjectFlags AS BYTE) AS STRING
     SELECT CASE HEX$(ObjectFlags, 1)
          CASE "0"         'None
               FUNCTION = HEX$(ObjectFlags, 1) & " (None)"
          CASE "1"         'Protect_from_close
               FUNCTION = HEX$(ObjectFlags, 1) & " (Protect_from_close)"
          CASE "2"         'Inherit
               FUNCTION = HEX$(ObjectFlags, 1) & " (Inherit)"
     END SELECT
END FUNCTION
'______________________________________________________________________________
FUNCTION SortObjectTypeName(BYVAL ObjectType AS LONG) AS STRING
'Windows < Win95
'--------------------------------------------------------------------------------
'
'               Win 3.1
'PlatformID     0
'Major Version
'Minor Version
'Build
'
'--------------------------------------------------------------------------------
'Windows 95/98/ME
'--------------------------------------------------------------------------------
'               Win     Win     Win
'               95      98      Me
'               ---     ---     ---
'PlatformID     1       1       1
'Major Version  4       4       4
'Minor Version  0       10      90
'Build          950*    1111    1998
'
'--------------------------------------------------------------------------------
'Old Windows NT
'--------------------------------------------------------------------------------
'
'               Win     Win     Win     Win
'               NT      NT      NT      2000
'               3.0     3.1     4
'               ---     ---     ---     ----
'PlatformID     2       2       2       2
'Major Version  3       3       4       5
'Minor Version  0       1       0       0
'Build                          1381    2195
'
'--------------------------------------------------------------------------------
'Windows NT
'--------------------------------------------------------------------------------
'
'               Win     Win     Win
'               2003    XP      VISTA
'PlatformID     2       2       2
'Major Version  5       5       6
'Minor Version  2       1       0
'Build          3790    2600    TBD
'
'--------------------------------------------------------------------------------
     STATIC NtVer AS DWORD
     LOCAL  os AS OSVERSIONINFO

     IF NtVer = 0 THEN
          os.dwOSVersionInfoSize = SIZEOF(os)
          GetVersionEx os
          IF os.dwPlatformId = %VER_PLATFORM_WIN32_NT THEN
               IF os.dwMajorVersion = 4 THEN
                    NtVer = 4  'Window NT 4
               ELSEIF (os.dwMajorVersion = 5) AND (os.dwMinorVersion = 0) THEN
                    NtVer = 50 'Windows 2000
               ELSE
                    NtVer = 51 'Windows XP 5.1
               END IF
          END IF
     END IF
 ' Windows NT 4          Window 2000            Window XP, probably 2003 and Vista          '<--- Many Thanks to Pierre Bellisle for this info
 ' -----------------     -------------------    -------------------
 '  1 - Type              1 - Type               1 - (Type)
 '  2 - Directory         2 - Directory          2 - Directory
 '  3 - SymbolicLink      3 - SymbolicLink       3 - SymbolicLink
 '  4 - Token             4 - Token              4 - Token
 '  5 - Process           5 - Process            5 - Process
 '  6 - Thread            6 - Thread             6 - Thread
 '  7 - Event             7 - Job                7 - Job
 '  8 - EventPair         8 - Event              8 - ((DebugObject))
 '  9 - Mutant            9 - EventPair          9 - Event
 ' 10 - Semaphore        10 - Mutant            10 - (EventPair)
 ' 11 - Timer            11 - Callback          11 - Mutant
 ' 12 - Profile          12 - Semaphore         12 - (Callback)
 ' 13 - WindowStation    13 - Timer             13 - Semaphore
 ' 14 - Desktop          14 - Profile           14 - Timer
 ' 15 - Section          15 - WindowsStation    15 - (Profile)
 ' 16 - Key              16 - Desktop           16 - KeyedEvent
 ' 17 - Port             17 - Section           17 - WindowStation
 ' 18 - Adapter          18 - Key               18 - Desktop
 ' 19 - Controller       19 - Port              19 - Section
 ' 20 - Device           20 - WaitablePort      20 - Key
 ' 21 - Driver           21 - Adapter           21 - Port
 ' 22 - IoCompletion     22 - Controller        22 - WaitablePort
 ' 23 - File             23 - Device            23 - (Adapter)
 '                       24 - Driver            24 - (Controller)
 '                       25 - IoCompletion      25 - (Device)
 '                       26 - File              26 - (Driver)
 '                       27 - WmiGuid           27 - IoCompletion
 '                                              28 - File
 '                                              29 - WmiGuid
     SELECT CASE NtVer
          CASE 4 'Window NT 4
               SELECT CASE ObjectType
                    CASE 01 : FUNCTION =  "1: Type"
                    CASE 02 : FUNCTION =  "2: Directory"
                    CASE 03 : FUNCTION =  "3: SymbolicLink"
                    CASE 04 : FUNCTION =  "4: Token"
                    CASE 05 : FUNCTION =  "5: Process"
                    CASE 06 : FUNCTION =  "6: Thread"
                    CASE 07 : FUNCTION =  "7: Event"
                    CASE 08 : FUNCTION =  "8: EventPair"
                    CASE 09 : FUNCTION =  "9: Mutant"
                    CASE 10 : FUNCTION = "10: Semaphore"
                    CASE 11 : FUNCTION = "11: Timer"
                    CASE 12 : FUNCTION = "12: Profile"
                    CASE 13 : FUNCTION = "13: WindowStation"
                    CASE 14 : FUNCTION = "14: Desktop"
                    CASE 15 : FUNCTION = "15: Section"
                    CASE 16 : FUNCTION = "16: Key"
                    CASE 17 : FUNCTION = "17: Port"
                    CASE 18 : FUNCTION = "18: Adapter"
                    CASE 19 : FUNCTION = "19: Controller"
                    CASE 20 : FUNCTION = "20: Device"
                    CASE 21 : FUNCTION = "21: Driver"
                    CASE 22 : FUNCTION = "22: IoCompletion"
                    CASE 23 : FUNCTION = "23: File"
                    CASE ELSE : FUNCTION = FORMAT$(ObjectType) & ": Not defined"
               END SELECT
          CASE 50 'Windows 2000
               SELECT CASE ObjectType
                    CASE 01 : FUNCTION =  "1: Type"
                    CASE 02 : FUNCTION =  "2: Directory"
                    CASE 03 : FUNCTION =  "3: SymbolicLink"
                    CASE 04 : FUNCTION =  "4: Token"
                    CASE 05 : FUNCTION =  "5: Process"
                    CASE 06 : FUNCTION =  "6: Thread"
                    CASE 07 : FUNCTION =  "7: Job"
                    CASE 08 : FUNCTION =  "8: Event"
                    CASE 09 : FUNCTION =  "9: EventPair"
                    CASE 10 : FUNCTION = "10: Mutant"
                    CASE 11 : FUNCTION = "11: Callback"
                    CASE 12 : FUNCTION = "12: Semaphore"
                    CASE 13 : FUNCTION = "13: Timer"
                    CASE 14 : FUNCTION = "14: Profile"
                    CASE 15 : FUNCTION = "15: WindowStation"
                    CASE 16 : FUNCTION = "16: Desktop"
                    CASE 17 : FUNCTION = "17: Section"
                    CASE 18 : FUNCTION = "18: Key"
                    CASE 19 : FUNCTION = "19: Port"
                    CASE 20 : FUNCTION = "20: WaitablePort"
                    CASE 21 : FUNCTION = "21: Adapter"
                    CASE 22 : FUNCTION = "22: Controller"
                    CASE 23 : FUNCTION = "23: Device"
                    CASE 24 : FUNCTION = "24: Driver"
                    CASE 25 : FUNCTION = "25: IoCompletion"
                    CASE 26 : FUNCTION = "26: File"
                    CASE 27 : FUNCTION = "27: WmiGuid"
                    CASE ELSE : FUNCTION = FORMAT$(ObjectType) & ": Not defined"
               END SELECT
          CASE 51 'Windows XP
               SELECT CASE ObjectType
                    CASE 01 : FUNCTION =  "1: Type"
                    CASE 02 : FUNCTION =  "2: Directory"
                    CASE 03 : FUNCTION =  "3: SymbolicLink"
                    CASE 04 : FUNCTION =  "4: Token"
                    CASE 05 : FUNCTION =  "5: Process"
                    CASE 06 : FUNCTION =  "6: Thread"
                    CASE 07 : FUNCTION =  "7: Job"
                    CASE 08 : FUNCTION =  "8: DebugObject"
                    CASE 09 : FUNCTION =  "9: Event"
                    CASE 10 : FUNCTION = "10: EventPair"
                    CASE 11 : FUNCTION = "11: Mutant"
                    CASE 12 : FUNCTION = "12: Callback"
                    CASE 13 : FUNCTION = "13: Semaphore"
                    CASE 14 : FUNCTION = "14: Timer"
                    CASE 15 : FUNCTION = "15: Profile"
                    CASE 16 : FUNCTION = "16: KeyedEvent"
                    CASE 17 : FUNCTION = "17: WindowStation"
                    CASE 18 : FUNCTION = "18: Desktop"
                    CASE 19 : FUNCTION = "19: Section"
                    CASE 20 : FUNCTION = "20: Key"
                    CASE 21 : FUNCTION = "21: Port"
                    CASE 22 : FUNCTION = "22: WaitablePort"
                    CASE 23 : FUNCTION = "23: Adapter"
                    CASE 24 : FUNCTION = "24: Controller"
                    CASE 25 : FUNCTION = "25: Device"
                    CASE 26 : FUNCTION = "26: Driver"
                    CASE 27 : FUNCTION = "27: IoCompletion"
                    CASE 28 : FUNCTION = "28: File"
                    CASE 29 : FUNCTION = "29: WmiGuid"
                    CASE ELSE : FUNCTION = FORMAT$(ObjectType) & ": Not defined"
               END SELECT
     END SELECT
END FUNCTION
'______________________________________________________________________________

'------------------------------------------------------------------------------------------------------------------
' DISPLAY FUNCTIONS SHOWN BELOW
'------------------------------------------------------------------------------------------------------------------
FUNCTION SetHorizontalListboxBar() AS LONG
     LOCAL  hFont     AS DWORD
     LOCAL  hDC       AS DWORD
     LOCAL  ListWidth AS LONG
     LOCAL  LastItem  AS LONG
     LOCAL  Counter   AS LONG
     LOCAL  sBuffer   AS STRING
     LOCAL  TextLen   AS LONG
     LOCAL  Si        AS apiSize
     LOCAL  Looper    AS LONG

     hFont = SendMessage(hList, %WM_GETFONT, 0, 0)
     hDC = GetDC(hList)
     IF hFont THEN hFont = SelectObject(hDC, hFont)
     LastItem = SendMessage(hList, %LB_GETCOUNT, 0, 0) - 1
     IF LastItem > 0 THEN
          FOR Looper = 0 TO LastItem
               TextLen = SendMessage(hList, %LB_GETTEXTLEN, Looper, 0)
               IF TextLen THEN
                    sBuffer = NUL$(TextLen)
                    SendMessage hList, %LB_GETTEXT, Looper, STRPTR(sBuffer)
                    GetTextExtentPoint32 hDC, BYCOPY sBuffer + "W", TextLen + 1, Si
                    ListWidth = MAX& (ListWidth, Si.cx)
               END IF
          NEXT Looper
          SendMessage hList, %LB_SETHORIZONTALEXTENT, ListWidth, 0
     END IF
     IF hFont THEN SelectObject hDC, hFont
     ReleaseDC hList, hDC
END FUNCTION
'______________________________________________________________________________
FUNCTION ListAdd(AddToList AS STRING) AS LONG
     STATIC LastItem AS LONG
     LastItem = SendMessage(hList, %LB_GETCOUNT,  0, 0) - 1
     LastItem = SendMessage(hList, %LB_ADDSTRING, LastItem, BYVAL STRPTR(AddToList))
     SELECT CASE LastItem MOD 24              '6 lines total per entry so change mod value to multiples of 6 as needed
          CASE 0
               SendMessage hList, %LB_SETCURSEL, LastItem, 0
               DIALOG DOEVENTS
          CASE ELSE
     END SELECT
END FUNCTION
'______________________________________________________________________________