Acceso a los Procesos del Sistema

[Acceso a todos los procesos desde VB]

 

Fecha: 27/Jun/2005 (23-06-05)
Autor: Pol Florez Viciana [email protected]

 


En este articulo te muestro como es posible leer los procesos del sistema, y si esto te sabe a poco he diseñado un metodo para que cuando se encuentre un proceso nuevo se genere un evento y si este se cierra se genere otro evento de cierre. Para ello debemos añadir un control ListView al control Active-X llamado 'Listado' y a parte tendremos que añadir un control Timer llamado 'Tiempo' que se encargara de ir actualizando el listado según se encuentren mas o menos procesos que los mostrados en la lista. A parte yo le he añadido dos controles Label y un control Image para, en el control image mostrar una imagen descriptiva del control y en los Labels mostrar informacion de que es lo que va haciendo el control.

A continuación te muestro como se hace esto mismo:

 

   Option Explicit
' ***************************************************************
' Active-X Dedicado a controlar los procesos del sistema
'
' Escrito por Pol Florez Viciana        05-05-2005 - 23-06-2005
' ***************************************************************

' Constantes de Utilizacion propia
Private Const Cero = 0
Private Const Uno = 1
Private Const Dos = 2
Private Const Tres = 3
Private Const Cuatro = 4
Private Const Cinco = 5
Private Const Seis = 6
Private Const Siete = 7
Private Const Ocho = 8
Private Const Nueve = 9
Private Const Diez = 10
Private Const Once = 11
Private Const Doce = 12
Private Const Trece = 13
Private Const Catorce = 14
Private Const Quince = 15
Private Const Dieziseis = 16
Private Const Diezisiete = 17
Private Const Dieziocho = 18
Private Const Diezinueve = 19
Private Const Veinte = 20
Private Const Veintiuno = 21
Private Const Veintidos = 22
Private Const Veintitres = 23
Private Const Veinticuatro = 24
Private Const Veinticinco = 25
Private Const Veintiseis = 26
Private Const Veintisiete = 27
Private Const Veintiocho = 28
Private Const Veintinueve = 29
Private Const Treinta = 30
Private Const Treintaiuno = 31
Private Const Treintaidos = 32

Private Const Nada As String = ""
Private Const Barra As String * Uno = "/"
Private Const Contrabarra As String * Uno = "\"
Private Const Punto As String * Uno = "."
Private Const DosPuntos As String * Uno = ":"
Private Const Asterisco As String * Uno = "*"

' Declaracion tipos definidos por mi    ( Como no )
Public Type ProcessItem
    PID As Integer
    PHandle As Long
    PName As String
    PPath As String
    PCommandLine As String
    PRealSize As Long
    PVirtualSize As Long
    PCreationDate As String ' Date Execution
    PCreationTime As String ' Time Execution
    PNameUser As String
    PNameDomain As String
End Type

Public Type ProcessList
    PItem() As ProcessItem
    PCount As Integer
End Type

' Declaracion de Eventos para el control
Public Event ListChanged()
Public Event Initialized()
Public Event ProcessClick(ProcessItemClicked As ProcessItem)
Public Event ProcessDblClick(ProcessItemClicked As ProcessItem)
Public Event AgregatedItem(AgreItem As ProcessItem)
Public Event DeletedItem(DeleteItem As ProcessItem)
Public Event MouseUp(KeyButton As Integer, KeyShift As Integer, XPos As Single, YPos As Single)
Public Event MouseMove(KeyButton As Integer, KeyShift As Integer, XPos As Single, YPos As Single)
Public Event MouseDown(KeyButton As Integer, KeyShift As Integer, XPos As Single, YPos As Single)
Public Event KeyboardPress(KeyCode As Integer)

' Declaracion de Propiedades del control

Public Property Let Selected(ByVal ItemIndex As Integer)
On Error Resume Next
' Con esta podemos seleccionar un 'Item' del listado mediante
' codigo
Listado.ListItems.Item(ItemIndex).Selected = True

End Property

Public Property Get Selected() As Integer
On Error Resume Next
' Y con esta ver cual esta seleccionado, hay que decir
' que si esta devuelve cero es que no hay ningun Item seleccionado
Static Man As Integer   ' Con Static son mas rapidas

