VB.NET WindowsService から画面をロックする

ここしばらく、WindowsServiceからWindowsをシャットダウンするソフトを作っていましたが。

シャットダウンではなくて画面ロックでできないか、ということでやってみました。

 

 

<DllImport("Advapi32.dll", EntryPoint:="CreateProcessAsUser",
   ExactSpelling:=False, SetLastError:=True, CharSet:=CharSet.Unicode)>
Public Shared Function CreateProcessAsUser(ByVal hToken As IntPtr,
                     ByVal lpApplicationName As String,
                     <[In](), Out(), [Optional]()> ByVal lpCommandLine As System.Text.StringBuilder,
                     ByVal lpProcessAttributes As IntPtr,
                     ByVal lpThreadAttributes As IntPtr,
                     <MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandles As Boolean,
                     ByVal dwCreationFlags As Integer,
                     ByVal lpEnvironment As IntPtr,
                     ByVal lpCurrentDirectory As String,
                     <[In]()> ByRef lpStartupInfo As STARTUPINFOW,
<Out()> ByRef lpProcessInformation As PROCESS_INFORMATION) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("Wtsapi32.dll", EntryPoint:="WTSQueryUserToken", SetLastError:=True)>
Public Shared Function WTSQueryUserToken(ByVal SessionId As UInteger,
ByRef phToken As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

<DllImport("kernel32.dll", EntryPoint:="WTSGetActiveConsoleSessionId", SetLastError:=True)>
Public Shared Function WTSGetActiveConsoleSessionId() As UInteger
End Function

 

<StructLayout(LayoutKind.Sequential)>
Public Structure STARTUPINFOW
  Public cb As UInteger
  <MarshalAs(UnmanagedType.LPWStr)>
  Public lpReserved As String
  <MarshalAs(UnmanagedType.LPWStr)>
  Public lpDesktop As String
  <MarshalAs(UnmanagedType.LPWStr)>
  Public lpTitle As String
  Public dwX As UInteger
  Public dwY As UInteger
  Public dwXSize As UInteger
  Public dwYSize As UInteger
  Public dwXCountChars As UInteger
  Public dwYCountChars As UInteger
  Public dwFillAttribute As UInteger
  Public dwFlags As UInteger
  Public wShowWindow As UShort
  Public cbReserved2 As UShort
  Public lpReserved2 As IntPtr
  Public hStdInput As IntPtr
  Public hStdOutput As IntPtr
  Public hStdError As IntPtr
End Structure

<StructLayout(LayoutKind.Sequential)>
Public Structure PROCESS_INFORMATION
  Public hProcess As IntPtr
  Public hThread As IntPtr
  Public dwProcessId As UInteger
  Public dwThreadId As UInteger
End Structure

 

ここまでが関数のインポート等です。

 

これを

 

Dim UserTokenHandle As IntPtr = IntPtr.Zero
WTSQueryUserToken(WTSGetActiveConsoleSessionId, UserTokenHandle)
Dim ProcInfo As New PROCESS_INFORMATION
Dim StartInfo As New STARTUPINFOW
StartInfo.cb = CUInt(Runtime.InteropServices.Marshal.SizeOf(StartInfo))
Dim cmdline As New System.Text.StringBuilder
cmdline.Append("rundll32.exe user32.dll,LockWorkStation")
CreateProcessAsUser(UserTokenHandle, Nothing, cmdline, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)

 

のようにWindowsService上で呼び出すことにより、画面をロックすることができました。

 

実際やってみると、シャットダウンよりも安定して動作するようなので、今回はこちらを採用しようかと思っています。シャットダウンは、ふいに動作しないことがあったので、少し不安が残るのです。