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
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 '______________________________________________________________________________