Selected = Cero
For Man = Uno To Listado.ListItems.Count
    If Listado.ListItems.Item(Man).Selected = True Then _
        Selected = Man: Exit For
Next

End Property

' Declaracion de Funciones
Public Function GetProcessList() As ProcessList
On Error Resume Next
' Esta nos devolvera toda una Lista de Procesos activos

Static Process, objWMIService, colProcesses
Static Man As Integer, T As String, R As Integer

' Accedemos a los Objetos necesarios ( Servicio WMI )
'         WMI = WINDOWS MANAGEMENT INSTRUMENTATION
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & Punto & "\root\cimv2")
' Y dentro del Objeto WMI accedemos a la columna de procesos
Set colProcesses = objWMIService.ExecQuery("select * from win32_process")

' Añadimos los procesos que hay actualmente a ListCount
GetProcessList.PCount = colProcesses.Count
' Y redimensionamos el Array de Tipos de Proceso
ReDim GetProcessList.PItem(Uno To GetProcessList.PCount)

' La Var 'Man' nos servira para ir contando los procesos
Man = Cero
For Each Process In colProcesses
  Man = Man + Uno
  T = Nada
 With GetProcessList
  .PItem(Man).PID = Process.ProcessId
  .PItem(Man).PHandle = CLng(Process.ProcessId)
  .PItem(Man).PName = Process.Name
  .PItem(Man).PPath = Process.ExecutablePath
  .PItem(Man).PRealSize = FileLen(.PItem(Man).PPath)
  T = Process.CreationDate
  .PItem(Man).PCreationDate = ObtainDateOrTime(True, T)
  .PItem(Man).PCreationTime = ObtainDateOrTime(False, T)
  .PItem(Man).PCommandLine = Process.CommandLine
  .PItem(Man).PVirtualSize = Process.VirtualSize
  R = Process.GetOwner(.PItem(Man).PNameUser, .PItem(Man).PNameDomain)
 End With
Next

' Y Descargamos los objetos
Set objWMIService = Nothing
Set colProcesses = Nothing
Set Process = Nothing

End Function

Public Function GetProcessItem(ByVal PrcId As Integer) As ProcessItem
On Error Resume Next
' Esta nos servira para acceder a un solo proceso activo
' partiendo de su PID ( Process Identifier )

Static Process, objWMIService, colProcesses
Static T As String

' Accedemos a los Objetos necesarios ( Servicio WMI )
'         WMI = WINDOWS MANAGEMENT INSTRUMENTATION
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & Punto & "\root\cimv2")
' Y dentro del Objeto WMI accedemos a la columna de procesos
Set colProcesses = objWMIService.ExecQuery("select * from win32_process")

' Y empezamos a leer uno a uno para ver cual tiene el PID
' solicitado
For Each Process In colProcesses
  If PrcId = Process.ProcessId Then
    With GetProcessItem
     T = Nada
     .PID = Process.ProcessId
     .PHandle = CLng(Process.ProcessId)
     .PName = Process.Name
     .PPath = Process.ExecutablePath
     .PRealSize = FileLen(.PPath)
     T = Process.CreationDate
     .PCreationDate = ObtainDateOrTime(True, T)
     .PCreationTime = ObtainDateOrTime(False, T)
     .PCommandLine = Process.CommandLine
     .PVirtualSize = Process.VirtualSize
    End With
   Exit For
  End If
Next

' Y Descargamos los objetos
Set objWMIService = Nothing
Set colProcesses = Nothing
Set Process = Nothing

End Function

Public Function GetProcessCount() As Integer
On Error Resume Next

' Aqui solo declaramos el objeto WMI con las Columnas de Procesos
Static objWMIService, colProcesses

' Accedemos a los Objetos necesarios ( Servicio WMI )
'         WMI = WINDOWS MANAGEMENT INSTRUMENTATION
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & Punto & "\root\cimv2")
' Y dentro del Objeto WMI accedemos a la columna de procesos
Set colProcesses = objWMIService.ExecQuery("select * from win32_process")

GetProcessCount = Cero

    GetProcessCount = colProcesses.Count

' Y los descargamos
Set objWMIService = Nothing
Set colProcesses = Nothing

End Function

