WTS APIs(Windows终端服务API)获取进程信息
Windows XP 有一个新特性叫做“快速用户转换——Fast User Switching”,这个特性允许多个用户同时在一台机器上登陆。当一个用户登陆后,另一个用户启动的进程仍然能够运行。这个神奇的特性所倚仗的是 WTS APIs。如果你想了解更多有关 WTS 的内容,可以参考 MSJ Oct99 的一篇文章:“Windows NT和 Windows 2000 终端服务APIs介绍”,作者是 Frank Kim。
Windows XP为每一个登陆用户创建一个WTS会话(Session)。每个运行进程总是与这样一个Session关联。Windows XP的任务管理器允许你列出进程清单,不论是针对所有会话的还是仅仅针对自己的会话,任务管理器对话框的进程标签中有一个"显示所有用户的进程"复选框可 以对此进行选择
如果你想了解某个进程隶属的 session ID,可以调用 kernel32.dll 输出的一个 API 函数 ProcessIdToSessionId。给定一个进程的ID,他返回相应的 session ID。有趣的是这个 API 函数不是由 wtsapi32.dll 输出的,而是出自于 kernel32.dll,前者是所有 Windows 终端服务 APIs 的输出动态库。实际上,即使 Windows 终端服务没有运行起来,Windows 2000 和 Windows XP 都将 session ID 存储在 PEB 中。
注意 Windows NT 既不在 PEB 中存储 session ID,也不从 kernel32.dll 中输出 ProcessIdToSessionId 函数。当你调用 ProcessIdToSessionId,而 WTS 又没有运行,这时其返回值总是0。
除了允许你列出打开的会话之外,WTS 还有一个 API 用于枚举运行的进程,其实现方式与 PSAPI 和 TOOLHELP32 的实现方式是不同的。WTS枚举 APIs 函数的第一个参数都是一个服务器句柄。WTS_CURRENT_SERVER_HANDLE 用于当前的机器。第二个参数是保留参数,值应该为0。第三个参数希望的版本,其值应该是1。最后两个参数用于存放返回的信息。一个用于存放会话数或进程 数。另一个是结构数组的指针,结构可以是描述会话信息的结构,也可以是描述进程信息的结构。就看你是使用哪个枚举API,是枚举会话还是枚举进程。因为数 组的存储空间是由 WTS 分配的,你必须要记住用 WTSFreeMemory 释放这个空间。
下面是描述会话的结构:WTS_SESSION_INFO:
typedef struct _WTS_SESSION_INFO{ DWORD SessionId; LPTSTR pWinStationName; WTS_CONNECTSTATE_CLASS State;} WTS_SESSION_INFO, * PWTS_SESSION_INFO; 结构中除了会话的 SessionId,还有会话名 pWinStationName,当前会话的名字是“console”,而其它的会话是无名的。当前的会话状态为 WTSActive,其它则为 WTSDisconnected。
下面是描述进程的结构 WTS_PROCESS_ INFO:
typedef struct _WTS_PROCESS_INFO { DWORD SessionId; DWORD ProcessId; LPTSTR pProcessName; PSID pUserSid;} WTS_PROCESS_INFO, * PWTS_PROCESS_INFO; SessionId 与 ProcessIdToSessionId 所要找的值一样,ProcessId 不用说了,是进程ID。最后一个成员 pUserSid 指向安全标示符,描述用户账号,用户正是在这个账号下运行进程。使用 LookupAccountSid,你可以获得从 pUserSid 中获得用户名。这个信息已经可以通过 CProcess 类中的 GetProcessOwner 获得,但它是通过进程记号(token),而不是通过 WTS。某些情况下,即便由 WTSEnumerateProcesses 控制对它的提供,要想获得进程记号也是不可能的,这就是在 Windows XP 环境下要用 WTS API 而不用 PSAPI 或 TOOLHELP32 的缘故
VB代码例子:
Option Explicit
Private Const WTS_CURRENT_SERVER_HANDLE = 0&
Private Type WTS_PROCESS_INFO
SessionID As Long
ProcessID As Long
pProcessName As Long
pUserSid As Long
End Type
Private Declare Function WTSEnumerateProcesses _
Lib "wtsapi32.dll" Alias "WTSEnumerateProcessesA" _
(ByVal hServer As Long, ByVal Reserved As Long, _
ByVal Version As Long, ByRef ppProcessInfo As Long, _
ByRef pCount As Long _
) As Long
Private Declare Sub WTSFreeMemory Lib "wtsapi32.dll" _
(ByVal pMemory As Long)
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(Destination As Any, Source As Any, ByVal Length As Long)
Private Sub Command1_Click()
GetWTSProcesses
End Sub
Private Function GetStringFromLP(ByVal StrPtr As Long) As String
Dim b As Byte
Dim tempStr As String
Dim bufferStr As String
Dim Done As Boolean
Done = False
Do
' Get the byte/character that StrPtr is pointing to.
CopyMemory b, ByVal StrPtr, 1
If b = 0 Then ' If you've found a null character, then you're done.
Done = True
Else
tempStr = Chr$(b) ' Get the character for the byte's value
bufferStr = bufferStr & tempStr 'Add it to the string
StrPtr = StrPtr + 1 ' Increment the pointer to next byte/char
End If
Loop Until Done
GetStringFromLP = bufferStr
End Function
Private Sub Form_Load()
ListView1.View = lvwReport
Command1.Caption = "Refresh"
'Add the Column Headers for your ListView Control
ListView1.ColumnHeaders.Add 1, "SessionID", "Session ID"
ListView1.ColumnHeaders.Add 2, "ProcessID", "Process ID"
ListView1.ColumnHeaders.Add 3, "ProcessName", "Process Name"
ListView1.ColumnHeaders.Add 4, "UserID", "User ID"
GetWTSProcesses
End Sub
Private Sub ListView1_ColumnClick(ByVal ColumnHeader As _
MSComctlLib.ColumnHeader)
' When a ColumnHeader object is clicked, the ListView control is
' sorted by the subitems of that column.
' Set the SortKey to the Index of the ColumnHeader - 1
ListView1.SortKey = ColumnHeader.Index - 1
' Set Sorted to True to sort the list.
ListView1.Sorted = True
End Sub
Private Sub GetWTSProcesses()
Dim RetVal As Long
Dim Count As Long
Dim i As Integer
Dim lpBuffer As Long
Dim p As Long
Dim udtProcessInfo As WTS_PROCESS_INFO
Dim itmAdd As ListItem
ListView1.ListItems.Clear
RetVal = WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, _
0&, _
1, _
lpBuffer, _
Count)
If RetVal Then ' WTSEnumerateProcesses was successful
p = lpBuffer
For i = 1 To Count
' Count is the number of Structures in the buffer
' WTSEnumerateProcesses returns a pointer, so copy it to a
' WTS_PROCESS_INO UDT so you can access its members
CopyMemory udtProcessInfo, ByVal p, LenB(udtProcessInfo)
' Add items to the ListView control
Set itmAdd = ListView1.ListItems.Add(i, , _
CStr(udtProcessInfo.SessionID))
itmAdd.SubItems(1) = CStr(udtProcessInfo.ProcessID)
' Since pProcessName contains a pointer, call GetStringFromLP to get the
' variable length string it points to
itmAdd.SubItems(2) = GetStringFromLP(udtProcessInfo.pProcessName)
itmAdd.SubItems(3) = CStr(udtProcessInfo.pUserSid)
' Increment to next WTS_PROCESS_INO structure in the buffer
p = p + LenB(udtProcessInfo)
Next i
Set itmAdd = Nothing
WTSFreeMemory lpBuffer 'Free your memory buffer
Else
' Error occurred calling WTSEnumerateProcesses
' Check Err.LastDllError for error code
MsgBox "Error occurred calling WTSEnumerateProcesses. " & _
"Check the Platform SDK error codes in the MSDN Documentation" _
& " for more information.", vbCritical, "Error " & Err.LastDllError
End If
End Sub
WTS APIs(Windows终端服务API)获取进程信息
最新推荐文章于 2023-10-22 17:34:21 发布