system启动普通权限UI应用
注意:启动传参,使用变量; 补充添加,传递上下文环境变量
参考: https://www.cnblogs.com/fatterbetter/p/4203094.html
注意传参的第一个参数为agr[0] 默认为启动路径 agr[1]才是真正参数,C函数
using System;
using System.Runtime.InteropServices;
namespace LinseerCopilotServiceImpl.Services
{
public class ProcessAsUser
{
public struct SECURITY_ATTRIBUTES
{
public uint nLength;
public uint lpSecurityDescriptor;
public bool bInheritHandle;
}
public struct STARTUPINFO
{
public uint 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 ushort wShowWindow;
public ushort cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[DllImport("kernel32.dll")]
static extern uint WTSGetActiveConsoleSessionId();
[DllImport("Wtsapi32.dll")]
private static extern bool WTSQueryUserToken(uint SessionId, out uint hToken);
[DllImport("Kernel32.dll")]
private static extern uint GetLastError();
[DllImport("kernel32.dll")]
private static extern bool CloseHandle(IntPtr hSnapshot);
[DllImport("advapi32.dll")]
public extern static bool CreateProcessAsUser(IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandle,
uint dwCreationFlags,
uint lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
/// <summary>
/// 从服务启动外部UI应用进程
/// </summary>
/// <remarks>服务是System权限,应用是普通权限</remarks>
/// <param name="exePath"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static PROCESS_INFORMATION StartUIProcessFromService(string exePath)
{
//获取Session ID
var sId = WTSGetActiveConsoleSessionId();
H3CLog.Info($"WTSGetActiveConsoleSessionId:{sId}");
if (sId == 0)
{
var errorCode = GetLastError();
throw new Exception($"CreateProcessAsUser failed, WTSGetActiveConsoleSessionId failed with error code:{errorCode}.");
}
uint hToken;
var isOk = WTSQueryUserToken(sId, out hToken);
H3CLog.Info($"WTSQueryUserToken:{hToken}");
if (!isOk || hToken == 0)
{
var errorCode = GetLastError();
throw new Exception($"CreateProcessAsUser failed, WTSQueryUserToken failed with error code:{errorCode}.");
}
var lpProcessAttr = new SECURITY_ATTRIBUTES();
lpProcessAttr.nLength = (uint)Marshal.SizeOf(lpProcessAttr);
var lpThreadAttr = new SECURITY_ATTRIBUTES();
lpThreadAttr.nLength = (uint)Marshal.SizeOf(lpThreadAttr);
var lpStratupInfo = new STARTUPINFO();
lpStratupInfo.cb = (uint)Marshal.SizeOf(lpStratupInfo);
lpStratupInfo.lpDesktop = @"winsta0\default";
PROCESS_INFORMATION lpProcessInfo;
string arguments = "LinseerCopilotService";
string commandLine = $"\"{exePath}\" {arguments}"; // 创建一个完整的命令行字符串
isOk = CreateProcessAsUser((IntPtr)hToken, exePath, commandLine, ref lpProcessAttr, ref lpThreadAttr, false, 0, 0, null, ref lpStratupInfo, out lpProcessInfo);
CloseHandle((IntPtr)hToken);
if (!isOk)
{
var errorCode = GetLastError();
throw new Exception($"CreateProcessAsUser failed with error code: {errorCode}");
}
return lpProcessInfo;
}
}
}
using System;
using System.IO;
using System.Diagnostics;
using System.Threading;
using LinseerCopilotServiceImpl.Services;
using Topshelf;
using System.Threading.Tasks;
namespace LinseerCopilotServiceImpl.Business
{
internal class UiProcessManager : IServiceBusiness
{
#region Fields
AutoResetEvent _resetEvent = new AutoResetEvent(false);
private bool _isRunning = false;
private readonly string LinseerCopilotAppName = "LinseerCopilot";
#endregion
#region Constructors
public UiProcessManager()
{
}
#endregion
#region Private Methods
private void ProcessAppStarting()
{
while (_isRunning)
{
_resetEvent.WaitOne();
if (!_isRunning)
{
break;
}
try
{
StopExistApps();
string exePath = GetAppEntryPath();
var result = ProcessAsUser.StartUIProcessFromService(exePath);
H3CLog.Info($"Success to start {LinseerCopilotAppName},Process ID:{result.dwProcessId}");
}
catch (Exception ex)
{
H3CLog.Error($"Fail to start {LinseerCopilotAppName}", ex);
}
}
}
private string GetAppEntryPath()
{
string processPath = Process.GetCurrentProcess().MainModule.FileName;
if (string.IsNullOrEmpty(processPath))
{
throw new FileNotFoundException("ProcessPath is null or empty");
}
DirectoryInfo dirInfo = new FileInfo(processPath).Directory;
if (dirInfo == null)
{
throw new DirectoryNotFoundException($"ProcessPath is not a directory, path:[{processPath}]");
}
var parentDir = dirInfo.Parent;
if (parentDir == null)
{
throw new DirectoryNotFoundException($"ParentDir is null, path:[{processPath}]");
}
string exePath = Path.Combine(parentDir.FullName, "LinseerCopilot", "H3C.Entry.exe");
if (!File.Exists(exePath))
{
throw new FileNotFoundException($"{LinseerCopilotAppName} exePath is null or file does not exist, exe path:[${exePath}]");
}
H3CLog.Info($"启动外部进程的路径: {exePath}");
return exePath;
}
private void StopExistApps()
{
Process[] processes = Process.GetProcessesByName(LinseerCopilotAppName);
foreach (var process in processes)
{
try
{
H3CLog.Info($"Success to close {LinseerCopilotAppName},Process ID:{process.Id}");
process.Kill();
}
catch (Exception ex)
{
H3CLog.Error($"Fail to stop {LinseerCopilotAppName}", ex);
}
}
}
private async Task RunAppAsync()
{
await Task.Run(() =>
{
_resetEvent.Set();
//try
//{
// StopApp();
// string exePath = GetAppEntryPath();
// var result = ProcessAsUser.StartUIProcessFromService(exePath);
// _systemControlAppProcessId = (int)result.dwProcessId;
// H3CLog.Info($"Success to start SystemControl,Process ID:{_systemControlAppProcessId}");
//}
//catch (Exception ex)
//{
// H3CLog.Error("Fail to start SystemControl", ex);
//}
});
}
#endregion
#region Public Methods
public async Task StartAsync()
{
if (_isRunning) return;
Thread thread = new Thread(ProcessAppStarting);
thread.IsBackground = true;
_isRunning = true;
thread.Start();
await RunAppAsync();
}
public async Task StopAsync()
{
_isRunning = false;
_resetEvent.Set();
await Task.CompletedTask;
}
public async Task PauseAsync()
{
await Task.CompletedTask;
}
public async Task ContinueAsync()
{
await Task.CompletedTask;
}
public async Task OnSessionChangedAsync(SessionChangedArguments session)
{
if (session.ReasonCode == SessionChangeReasonCode.SessionUnlock || session.ReasonCode == SessionChangeReasonCode.SessionLogon)
{
H3CLog.Info("Session changed, start app");
await RunAppAsync();
}
}
#endregion
}
}
** 补充添加,传递上下文环境变量**
public class ProcessAsUser
{
public struct SECURITY_ATTRIBUTES
{
public uint nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
public struct STARTUPINFO
{
public uint 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 ushort wShowWindow;
public ushort cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[DllImport("kernel32.dll")]
static extern uint WTSGetActiveConsoleSessionId();
[DllImport("Wtsapi32.dll")]
private static extern bool WTSQueryUserToken(uint SessionId, out IntPtr hToken);
[DllImport("Kernel32.dll")]
private static extern uint GetLastError();
[DllImport("kernel32.dll")]
private static extern bool CloseHandle(IntPtr hSnapshot);
[DllImport("advapi32.dll")]
public extern static bool CreateProcessAsUser(IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandle,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool CreateEnvironmentBlock(
out IntPtr lpEnvironment,
IntPtr hToken,
bool bInherit);
[DllImport("userenv.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DestroyEnvironmentBlock(
IntPtr lpEnvironment);
[DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool LoadUserProfile(
IntPtr hToken,
ref PROFILEINFO lpProfileInfo);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct PROFILEINFO
{
public int dwSize;
public int dwFlags;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpUserName;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpProfilePath;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpDefaultPath;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpServerName;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpPolicyPath;
public IntPtr hProfile;
}
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DuplicateTokenEx(
IntPtr hExistingToken,
uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
Int32 ImpersonationLevel,
Int32 dwTokenType,
ref IntPtr phNewToken);
internal const uint TOKEN_QUERY = 0x0008;
internal const uint TOKEN_DUPLICATE = 0x0002;
internal const uint TOKEN_ASSIGN_PRIMARY = 0x0001;
internal const uint CREATE_UNICODE_ENVIRONMENT = 0x00000400;
internal enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
internal enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
/// <summary>
/// 从服务启动外部UI应用进程
/// </summary>
/// <remarks>服务是System权限,应用是普通权限</remarks>
/// <param name="exePath"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public PROCESS_INFORMATION StartUiProcessFromService(string exePath)
{
//获取Session ID
var sId = WTSGetActiveConsoleSessionId();
H3CLog.Info($"WTSGetActiveConsoleSessionId:{sId}");
if (sId == 0)
{
var errorCode = GetLastError();
throw new Exception($"CreateProcessAsUser failed, WTSGetActiveConsoleSessionId failed with error code:{errorCode}.");
}
var isOk = WTSQueryUserToken(sId, out var hToken);
H3CLog.Info($"WTSQueryUserToken:{hToken}");
if (!isOk || hToken == IntPtr.Zero)
{
var errorCode = GetLastError();
throw new Exception($"CreateProcessAsUser failed, WTSQueryUserToken failed with error code:{errorCode}.");
}
// 复制令牌
IntPtr primaryToken = IntPtr.Zero;
var securityAttrs = new SECURITY_ATTRIBUTES();
securityAttrs.nLength = (uint)Marshal.SizeOf(securityAttrs);
securityAttrs.bInheritHandle = false;
securityAttrs.lpSecurityDescriptor = IntPtr.Zero;
//var lpThreadAttr = new SECURITY_ATTRIBUTES();
//lpThreadAttr.nLength = (uint)Marshal.SizeOf(lpThreadAttr);
var lpStratupInfo = new STARTUPINFO();
lpStratupInfo.cb = (uint)Marshal.SizeOf(lpStratupInfo);
lpStratupInfo.lpDesktop = @"winsta0\default";
bool retdup = DuplicateTokenEx(hToken, TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY, ref securityAttrs,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref primaryToken);
if (!retdup)
{
var errorCode = GetLastError();
H3CLog.Error($"DuplicateTokenEx failed with error code: {errorCode}");
throw new Exception($"DuplicateTokenEx failed with error code: {errorCode}");
}
try
{
var isEnvironmentOk = CreateEnvironmentBlock(out var hEnv, primaryToken, false);
if (!isEnvironmentOk)
{
var errorCode = GetLastError();
H3CLog.Error($"CreateEnvironmentBlock failed with error code: {errorCode}");
throw new Exception($"CreateEnvironmentBlock failed with error code: {errorCode}");
}
try
{
PROCESS_INFORMATION lpProcessInfo;
string arguments = "1 LinseerCopilotService";
isOk = CreateProcessAsUser(primaryToken, exePath, arguments, ref securityAttrs, ref securityAttrs, false, CREATE_UNICODE_ENVIRONMENT, hEnv, null, ref lpStratupInfo, out lpProcessInfo);
//isOk = CreateProcessAsUser(hToken, exePath, arguments, ref lpProcessAttr, ref lpThreadAttr, false, 0, 0, null, ref lpStratupInfo, out lpProcessInfo);
if (!isOk)
{
var errorCode = GetLastError();
throw new Exception($"CreateProcessAsUser failed with error code: {errorCode}");
}
return lpProcessInfo;
}
finally
{
DestroyEnvironmentBlock(hEnv);
}
}
finally
{
CloseHandle(primaryToken);
}
}
}
再次补充:
传递工作空间,否者将继承调用的工作空间,在删除调用的工作空间(目录)时,如何被调用的应用在运行。将导致文件目录被占用,从而无法删除该目录。
针对上面的问题如何解决呢,只需要设置被调用的程序的工作空间即可
string workDir = Path.GetDirectoryName(exePath) ?? string.Empty;result = CreateProcessAsUser(primaryToken, exePath, args, ref securityAttrs, ref securityAttrs, false, CREATE_UNICODE_ENVIRONMENT, hEnv, workDir, ref startupInfo, out var lpProcessInfo);
浙公网安备 33010602011771号