.net 如何从windows服务锁定工作站?

.net 如何从windows服务锁定工作站?,.net,windows-services,locking,.net,Windows Services,Locking,我需要从用VB.Net编写的windows服务中锁定工作站。我正在Windows7上编写应用程序,但它也需要在Vista和XP下运行 User32 API LockWorkStation不工作,因为它需要一个交互式桌面,我得到的返回值为0 我尝试从进程和Shell调用%windir%\System32\rundll32.exe user32.dll、lockstation,但仍然没有任何结果 设置该服务与桌面交互是不可行的,因为我正在以管理员帐户运行该服务,因此它可以执行其他需要管理员权限的操作

我需要从用VB.Net编写的windows服务中锁定工作站。我正在Windows7上编写应用程序,但它也需要在Vista和XP下运行

User32 API LockWorkStation不工作,因为它需要一个交互式桌面,我得到的返回值为0

我尝试从进程和Shell调用%windir%\System32\rundll32.exe user32.dll、lockstation,但仍然没有任何结果

设置该服务与桌面交互是不可行的,因为我正在以管理员帐户运行该服务,因此它可以执行其他需要管理员权限的操作,例如禁用网络,并且如果在本地系统帐户下运行,则只能选择“与桌面交互”选项

这将是第二个问题-如何从本地系统帐户下运行的服务中运行另一个具有管理员权限的应用程序,而不干扰用户

我正在编写一个应用程序来控制我孩子的计算机/互联网访问(我计划在完成后开源),所以我需要一切尽可能秘密地进行

我有一个UI,可以处理任务栏中的设置和状态通知,但这很容易终止,从而破坏锁定。我可以制作另一个隐藏的Windows窗体应用程序来处理锁定,但这似乎是一个相当不雅观的解决方案


任何人都有更好的想法?

另一个不雅观的解决方案(但没有向UI应用程序发送信号的缺点)是安装另一个服务,与桌面交互,桌面的任务是监听锁定桌面的信号


我同意必须使用本地系统凭据运行不是件好事,但如果该服务所做的只是锁定桌面,那么需要保护的占用空间就相当小。

您试图做的事情被Microsoft积极阻止-如果您确实让它工作起来,它将利用一个漏洞,这个漏洞肯定很快就会被关闭


不过,您可以做的是解决方案——让两个程序运行并相互监控。当一个用户被杀死时,另一个会检测到并重新启动它(或者,根据您希望的严重程度,将当前用户注销作为惩罚).

您可以尝试从windows服务启动一个屏幕保护程序,自动锁定工作站。

我对我的答案并不完全满意,但windows的安全性让我别无选择。在服务中打开的任何内容(通过进程、Shell等)都将无法访问桌面。我理解微软创造的限制背后的原因,但仍然令人沮丧

我的服务使用IPC通知我的UI锁定计算机。下面是一个基本的链接:

更多数据请参见他的参考链接

然而,这仍然不起作用。另请参阅此链接,了解如何在没有访问被拒绝消息的情况下执行此操作:

确保您的URI是正确的。服务器端的portName属性是GetObject方法调用中IPC路径的第一部分。第二部分映射到服务器端的RegisterWellKnownServiceType调用的第二个参数

显然,服务器端和客户端的端口名属性需要不同


如果您的客户端出现“无法连接到IPC端口:系统找不到指定的文件”。则服务器尚未启动,因此没有听到您的尖叫声。

我已经为此争论了一个多星期,在阅读了大量有关此问题的信息后,终于找到了此问题的解决方案

您必须像这样使用CreateProcessAsUser函数:

  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
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)
获取了大部分代码,您还可以从中找到与此函数一起使用的WindowsApi。 我仍在努力寻找是否可以避免bat文件,但至少是一个非常好的解决方案

编辑: 要避免使用外部*.bat文件执行代码,只需编辑WindowsApi类并用以下内容替换CreateProcessAsUser和advapi32.dll导入部分:

    <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
它会起作用的

问候,,
AP

为了与服务中的用户会话进行交互,首先需要使用用户会话id。基本上,在调用
CreateProcessAsUser
之前,需要使用
WTSGetActiveConsoleSessionId
WTSGetActiveConsoleSessionId
CreateEnvironmentBlock
重要的部分是
CreateEnvironmentBlock
。前两种方法允许我们不使用预定义的用户名/密码。 Python代码段作为从服务锁定工作站的概念证明,如下所示:

导入win32process
导入win32con
导入win32ts
控制台会话id=win32ts.WTSGetActiveConsoleSessionId()
控制台用户令牌=win32ts.WTSQueryUserToken(控制台会话标识)
startup=win32process.STARTUPINFO()
优先级=win32con.NORMAL\u优先级\u类
environment=win32profile.CreateEnvironmentBlock(控制台\用户\令牌,False)
句柄,线程id,pid,tid=win32process.CreateProcessAsUser(控制台用户令牌,无,“rundll32.exe user32.dll,锁工作站”,无,无,真,优先级,环境,无,启动)

我认为这是一个很好的方法。自会话0隔离以来,与桌面交互已成为历史。我还不知道从服务向UI发送信号有什么困难,但我希望避免添加另一个部分(2个服务加上UI)。另外,我听说Vista中不推荐使用桌面交互,但我在7年前就看到了。(我自己跳过了Vista)。不确定我是否能相信它会留下来?有什么想法?我忘了加强会话0对桌面的访问。我的建议似乎过于脆弱,依赖于不同版本的Windows如何让(或阻止)服务与桌面交互。我同意有两个服务会留下一些不尽如人意的东西(假设它甚至可以工作)。我必须做一些研究来找出答案(所以我是公关)