Public Function ListAllItems() As ProcessList
On Error Resume Next
' Esta nos devolvera toda la lista visible de procesos ( La del
' listado )
Static Man As Integer

With ListAllItems
ReDim .PItem(Uno To Listado.ListItems.Count)
.PCount = Listado.ListItems.Count

For Man = Uno To .PCount
 .PItem(Man).PID = CInt(Listado.ListItems.Item(Man).Text)
 .PItem(Man).PHandle = CLng(Listado.ListItems.Item(Man).SubItems(Uno))
 .PItem(Man).PName = Listado.ListItems.Item(Man).SubItems(Dos)
 .PItem(Man).PPath = Listado.ListItems.Item(Man).SubItems(Tres)
 .PItem(Man).PCommandLine = Listado.ListItems.Item(Man).SubItems(Cuatro)
 .PItem(Man).PRealSize = CLng(Listado.ListItems.Item(Man).SubItems(Cinco))
 .PItem(Man).PVirtualSize = CLng(Listado.ListItems.Item(Man).SubItems(Seis))
 .PItem(Man).PCreationDate = Listado.ListItems.Item(Man).SubItems(Siete)
 .PItem(Man).PCreationTime = Listado.ListItems.Item(Man).SubItems(Ocho)
Next
End With

End Function

Public Function List(ByVal LIndex As Integer, _
            Optional ByVal LSubIndex As Integer) As String
On Error Resume Next
' Esta nos devolvera un solo Registro dado del listado
If LSubIndex < Uno Then
  List = Listado.ListItems.Item(LIndex).Text
Else
  List = Listado.ListItems.Item(LIndex).SubItems(LSubIndex)
End If

End Function

Public Function ListItem(ByVal LIndex As Integer) As ProcessItem
On Error Resume Next
' Esta nos devolvera toda la fila de un proceso del listado
With ListItem
.PID = CInt(Listado.ListItems.Item(LIndex).Text)
.PHandle = CLng(Listado.ListItems.Item(LIndex).SubItems(Uno))
.PName = Listado.ListItems.Item(LIndex).SubItems(Dos)
.PPath = Listado.ListItems.Item(LIndex).SubItems(Tres)
.PCommandLine = Listado.ListItems.Item(LIndex).SubItems(Cuatro)
.PRealSize = CLng(Listado.ListItems.Item(LIndex).SubItems(Cinco))
.PVirtualSize = CLng(Listado.ListItems.Item(LIndex).SubItems(Seis))
.PCreationDate = Listado.ListItems.Item(LIndex).SubItems(Siete)
.PCreationTime = Listado.ListItems.Item(LIndex).SubItems(Ocho)
.PNameUser = Listado.ListItems.Item(LIndex).SubItems(Nueve)
.PNameDomain = Listado.ListItems.Item(LIndex).SubItems(Diez)
End With

End Function

Public Function ListCount() As Integer
On Error Resume Next
' Sin comentarios...
ListCount = Listado.ListItems.Count

End Function

Public Function KillProcess(ByVal PrcId As Integer)
On Error Resume Next
' Esta se encargara de cerrar el proceso seleccionado
' aunque me he fijado que si el proceso lo inicio un usuario
' distinto al nuestro ( por ejemplo SYSTEM ) este no se cierra
' correctamente y no se resolverlo pero bueno este es el metodo

Static Process, objWMIService, colProcesses

' Accedemos a los Objetos necesarios ( para variar )
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & Punto & "\root\cimv2")
' Y dentro del Objeto WMI accedemos a la columna de procesos
Set colProcesses = objWMIService.ExecQuery("select * from win32_process")
    
For Each Process In colProcesses
 ' Buscamos su PID y a continuacion le mandamos que se cierre
 ' ( o lo mandamos a la mie... )
 If PrcId = Process.ProcessId Then
 Process.Terminate PrcId: Exit For
 End If
Next

' Y Descargamos los objetos
Set objWMIService = Nothing
Set colProcesses = Nothing
Set Process = Nothing

End Function

Public Function RefreshList()
  CreateNewList
End Function

Public Function ProcessIdIsRun(ByVal ProcIdToSearch As Integer) As Boolean
On Error Resume Next
' Esta comprueba si un cierto PID esta ejecutandose
Static Process, objWMIService, colProcesses

Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & Punto & "\root\cimv2")
Set colProcesses = objWMIService.ExecQuery("select * from win32_process")

