我要开发一个系统服务,服务的作用是定时检测并关闭其他应用的弹窗,但是开发后却发现,服务在运行是压根获取不到任何窗口。
原因在于
Windows服务一般在Session0里,EXE应用一般在Session1里,Win7及以后的系统将服务与应用程序进行了Session隔离,不允许其进行UI交互,可以考虑穿透Session隔离来启动。
这样就想到另一个方法,把业务写成一个控制台程序,在服务中调用,但是依旧不行
服务中启动的其他应用依旧会在Session0中。
那我们就要想个方法能在Session1中运行的方法。
总的来说有以下注意点
LocalSystem
,安装服务后的登录身份则为本地系统账户C:\Users\Administrator\
目录下运行,不然启动服务的时候会遇到权限问题创建后在Service1.cs
的设计试图上右键 添加安装程序
之后会出现以下两个
点击1
对应的属性 设置 Account
设置为 LocalSystem
点击2
其中
ServiceName
就是安装后显示的服务名称
支持中文
StartType
是启动的方式 默认是手动
这里设置为自动
(Automatic),
但是注意就算设置为自动在安装服务后也不会自动启动,只有下次重启电脑时才会自动启动。
如图
服务代码
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
log("服务-启动");
closePopWin();
}
protected override void OnStop()
{
log("服务-停止");
}
public void closePopWin()
{
new Thread(o =>
{
while (true)
{
try
{
string exeFile = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "CloseWPSPopWin.exe");
WinAPIInterop.CreateProcess(exeFile);
closeWpsWins();
}
catch (Exception ex)
{
log(ex.Message);
}
Thread.Sleep(1000);
}
})
{
IsBackground = true
}.Start();
}
public static void closeWpsWins()
{
try
{
var windows = WindowEnumerator.FindAll();
for (int i = 0; i < windows.Count; i++)
{
var win = windows[i];
if (win.Title.Contains("WPS") && !win.IsTop)
{
WindowEnumerator.CloseWin(win.Hwnd);
}
}
}
catch (Exception)
{
}
}
private static void log(string content)
{
if (string.IsNullOrEmpty(content))
{
return;
}
try
{
string logFile = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, string.Format("service.{0:yyyyMMdd}.log", DateTime.Now));
using (FileStream fileStream = new FileStream(logFile, FileMode.Append, FileAccess.Write))
{
using (StreamWriter streamWriter = new StreamWriter(fileStream))
{
string time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
streamWriter.WriteLine(time + " " + content);
}
}
}
catch { }
}
}
界面效果
服务安装后我们可以通过下面的命令打开服务面板
services.msc
窗口对应的代码
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
selectFileBtn.Click += SelectFileBtn_Click;
installBtn.Click += InstallBtn_Click;
unInstallBtn.Click += UnInstallBtn_Click;
startBtn.Click += StartBtn_Click;
stopBtn.Click += StopBtn_Click;
}
private void StartBtn_Click(object sender, RoutedEventArgs e)
{
if (serviceNameTb.Text != "")
{
if (ServiceUtil.IsServiceExisted(serviceNameTb.Text))
{
ServiceUtil.ServiceStart(serviceNameTb.Text);
}
}
}
private void StopBtn_Click(object sender, RoutedEventArgs e)
{
if (serviceNameTb.Text != "")
{
if (ServiceUtil.IsServiceExisted(serviceNameTb.Text))
{
ServiceUtil.ServiceStop(serviceNameTb.Text);
}
}
}
private void UnInstallBtn_Click(object sender, RoutedEventArgs e)
{
if (filePathTb.Text != "")
{
ServiceUtil.UninstallService(filePathTb.Text);
}
}
private void InstallBtn_Click(object sender, RoutedEventArgs e)
{
if (filePathTb.Text != "")
{
ServiceUtil.InstallService(filePathTb.Text);
}
}
private void SelectFileBtn_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
ofd.Filter = "可执行程序|*.exe";
//ofd.InitialDirectory = desktopPath;
ofd.Multiselect = false;
ofd.AddExtension = true;
ofd.DereferenceLinks = true;
if (ofd.ShowDialog() == true)
{
filePathTb.Text = ofd.FileName;
}
}
}
服务操作工具类
using System;
using System.Collections;
using System.Configuration.Install;
using System.ServiceProcess;
namespace WPSServiceClient.Utils
{
internal class ServiceUtil
{
//判断服务是否存在
public static bool IsServiceExisted(string serviceName)
{
ServiceController[] services = ServiceController.GetServices();
foreach (ServiceController sc in services)
{
if (sc.ServiceName.ToLower() == serviceName.ToLower())
{
return true;
}
}
return false;
}
//安装服务
public static void InstallService(string serviceFilePath)
{
using (AssemblyInstaller installer = new AssemblyInstaller())
{
installer.UseNewContext = true;
installer.Path = serviceFilePath;
IDictionary savedState = new Hashtable();
installer.Install(savedState);
installer.Commit(savedState);
}
}
//卸载服务
public static bool UninstallService(string serviceFilePath)
{
using (AssemblyInstaller installer = new AssemblyInstaller())
{
try
{
installer.UseNewContext = true;
installer.Path = serviceFilePath;
installer.Uninstall(null);
return true;
}
catch (Exception) {
return false;
}
}
}
//启动服务
public static void ServiceStart(string serviceName)
{
using (ServiceController control = new ServiceController(serviceName))
{
if (control.Status == ServiceControllerStatus.Stopped)
{
control.Start();
}
}
}
//停止服务
public static void ServiceStop(string serviceName)
{
using (ServiceController control = new ServiceController(serviceName))
{
if (control.Status == ServiceControllerStatus.Running)
{
control.Stop();
}
}
}
}
}
我们之前运行是这样的
但是这种方法会在所在的Session中运行,所以这里是不行的。
string exeFile = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "CloseWPSPopWin.exe");
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = exeFile;
start.Arguments = "";
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
log("执行 " + exeFile);
//启动调用
using (Process process = Process.Start(start))
{
//接收控制台输出的消息
process.OutputDataReceived += (s1, e1) =>
{
if (e1 != null && e1.Data != null && e1.Data.Equals("Update"))
{
Process[] p = System.Diagnostics.Process.GetProcessesByName("Starter");
p[0].Kill();
}
};
process.BeginOutputReadLine();
//等待退出
process.WaitForExit();
}
调用方式
WinAPIInterop.CreateProcess(exeFile);
工具类
public class WinAPIInterop
{
public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
/// <summary>
/// 服务程序执行消息提示,前台MessageBox.Show
/// </summary>
/// <param name="message">消息内容</param>
/// <param name="title">标题</param>
public static void ShowServiceMessage(string message, string title)
{
int resp = 0;
WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, WTSGetActiveConsoleSessionId(), title, title.Length, message, message.Length, 0, 0, out resp, false);
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int WTSGetActiveConsoleSessionId();
[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern bool WTSSendMessage(IntPtr hServer, int SessionId, String pTitle, int TitleLength, String pMessage, int MessageLength, int Style, int Timeout, out int pResponse, bool bWait);
#region P/Invoke WTS APIs
private enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct WTS_SESSION_INFO
{
public UInt32 SessionID;
public string pWinStationName;
public WTS_CONNECTSTATE_CLASS State;
}
[DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool WTSEnumerateSessions(
IntPtr hServer,
[MarshalAs(UnmanagedType.U4)] UInt32 Reserved,
[MarshalAs(UnmanagedType.U4)] UInt32 Version,
ref IntPtr ppSessionInfo,
[MarshalAs(UnmanagedType.U4)] ref UInt32 pSessionInfoCount
);
[DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
private static extern void WTSFreeMemory(IntPtr pMemory);
[DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
#endregion P/Invoke WTS APIs
#region P/Invoke CreateProcessAsUser
/// <summary>
/// Struct, Enum and P/Invoke Declarations for CreateProcessAsUser.
/// </summary>
///
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
/// <summary>
/// 以当前登录的windows用户(角色权限)运行指定程序进程
/// </summary>
/// <param name="hToken"></param>
/// <param name="lpApplicationName">指定程序(全路径)</param>
/// <param name="lpCommandLine">参数</param>
/// <param name="lpProcessAttributes">进程属性</param>
/// <param name="lpThreadAttributes">线程属性</param>
/// <param name="bInheritHandles"></param>
/// <param name="dwCreationFlags"></param>
/// <param name="lpEnvironment"></param>
/// <param name="lpCurrentDirectory"></param>
/// <param name="lpStartupInfo">程序启动属性</param>
/// <param name="lpProcessInformation">最后返回的进程信息</param>
/// <returns>是否调用成功</returns>
[DllImport("ADVAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes,
bool bInheritHandles, uint dwCreationFlags, string lpEnvironment, string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
[DllImport("KERNEL32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool CloseHandle(IntPtr hHandle);
#endregion P/Invoke CreateProcessAsUser
/// <summary>
/// 以当前登录系统的用户角色权限启动指定的进程
/// </summary>
/// <param name="ChildProcName">指定的进程(全路径)</param>
public static void CreateProcess(string ChildProcName)
{
IntPtr ppSessionInfo = IntPtr.Zero;
UInt32 SessionCount = 0;
if (WTSEnumerateSessions(
(IntPtr)WTS_CURRENT_SERVER_HANDLE, // Current RD Session Host Server handle would be zero.
0, // This reserved parameter must be zero.
1, // The version of the enumeration request must be 1.
ref ppSessionInfo, // This would point to an array of session info.
ref SessionCount // This would indicate the length of the above array.
))
{
for (int nCount = 0; nCount < SessionCount; nCount++)
{
WTS_SESSION_INFO tSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure(ppSessionInfo + nCount * Marshal.SizeOf(typeof(WTS_SESSION_INFO)), typeof(WTS_SESSION_INFO));
if (WTS_CONNECTSTATE_CLASS.WTSActive == tSessionInfo.State)
{
IntPtr hToken = IntPtr.Zero;
if (WTSQueryUserToken(tSessionInfo.SessionID, out hToken))
{
PROCESS_INFORMATION tProcessInfo;
STARTUPINFO tStartUpInfo = new STARTUPINFO();
tStartUpInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
bool ChildProcStarted = CreateProcessAsUser(
hToken, // Token of the logged-on user.
ChildProcName, // Name of the process to be started.
null, // Any command line arguments to be passed.
IntPtr.Zero, // Default Process' attributes.
IntPtr.Zero, // Default Thread's attributes.
false, // Does NOT inherit parent's handles.
0, // No any specific creation flag.
null, // Default environment path.
null, // Default current directory.
ref tStartUpInfo, // Process Startup Info.
out tProcessInfo // Process information to be returned.
);
if (ChildProcStarted)
{
CloseHandle(tProcessInfo.hThread);
CloseHandle(tProcessInfo.hProcess);
}
else
{
ShowServiceMessage("CreateProcessAsUser失败", "CreateProcess");
}
CloseHandle(hToken);
break;
}
}
}
WTSFreeMemory(ppSessionInfo);
}
}
}
调用方式
ApplicationLoader.PROCESS_INFORMATION procInfo;
ApplicationLoader.StartProcessAndBypassUAC(exeFile, out procInfo);
工具类
/// <summary>
/// Class that allows running applications with full admin rights. In
/// addition the application launched will bypass the Vista UAC prompt.
/// </summary>
public class ApplicationLoader
{
#region Structrures
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public int cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
#endregion Structrures
#region Enumberation
private enum TOKEN_TYPE : int
{
TokenPrimary = 1,
TokenImpersonation = 2
}
private enum SECURITY_IMPERSONATION_LEVEL : int
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3,
}
#endregion Enumberation
#region Constants
public const int TOKEN_DUPLICATE = 0x0002;
public const uint MAXIMUM_ALLOWED = 0x2000000;
public const int CREATE_NEW_CONSOLE = 0x00000010;
public const int IDLE_PRIORITY_CLASS = 0x40;
public const int NORMAL_PRIORITY_CLASS = 0x20;
public const int HIGH_PRIORITY_CLASS = 0x80;
public const int REALTIME_PRIORITY_CLASS = 0x100;
#endregion Constants
#region Win32 API Imports
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hSnapshot);
[DllImport("kernel32.dll")]
private static extern uint WTSGetActiveConsoleSessionId();
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment,
String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll")]
private static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType,
int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
[DllImport("kernel32.dll")]
private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
[DllImport("advapi32.dll", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
private static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);
//[DllImport("advapi32.dll", SetLastError = true)]
//[return: MarshalAs(UnmanagedType.Bool)]
//static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, ref IntPtr TokenHandle);
#endregion Win32 API Imports
/// <summary>
/// Launches the given application with full admin rights, and in addition bypasses the Vista UAC prompt
/// </summary>
/// <param name="applicationName">The name of the application to launch</param>
/// <param name="procInfo">Process information regarding the launched application that gets returned to the caller</param>
/// <returns></returns>
public static bool StartProcessAndBypassUAC(String applicationName, out PROCESS_INFORMATION procInfo)
{
uint winlogonPid = 0;
IntPtr hUserTokenDup = IntPtr.Zero,
hPToken = IntPtr.Zero,
hProcess = IntPtr.Zero;
procInfo = new PROCESS_INFORMATION();
// obtain the currently active session id; every logged on user in the system has a unique session id
TSControl.WTS_SESSION_INFO[] pSessionInfo = TSControl.SessionEnumeration();
uint dwSessionId = 100;
for (int i = 0; i < pSessionInfo.Length; i++)
{
if (pSessionInfo[i].SessionID != 0)
{
try
{
int count = 0;
IntPtr buffer = IntPtr.Zero;
StringBuilder sb = new StringBuilder();
bool bsuccess = TSControl.WTSQuerySessionInformation(
IntPtr.Zero, pSessionInfo[i].SessionID,
TSControl.WTSInfoClass.WTSUserName, out sb, out count);
if (bsuccess)
{
if (sb.ToString().Trim() == "Administrator")//Administrator
{
dwSessionId = (uint)pSessionInfo[i].SessionID;
}
}
}
catch (Exception ex)
{
}
}
}
// obtain the process id of the winlogon process that is running within the currently active session
Process[] processes = Process.GetProcessesByName("explorer");
foreach (Process p in processes)
{
if ((uint)p.SessionId == dwSessionId)
{
winlogonPid = (uint)p.Id;
}
}
// obtain a handle to the winlogon process
hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
// obtain a handle to the access token of the winlogon process
if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken))
{
CloseHandle(hProcess);
return false;
}
// Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser
// I would prefer to not have to use a security attribute variable and to just
// simply pass null and inherit (by default) the security attributes
// of the existing token. However, in C# structures are value types and therefore
// cannot be assigned the null value.
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
// copy the access token of the winlogon process; the newly created token will be a primary token
if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup))
{
CloseHandle(hProcess);
CloseHandle(hPToken);
return false;
}
// By default CreateProcessAsUser creates a process on a non-interactive window station, meaning
// the window station has a desktop that is invisible and the process is incapable of receiving
// user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user
// interaction with the new process.
STARTUPINFO si = new STARTUPINFO();
si.cb = (int)Marshal.SizeOf(si);
si.lpDesktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop
// flags that specify the priority and creation method of the process
int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
// create a new process in the current user's logon session
bool result = CreateProcessAsUser(hUserTokenDup, // client's access token
null, // file to execute
applicationName, // command line
ref sa, // pointer to process SECURITY_ATTRIBUTES
ref sa, // pointer to thread SECURITY_ATTRIBUTES
false, // handles are not inheritable
dwCreationFlags, // creation flags
IntPtr.Zero, // pointer to new environment block
null, // name of current directory
ref si, // pointer to STARTUPINFO structure
out procInfo // receives information about new process
);
// invalidate the handles
CloseHandle(hProcess);
CloseHandle(hPToken);
CloseHandle(hUserTokenDup);
//LoaderService.WriteLog("launch Task", "Monitor");
return result; // return the result
}
}
public class TSControl
{
/**/
/// <summary>
/// Terminal Services API Functions,The WTSEnumerateSessions function retrieves a list of sessions on a specified terminal server,
/// </summary>
/// <param name="hServer">[in] Handle to a terminal server. Specify a handle opened by the WTSOpenServer function, or specify WTS_CURRENT_SERVER_HANDLE to indicate the terminal server on which your application is running</param>
/// <param name="Reserved">Reserved; must be zero</param>
/// <param name="Version">[in] Specifies the version of the enumeration request. Must be 1. </param>
/// <param name="ppSessionInfo">[out] Pointer to a variable that receives a pointer to an array of WTS_SESSION_INFO structures. Each structure in the array contains information about a session on the specified terminal server. To free the returned buffer, call the WTSFreeMemory function.
/// To be able to enumerate a session, you need to have the Query Information permission.</param>
/// <param name="pCount">[out] Pointer to the variable that receives the number of WTS_SESSION_INFO structures returned in the ppSessionInfo buffer. </param>
/// <returns>If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero</returns>
[DllImport("wtsapi32", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool WTSEnumerateSessions(int hServer, int Reserved, int Version, ref long ppSessionInfo, ref int pCount);
/**/
/// <summary>
/// Terminal Services API Functions,The WTSFreeMemory function frees memory allocated by a Terminal Services function.
/// </summary>
/// <param name="pMemory">[in] Pointer to the memory to free</param>
[DllImport("wtsapi32.dll")]
public static extern void WTSFreeMemory(System.IntPtr pMemory);
/**/
/// <summary>
/// Terminal Services API Functions,The WTSLogoffSession function logs off a specified Terminal Services session.
/// </summary>
/// <param name="hServer">[in] Handle to a terminal server. Specify a handle opened by the WTSOpenServer function, or specify WTS_CURRENT_SERVER_HANDLE to indicate the terminal server on which your application is running. </param>
/// <param name="SessionId">[in] A Terminal Services session identifier. To indicate the current session, specify WTS_CURRENT_SESSION. You can use the WTSEnumerateSessions function to retrieve the identifiers of all sessions on a specified terminal server.
/// To be able to log off another user's session, you need to have the Reset permission </param>
/// <param name="bWait">[in] Indicates whether the operation is synchronous.
/// If bWait is TRUE, the function returns when the session is logged off.
/// If bWait is FALSE, the function returns immediately.</param>
/// <returns>If the function succeeds, the return value is a nonzero value.
/// If the function fails, the return value is zero.</returns>
[DllImport("wtsapi32.dll")]
public static extern bool WTSLogoffSession(int hServer, long SessionId, bool bWait);
[DllImport("Wtsapi32.dll")]
public static extern bool WTSQuerySessionInformation(
System.IntPtr hServer,
int sessionId,
WTSInfoClass wtsInfoClass,
out StringBuilder ppBuffer,
out int pBytesReturned
);
public enum WTSInfoClass
{
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType
}
/**/
/// <summary>
/// The WTS_CONNECTSTATE_CLASS enumeration type contains INT values that indicate the connection state of a Terminal Services session.
/// </summary>
public enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit,
}
/**/
/// <summary>
/// The WTS_SESSION_INFO structure contains information about a client session on a terminal server.
/// if the WTS_SESSION_INFO.SessionID==0, it means that the SESSION is the local logon user's session.
/// </summary>
public struct WTS_SESSION_INFO
{
public int SessionID;
[MarshalAs(UnmanagedType.LPTStr)]
public string pWinStationName;
public WTS_CONNECTSTATE_CLASS state;
}
/**/
/// <summary>
/// The SessionEnumeration function retrieves a list of
///WTS_SESSION_INFO on a current terminal server.
/// </summary>
/// <returns>a list of WTS_SESSION_INFO on a current terminal server</returns>
public static WTS_SESSION_INFO[] SessionEnumeration()
{
//Set handle of terminal server as the current terminal server
int hServer = 0;
bool RetVal;
long lpBuffer = 0;
int Count = 0;
long p;
WTS_SESSION_INFO Session_Info = new WTS_SESSION_INFO();
WTS_SESSION_INFO[] arrSessionInfo;
RetVal = WTSEnumerateSessions(hServer, 0, 1, ref lpBuffer, ref Count);
arrSessionInfo = new WTS_SESSION_INFO[0];
if (RetVal)
{
arrSessionInfo = new WTS_SESSION_INFO[Count];
int i;
p = lpBuffer;
for (i = 0; i < Count; i++)
{
arrSessionInfo[i] =
(WTS_SESSION_INFO)Marshal.PtrToStructure(new IntPtr(p),
Session_Info.GetType());
p += Marshal.SizeOf(Session_Info.GetType());
}
WTSFreeMemory(new IntPtr(lpBuffer));
}
else
{
//Insert Error Reaction Here
}
return arrSessionInfo;
}
public TSControl()
{
}
}
把输出类型 改为 Windows应用程序