I need to lock the workstation from a windows service written in VB.Net. I am writing the app on Windows 7 but it needs to work under Vista and XP as well.
User32 API LockWorkStation does not work as it requires an interactive desktop and I get return value of 0.
I tried calling %windir%\System32\rundll32.exe user32.dll,LockWorkStation from both a Process and from Shell, but still nothing happens.
Setting the service to interact with the desktop is a no-go as I am running the service under the admin account so it can do some other stuff that requires admin rights - like disabling the network, and you can only select the interact with desktop option if running under Local System Account.
That would be secondary question - how to run another app with admin rights from a service running under Local System Account without bugging the user.
I am writing an app to control my kids computer/internet access (which I plan to open source when done) so I need everything to happen as stealthily as possible.
I have a UI that handles settings and status notifications in the taskbar, but that is easy to kill and thus defeat the locking. I could make another hidden Windows Forms app to handle the locking, but that just seems a rather inelegant solution.
Better ideas anyone?
Press Ctrl-Alt-Del , and then click Lock this computer, Lock Computer, or Lock.
Using the Keyboard: Press Ctrl, Alt and Del at the same time. Then, select Lock from the options that appear on the screen.
I've been fighting with this over a week and after reading a lot of information about this issue, finally got the solution for this...
You have to use the CreateProcessAsUser function like this:
Private Shared Sub Executer(ByVal content As String)
Dim objProcess As System.Diagnostics.Process
Dim filename As String
filename = "e:\lock.bat"
'create a bat file with ''rundll32.exe user32.dll,LockWorkStation'' inside
Dim UserTokenHandle As IntPtr = IntPtr.Zero
WindowsApi.WTSQueryUserToken(WindowsApi.WTSGetActiveConsoleSessionId, UserTokenHandle)
Dim ProcInfo As New WindowsApi.PROCESS_INFORMATION
Dim StartInfo As New WindowsApi.STARTUPINFOW
StartInfo.cb = CUInt(Marshal.SizeOf(StartInfo))
WindowsApi.CreateProcessAsUser(UserTokenHandle, filename, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)
If Not UserTokenHandle = IntPtr.Zero Then
WindowsApi.CloseHandle(UserTokenHandle)
End If
End Sub
Got most of the code from here where you can, also, find the WindowsApi to use with this function. I'me still trying to find if can avoid the bat file but at least is a very decent solution.
EDIT: To avoid using an external *.bat file to execute the code just edit the WindowsApi Class and replace the CreateProcessAsUser and the advapi32.dll import part with this:
<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 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
And now you can use a stringbuilder as the thrid argument(comandline) for CreateProcessAsUser function and put the second(applicationame) as 'Nothing' like this:
Dim cmdline As New StringBuilder
cmdline.Append("rundll32.exe user32.dll,LockWorkStation")
WindowsApi.CreateProcessAsUser(UserTokenHandle, Nothing, cmdline, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)
And it WILL WORK!!!!
Regards, AP
What you're trying to do is actively blocked by Microsoft - if you did get it working, it'd be exploiting a loophole that will surely be closed soon.
What you can do though is the Friar Tuck/Robin Hood solution - have two programs running and monitoring each other. When one is killed, the other detects this and restarts it (or, just logs the current user out as punishment, depending on how severe you want this to be).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With