Announcement

Collapse

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

Enum Handles with NtQuerySystemInformation (improved)

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Enum Handles with NtQuerySystemInformation (improved)

    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
    '______________________________________________________________________________
    Engineer's Motto: If it aint broke take it apart and fix it

    "If at 1st you don't succeed... call it version 1.0"

    "Half of Programming is coding"....."The other 90% is DEBUGGING"

    "Document my code????" .... "WHYYY??? do you think they call it CODE? "
Working...
X