C# 从Windows服务以编程方式锁定工作站
在我的Windows服务中,我尝试使用以下代码锁定我的工作站:C# 从Windows服务以编程方式锁定工作站,c#,visual-studio-2015,windows-services,C#,Visual Studio 2015,Windows Services,在我的Windows服务中,我尝试使用以下代码锁定我的工作站: [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool LockWorkStation(); if (!LockWorkStation()){ //Workstation was unable to lock(Write this on event log) } 但是上面的
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool LockWorkStation();
if (!LockWorkStation()){
//Workstation was unable to lock(Write this on event log)
}
但是上面的代码不起作用
有人对此有解决方案吗?您不能从Windows服务中执行此操作,因为它清楚地说明,此API函数只能从交互式桌面中运行的进程调用。Windows服务未在交互式桌面中运行
若必须这样做,则应首先检查用户是否已登录,然后在要锁定的inpersonating用户下生成进程。但在我看来,这是一个相当老套的解决方案。也许更好的解决方案是在用户登录时启动隐藏或托盘应用程序,然后从该应用程序执行作业。Windows服务不在桌面上运行,因此您无法从该服务调用它 从文档中,强调我的: LockWorkStation功能只能由交互式桌面上运行的进程调用。此外,用户必须登录,并且工作站不能已经锁定 这可能是一种黑客行为,但您可以创建一个托盘应用程序,该应用程序可以响应来自服务的某种进程间调用,调用
LockWorkStation
如果您不喜欢托盘应用程序的可见性质,请考虑创建一个控制台应用程序,该程序生成线程等待调用,并在用户登录时运行无窗口。 另一种可能是创建一个从不创建UI窗口的Windows应用程序。如果您使用API,这绝对是您想要做的
这里的关键是,某些东西必须在用户的交互上下文中运行 作为参考,您可以查看。您可以使用Windows API执行此操作,它将以与LockWorkStation相同的方式注销用户 但是,由于该服务处于特殊会话中,您不能仅断开WTS_当前_会话,而必须断开计算机上的每个活动会话using System;
using System.Runtime.InteropServices;
public class LockWorkstation
{
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern bool WTSDisconnectSession(IntPtr hServer, int sessionId, bool bWait);
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern int WTSEnumerateSessions(IntPtr hServer, int Reserved, int Version, ref IntPtr ppSessionInfo, ref int pCount);
[DllImport("wtsapi32.dll")]
static extern void WTSFreeMemory(IntPtr pMemory);
[StructLayout(LayoutKind.Sequential)]
private struct WTS_SESSION_INFO
{
public Int32 SessionID;
[MarshalAs(UnmanagedType.LPStr)]
public String pWinStationName;
public WTS_CONNECTSTATE_CLASS State;
}
private enum WTS_INFO_CLASS
{
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType
}
private enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}
public static void LockWorkStation()
{
IntPtr ppSessionInfo = IntPtr.Zero;
Int32 count = 0;
Int32 retval = WTSEnumerateSessions(IntPtr.Zero, 0, 1, ref ppSessionInfo, ref count);
Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
IntPtr currentSession = ppSessionInfo;
if (retval == 0) return;
for (int i = 0; i < count; i++)
{
WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure(currentSession, typeof(WTS_SESSION_INFO));
if (si.State == WTS_CONNECTSTATE_CLASS.WTSActive) WTSDisconnectSession(IntPtr.Zero, si.SessionID, false);
currentSession += dataSize;
}
WTSFreeMemory(ppSessionInfo);
}
}
使用系统;
使用System.Runtime.InteropServices;
公营锁具工作站
{
[DllImport(“wtsapi32.dll”,SetLastError=true)]
静态外部bool-WTSDisconnectSession(IntPtr-hServer、int-sessionId、bool-bWait);
[DllImport(“wtsapi32.dll”,SetLastError=true)]
静态外部int WTSEnumeratessions(IntPtr hServer、int Reserved、int Version、ref IntPtr ppSessionInfo、ref int pCount);
[DllImport(“wtsapi32.dll”)]
静态外部无效WTSFreeMemory(IntPtr pMemory);
[StructLayout(LayoutKind.Sequential)]
私有结构WTS\u会话\u信息
{
公共Int32会话ID;
[Marshallas(UnmanagedType.LPStr)]
公共字符串pInstallationName;
公共WTS_CONNECTSTATE_CLASS State;
}
私有枚举WTS_信息_类
{
中国程序,
WTS应用程序名称,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
苏瑟南,
WTSWinStationName,
WTSDomainName,
WTS连接状态,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType
}
私有枚举WTS_连接状态_类
{
是的,
WTS连接,
WTSConnectQuery,
WTSShadow,
WTS断开连接,
西德尔,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}
公共静态无效锁定工作站()
{
IntPtr ppSessionInfo=IntPtr.Zero;
Int32计数=0;
Int32 retval=WTSEnumerateSessions(IntPtr.Zero,0,1,ref-ppSessionInfo,ref-count);
Int32 dataSize=Marshal.SizeOf(typeof(WTS_SESSION_INFO));
IntPtr currentSession=ppSessionInfo;
如果(retval==0)返回;
for(int i=0;i
除了创建托盘应用程序,还有其他解决方案吗?如果可能,请给我一个链接。我用另一个选项更新了我的答案。我不认为你可以从服务中生成一个应用程序,如果可以的话,它可能会像Antonio提到的那样更加黑客。为了澄清,我可以在windows服务下调用控制台应用程序吗?你可以使用某种形式的IPC调用控制台应用程序或无头win32进程。搜索“windows进程间通信”以获得一些想法。更奇特的可能是消息总线或使用套接字,但这可能有些过分,因为您知道进程在同一台机器上。你可以做一些超级黑客的事情,比如在控制台应用程序中实现一个文件监视程序,监视服务删除文件,但这有点笨重。可能不是控制台应用程序,因为它们是可见的。(即使您立即隐藏控制台,它仍然会短暂弹出。)它们也会使用更多资源。最好将其配置为Windows应用程序,然后永远不要创建任何窗口。如果我没有将您的标记为正确答案,我很抱歉,但我会给您投票。在用户会话中启动进程以代表您工作是一项相当成熟的技术。我不会称之为黑客。(与使用在每个用户会话中永久运行的应用程序相比,有几个优点,最重要的可能是没有真正可靠的方法来做到这一点。)并不意味着在用户会话中启动过程是一种黑客行为。我说的是从服务中锁定用户会话,将更新我的回答你确定这与Windows+L相同吗?@JobaDiniz这与在每个打开的服务器上执行Windows+L相同