На заметку! Чтобы запустить приложение(например notepad) нужно вызвать:
C#
Process.Start("C:\Windows\System32\notepad.exe");
Но
windows service всегда запускает приложение как невидимое.
Наверное потому что
Windows Service сам работает в невидимом режиме или работает с другими правами.
Я долго искал решение и в итоге я запускаю приложение используя
C++ метод
CreateProcessAsUser.
Т.е. запускается приложение под правами пользователся.
Получилось вот так:
C#
Файл LaunchUtils.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
namespace MyWorkerServiceCore1
{
public class LaunchUtils
{
#region DLL Imports
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
internal const int MAXIMUM_ALLOWED = 0x2000000;
internal const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
internal const int NORMAL_PRIORITY_CLASS = 0x20;
internal const int CREATE_NEW_CONSOLE = 0x00000010;
const string SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege";
internal const int SW_SHOW = 5;
internal const int STARTF_USESHOWWINDOW = 1;
internal const int WM_CLOSE = 0x0010;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
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 short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3
}
enum TokenType
{
TokenPrimary = 0,
TokenImpersonation = 1
}
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("kernel32", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
static extern bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
static extern bool DuplicateTokenEx(IntPtr hExistingToken, Int32 dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes,
Int32 ImpersonationLevel, Int32 dwTokenType, ref IntPtr phNewToken);
[DllImport("userenv.dll", SetLastError = true)]
static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
#endregion
public static bool OpenAppWithLoginUserRights(string AppName, out Process resultProcess)
{
resultProcess = null;
IntPtr LoggedInUserToken = IntPtr.Zero;
if (!OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_ADJUST_PRIVILEGES, ref LoggedInUserToken))
return false;
long luid = 0;
if (!LookupPrivilegeValue(null, SE_INCREASE_QUOTA_NAME, ref luid))
{
CloseHandle(LoggedInUserToken);
return false;
}
TokPriv1Luid tp = new TokPriv1Luid()
{
Count = 1,
Luid = luid,
Attr = SE_PRIVILEGE_ENABLED
};
if (!AdjustTokenPrivileges(LoggedInUserToken, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero))
{
CloseHandle(LoggedInUserToken);
return false;
}
if (LoggedInUserToken != IntPtr.Zero)
CloseHandle(LoggedInUserToken);
List<Process> explorerProcessList = new List<Process>();
foreach (Process explorerProcess in Process.GetProcessesByName("explorer") ?? new Process[] { })
{
if (((Environment.OSVersion.Version.Major > 5 && explorerProcess.SessionId > 0) || Environment.OSVersion.Version.Major == 5))
{
explorerProcessList.Add(explorerProcess);
}
}
foreach (Process explorerProcess in explorerProcessList ?? new List<Process>())
{
try
{
int tokenRights = MAXIMUM_ALLOWED;
IntPtr ShellProcessToken = IntPtr.Zero;
if (!OpenProcessToken(explorerProcess.Handle, tokenRights, ref ShellProcessToken))
continue;
IntPtr DuplicateToken = IntPtr.Zero;
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES()
{
nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES))
};
bool resultDuplicateToken = DuplicateTokenEx(ShellProcessToken,
tokenRights,
ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
(int)TokenType.TokenImpersonation,
ref DuplicateToken);
if (ShellProcessToken != IntPtr.Zero)
CloseHandle(ShellProcessToken);
if (!resultDuplicateToken)
continue;
IntPtr UserEnvironment = IntPtr.Zero;
uint dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
if (CreateEnvironmentBlock(out UserEnvironment, ShellProcessToken, true))
{
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
}
SECURITY_ATTRIBUTES processAttributes = new SECURITY_ATTRIBUTES();
SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES();
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
STARTUPINFO si = new STARTUPINFO()
{
cb = (uint)Marshal.SizeOf(typeof(STARTUPINFO)),
dwFlags = STARTF_USESHOWWINDOW,
wShowWindow = SW_SHOW
};
bool resultCreateProcess = CreateProcessAsUser(DuplicateToken,
AppName,
string.Empty,
ref processAttributes,
ref threadAttributes,
true,
dwCreationFlags,
UserEnvironment,
null,
ref si,
out pi);
if (DuplicateToken != IntPtr.Zero)
CloseHandle(DuplicateToken);
if (resultCreateProcess)
{
resultProcess = Process.GetProcessById((int)pi.dwProcessId);
return true;
}
}
catch (Exception e)
{
}
}
return false;
}
}
}
Command Prompt (Win Console)
sc.exe create "My Worker Service Core1" binPath="D:\MyWorkerServiceCore1\bin\Debug\net5.0\MyWorkerServiceCore1.exe"
Command Prompt (Win Console)
sc.exe delete "My Worker Service Core1"