Otra forma de llevarlo a cabo sería utilizando el método Win32
RtlSetProcessIsCritical, el cual lo considero más apropiado o "directo" puesto que afecta al proceso actual desde el que se invocó dicho método, pero claro está, si queremos que afecte a un proceso distinto, entonces hay que usar la ya mencionada función Win32
NTSetInformationProcess.
Hay que tener en cuenta también, que para poder establecer un proceso cómo "crítico", dicho proceso necesita tener establecido el privilegio de proceso "
SE_DEBUG_NAME" (y si usasemos la función
NtSetInformationProcess, es necesario que el proceso sea abierto con el privilegio "
PROCESS_SET_INFORMATION"), por lo que esto aumenta considerablemente el tamaño del código fuente, declarando y utilizando los P/Invokes para asegurarnos (o al menos intentarlo) que todo salga de forma esperada.
Para determinar si un proceso es crítico o no lo es, en versiones superiores a Windows XP podemos llamar a la función Win32
IsProcessCritical, la cual es muy cómoda y abstracta, pero en Windows XP deberemos utilizar la función
NtQueryInformationProcess, la cual es insegura llamarla dependiendo de la versión de Windows desde la que se llame (como indica la documentación de dicha función en MSDN), y como Windows XP es un sistema operativo obsoleto, no me he molestado en implementar dicha función.
Aquí está mi solución (probado en Windows 10 y Windows XP), un "
todo en uno", tanto para establecer el proceso actual como "Crítico", "Normal", y averiguar si un proceso es crítico o no lo es:
( Todos los P/Invokes del código fuente, excepto el método '
RtlSetProcessIsCritical', los he sacado de mi framework
ElektroKit, lo comento por que con mi librería podeis hacer muchas virguerías al poder utilizar todos estos miembros Win32...y una infinidad más en el namespace
Elektro.Interop.Win32:
)
Clase para definir el P/Invoking:
Namespace Win32
Friend NotInheritable Class NativeMethods
<DebuggerNonUserCode>
Private Sub New()
End Sub
<Flags>
Friend Enum TokenPrivilegesFlags As UInteger
PrivilegeEnabledBYDefault = &H1UI
PrivilegeEnabled = &H2UI
PrivilegeRemoved = &H4UI
PrivilegeUsedForAccess = &H80000000UI
End Enum
<Flags>
Friend Enum AccessRights As UInteger
TokenAdjustPrivileges = &H32UI
TokenQuery = &H8UI
End Enum
<StructLayout(LayoutKind.Sequential)>
Friend Structure TokenPrivileges
<MarshalAs(UnmanagedType.I4)>
Public PrivilegeCount As Integer
<MarshalAs(UnmanagedType.Struct)>
Public Privileges As LuIdAndAttributes
End Structure
<StructLayout(LayoutKind.Sequential)>
Friend Structure LuIdAndAttributes
<MarshalAs(UnmanagedType.Struct)>
Public PLuid As Luid
<MarshalAs(UnmanagedType.U4)>
Public Attributes As TokenPrivilegesFlags
End Structure
<StructLayout(LayoutKind.Sequential)>
Friend Structure Luid
<MarshalAs(UnmanagedType.U4)>
Public LowPart As UInteger
<MarshalAs(UnmanagedType.I4)>
Public HighPart As Integer
End Structure
<DllImport("advapi32.dll", SetLastError:=True)>
Friend Shared Function AdjustTokenPrivileges(
<MarshalAs(UnmanagedType.SysInt)> ByVal tokenHandle As IntPtr,
<MarshalAs(UnmanagedType.Bool)> ByVal disableAllPrivileges As Boolean,
<MarshalAs(UnmanagedType.Struct)> ByRef newState As TokenPrivileges,
<MarshalAs(UnmanagedType.U4)> ByVal bufferLength As UInteger,
<MarshalAs(UnmanagedType.SysInt)> ByVal previousState As IntPtr,
<MarshalAs(UnmanagedType.SysInt)> ByVal returnLength As IntPtr
) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)>
Friend Shared Function OpenProcessToken(
<MarshalAs(UnmanagedType.SysInt)> ByVal processHandle As IntPtr,
<MarshalAs(UnmanagedType.U4)> ByVal desiredAccess As AccessRights,
<MarshalAs(UnmanagedType.SysInt)> ByRef tokenHandle As IntPtr
) As <MarshalAs(UnmanagedType.I4)> Integer
End Function
<DllImport("advapi32.dll", SetLastError:=True, CharSet:=CharSet.Unicode, BestFitMapping:=False, ThrowOnUnmappableChar:=True)>
Friend Shared Function LookupPrivilegeValue(
<MarshalAs(UnmanagedType.LPWStr)> ByVal lpSystemName As String,
<MarshalAs(UnmanagedType.LPWStr)> ByVal lpName As String,
<MarshalAs(UnmanagedType.Struct)> ByRef lpLuid As Luid
) As <MarshalAs(UnmanagedType.I4)> Integer
End Function
<DllImport("Kernel32.dll", SetLastError:=True)>
Friend Shared Function IsProcessCritical(
<MarshalAs(UnmanagedType.SysInt)> ByVal hProcess As IntPtr,
<MarshalAs(UnmanagedType.Bool)> ByRef refIsCritical As Boolean
) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("ntdll.dll", EntryPoint:="RtlSetProcessIsCritical", SetLastError:=True)>
Friend Shared Sub SetCurrentProcessIsCritical(
<MarshalAs(UnmanagedType.Bool)> ByVal isCritical As Boolean,
<MarshalAs(UnmanagedType.Bool)> ByRef refWasCritical As Boolean,
<MarshalAs(UnmanagedType.Bool)> ByVal needSystemCriticalBreaks As Boolean)
End Sub
End Class
End Namespace
Clase para definir los métodos o abstracción de los algoritmos:
Imports Win32
Imports Win32.NativeMethods
Namespace Tools
Public NotInheritable Class ProcessUtil
<DebuggerNonUserCode>
Private Sub New()
End Sub
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Specifies a critical state of a process.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Public Enum ProcessCriticalState As Integer
''' <summary>
''' Process isn't critical.
''' </summary>
NonCritical = 0
''' <summary>
''' Process is critical.
''' </summary>
Critical = 1
End Enum
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Determines whether the specified process is considered <c>critical</c>.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <param name="handle">
''' A handle (<see cref="IntPtr"/>) to the process to query.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' A <see cref="ProcessCriticalState"/> enumeration value indicating the critical state.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Shared Function GetProcessCriticalState(ByVal handle As IntPtr) As ProcessCriticalState
If (handle = IntPtr.Zero) Then
Throw New ArgumentNullException(paramName:="handle")
Else
Dim result As Boolean
Dim win32Err As Integer
NativeMethods.IsProcessCritical(handle, result)
win32Err = Marshal.GetLastWin32Error()
If (win32Err <> 0) Then
Throw New Win32Exception(win32Err)
Else
Select Case result
Case True
Return ProcessCriticalState.Critical
Case Else
Return ProcessCriticalState.NonCritical
End Select
End If
End If
End Function
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Determines whether the caller process is considered <c>critical</c>.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' A <see cref="ProcessCriticalState"/> enumeration value indicating the critical state.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Shared Function GetCurrentProcessCriticalState() As ProcessCriticalState
Return ProcessUtil.GetProcessCriticalState(Process.GetCurrentProcess().Handle)
End Function
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Sets the critical state for the caller process.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <param name="state">
''' The new critical state.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <exception cref="InvalidEnumArgumentException">
''' state
''' </exception>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Shared Sub SetCurrentProcessCriticalState(ByVal state As ProcessCriticalState)
Dim isCritical As Boolean
Dim wasCritical As Boolean
Dim needSystemCriticalBreaks As Boolean = False
Select Case state
Case ProcessCriticalState.Critical
isCritical = True
Case ProcessCriticalState.NonCritical
isCritical = False
Case Else
Throw New InvalidEnumArgumentException(argumentName:="state", invalidValue:=state,
enumClass:=GetType(ProcessCriticalState))
Exit Sub
End Select
' Set "SE_DEBUG_NAME" process privilege,
' required to debug and adjust the memory of a process owned by another account.
ProcessUtil.SetCurrentProcessPrivilege("SE_DEBUG_NAME")
' Set the critical state.
NativeMethods.SetCurrentProcessIsCritical(isCritical, wasCritical, needSystemCriticalBreaks)
Debug.
WriteLine(String.
Format("Current process was critical?: {0}", wasCritical
)) #End If
End Sub
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Sets a process privilege for the caller process.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <remarks>
''' <see href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716%28v=vs.85%29.aspx"/>
''' </remarks>
''' ----------------------------------------------------------------------------------------------------
Private Shared Sub SetCurrentProcessPrivilege(ByVal privilegeName As String)
Dim hToken As IntPtr
Dim tkp As New TokenPrivileges
NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle,
AccessRights.TokenAdjustPrivileges Or
AccessRights.TokenQuery,
hToken)
With tkp
.PrivilegeCount = 1
.Privileges.Attributes = TokenPrivilegesFlags.PrivilegeEnabled
End With
NativeMethods.LookupPrivilegeValue(Nothing, privilegeName, tkp.Privileges.PLuid)
NativeMethods.AdjustTokenPrivileges(hToken, False, tkp, 0UI, IntPtr.Zero, IntPtr.Zero)
End Sub
End Class
End Namespace
Clase (cualquiera) donde utilizar los miembros definidos:
Imports Tools
Imports Tools.ProcessUtil
Public NotInheritable Class Form1 : Inherits Form
' Establecer el estado del proceso actual a: crítico.
Private Sub Button1_Click() Handles Button1.Click
ProcessUtil.SetCurrentProcessCriticalState(ProcessCriticalState.Critical)
End Sub
' Establecer el estado del proceso actual a: no-crítico.
Private Sub Button2_Click() Handles Button2.Click
ProcessUtil.SetCurrentProcessCriticalState(ProcessCriticalState.NonCritical)
End Sub
' Determinar el estado del proceso actual.
Private Sub Button3_Click() Handles Button3.Click
Dim state As ProcessCriticalState = ProcessUtil.GetCurrentProcessCriticalState()
MessageBox.Show(String.Format("Is process critical?: {0}", CBool(state)))
End Sub
End Class