For Each Process In colProcesses
   If ProcIdToSearch = Process.ProcessId Then ProcessIdIsRun = True: Exit For
Next

' Y Descargamos los objetos
Set objWMIService = Nothing
Set colProcesses = Nothing
Set Process = Nothing

End Function

Public Function ProcessIdExist(ByVal ProcIdToSearch As Integer) As Boolean
On Error Resume Next
' Esta comprueba si un cierto PID esta en el Listado.List

Static Man As Integer, H As Integer

For Man = Uno To Listado.ListItems.Count
    H = CInt(Listado.ListItems.Item(Man).Text)
   If ProcIdToSearch = H Then ProcessIdExist = True: Exit For
Next

End Function

Public Function ProcessIdExistInThisList _
            (ListOfSearchPID As ProcessList, _
              PIDToSearch As Integer) As Boolean
On Error Resume Next
' Esta comprueba si existe un PID dentro de un Listado ya dado
Static Man As Integer

For Man = Uno To ListOfSearchPID.PCount
   If PIDToSearch = ListOfSearchPID.PItem(Man).PID Then
     ProcessIdExistInThisList = True: Exit For
   End If
Next

End Function

Private Function ObtainDateOrTime _
            (ByVal DateTrueTimeFalse As Boolean, _
             ByVal OriginalDateCreation As String) As String
On Error Resume Next
' Esta es de fabricacion propia y sirve para traducir
' la fecha y hora de ejecucion a formato legible
Dim YE As String, MO As String, DA As String
Dim HO As String, MI As String, Re As String, H As Long

YE = Left(OriginalDateCreation, Cuatro) ' Año
H = Len(OriginalDateCreation) - Cuatro
Re = Right(OriginalDateCreation, H)
MO = Left(Re, Dos)                      ' Mes
H = Len(OriginalDateCreation) - Seis
Re = Right(OriginalDateCreation, H)
DA = Left(Re, Dos)                      ' Dia
H = Len(OriginalDateCreation) - Ocho
Re = Right(OriginalDateCreation, H)
HO = Left(Re, Dos)                      ' Hora
H = Len(OriginalDateCreation) - Diez
Re = Right(OriginalDateCreation, H)
MI = Left(Re, Dos)                      ' Minutos

If DateTrueTimeFalse = True Then
   ObtainDateOrTime = DA & Barra & MO & Barra & YE
Else
   ObtainDateOrTime = HO & DosPuntos & MI
End If

End Function

Private Function CreateNewList()
On Error Resume Next

' Esta creara un nuevo listado cada vez que lo necesitemos

Static Process, objWMIService, colProcesses
Static T As String, I As Integer, N As String, D As String, R As Integer

' Accedemos a los Objetos necesarios
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & Punto & "\root\cimv2")
' Y dentro del Objeto WMI accedemos a la columna de procesos
Set colProcesses = objWMIService.ExecQuery("select * from win32_process")

Listado.ListItems.Clear
For Each Process In colProcesses
    T = Process.ProcessId
    Listado.ListItems.Add , , T
    I = Listado.ListItems.Count
   T = Process.Handle
   Listado.ListItems.Item(I).SubItems(Uno) = T
   T = Process.Name
   Listado.ListItems.Item(I).SubItems(Dos) = T
   T = Nada
   T = Process.ExecutablePath
   Listado.ListItems.Item(I).SubItems(Tres) = T
   Listado.ListItems.Item(I).SubItems(Cinco) = FileLen(T)
   T = Nada
   T = Process.CommandLine
   Listado.ListItems.Item(I).SubItems(Cuatro) = T
   T = Process.VirtualSize
   Listado.ListItems.Item(I).SubItems(Seis) = T
   T = Process.CreationDate
   If Process.ProcessId > Cinco Then
        T = ObtainDateOrTime(True, T)
   End If
   Listado.ListItems.Item(I).SubItems(Siete) = T
   T = Process.CreationDate
   If Process.ProcessId > Cinco Then
        T = ObtainDateOrTime(False, T)
   End If
   Listado.ListItems.Item(I).SubItems(Ocho) = T
   N = Nada: D = Nada
   R = Process.GetOwner(N, D)
   Listado.ListItems.Item(I).SubItems(Nueve) = N
   Listado.ListItems.Item(I).SubItems(Diez) = D
Next

NumProc.Caption = Listado.ListItems.Count
Estado.Caption = "El listado a Cambiado"
DoEvents

' Y Descargamos los objetos
Set objWMIService = Nothing
Set colProcesses = Nothing
Set Process = Nothing

RaiseEvent ListChanged

End Function

Private Sub Listado_Click()
On Error Resume Next
If Me.Selected = Cero Then Exit Sub

Dim S As Integer, ItemProcess As ProcessItem

S = Me.Selected

ItemProcess = ListItem(S)

RaiseEvent ProcessClick(ItemProcess)

End Sub

Private Sub Listado_DblClick()
On Error Resume Next
If Me.Selected = Cero Then Exit Sub

Dim S As Integer, ItemProcess As ProcessItem

S = Me.Selected

ItemProcess = ListItem(S)

RaiseEvent ProcessDblClick(ItemProcess)

End Sub

Private Sub Listado_ItemClick(ByVal Item As MSComctlLib.ListItem)
    Listado_Click
End Sub

Private Sub Listado_KeyPress(KeyAscii As Integer)
  RaiseEvent KeyboardPress(KeyAscii)
End Sub

Private Sub Listado_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
On Error Resume Next
  RaiseEvent MouseDown(Button, Shift, x, y)
End Sub

Private Sub Listado_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
On Error Resume Next
  RaiseEvent MouseMove(Button, Shift, x, y)
End Sub

Private Sub Listado_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
On Error Resume Next
  RaiseEvent MouseUp(Button, Shift, x, y)
End Sub

Private Sub Tiempo_Timer()
On Error Resume Next
' Con esto iremos comprobando si han aparecido Nuevos Procesos
' o si por el contrario se termino algun proceso

' ListCount And ListActivesProcess
Dim LC As Integer, LA As Integer

LC = Me.ListCount
LA = Me.GetProcessCount

If LC = LA Then
  ' No Changes, Exit Sub
 Exit Sub
End If

' Caso Excepcional ListCount = 0 Initial Event
If LC = Cero Then _
    CreateNewList: _
    Estado.Caption = "Inicializacion del Control": _
    RaiseEvent Initialized: _
    Exit Sub

Dim TempList As ProcessList
Static Man As Integer

TempList = Me.ListAllItems
CreateNewList
DoEvents

If LC < LA Then
  ' ListCount Is Minor ListActiveProcesses
  For Man = Uno To Listado.ListItems.Count
   If Me.ProcessIdExistInThisList(TempList, CInt(Listado.ListItems.Item(Man).Text)) = False Then
     RaiseEvent AgregatedItem(Me.ListItem(Man))
     Estado.Caption = "Se ha iniciado un nuevo proceso"
   End If
  Next
 Exit Sub
End If

If LC > LA Then
  ' ListActiveProcesses Is Minor ListCount
  For Man = Uno To TempList.PCount
    If Me.ProcessIdExist(TempList.PItem(Man).PID) = False Then
      RaiseEvent DeletedItem(TempList.PItem(Man))
      Estado.Caption = "Se ha cerrado un proceso"
    End If
  Next
 Exit Sub
End If

End Sub

Private Sub UserControl_Resize()
On Error Resume Next
' Sin comentarios...

With UserControl
    Listado.Left = .ScaleLeft
    Listado.Top = .ScaleTop
    Listado.Width = .ScaleWidth
    Listado.Height = .ScaleHeight - Imagen.Height
    NumProc.Left = .ScaleLeft
    NumProc.Top = .ScaleHeight - Imagen.Height
    .Refresh
    DoEvents
    Imagen.Left = NumProc.Left + NumProc.Width
    Imagen.Top = .ScaleHeight - Imagen.Height
    .Refresh
    DoEvents
    Estado.Left = Imagen.Left + Imagen.Width
    Estado.Top = .ScaleHeight - Imagen.Height
    Estado.Width = .ScaleWidth - Imagen.Width - NumProc.Width
End With

End Sub

Espero que esto le sirva de ayuda a mas de uno.


Fichero con el código de ejemplo: polflo_ProcessCtrl.zip - 37,5 KB


ir al índice