dir.by  
  Поиск  
Программирование, разработка, тестирование
Windows Service (используя C#)
Как открыть Notepad приложение из C# Windows Service | библиотека .NET Core и использую Worker
  Посмотрели 548 раз(а)    
 Как открыть Notepad приложение из C# Windows Service | библиотека .NET Core и использую Worker 
последнее обновление: 29 июня 2023
Скачать сервис с исходным кодом:
MyWorkerServiceCore1_LaunchApp.zip ...
размер: 7 kb
Шаг 1. Открываем Visual Studio
Если у вас не установлена Visual Studio нужно установить Visual Studio...
Открываем Visual Studio 2022
или
Открываем Visual Studio 2019
Шаг 2. Открываем проект C# Windows Service
Шаг 3. Создадим новый файл LaunchUtils.cs
 
Напишем имя файла LaunchUtils.cs:
Шаг 4. В файле LaunchUtils.cs напишем код
На заметку! Чтобы запустить приложение(например 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;
          }
     }
}

Получится вот так:
Шаг 5. Зарегистрируем сервис в системе
Сначала скомпилируем приложение.
Для этого нажмем Build → Build Solution
 
Зарегестрируем наш exe файл как сервис:
  Command Prompt (Win Console)  
sc.exe create "My Worker Service Core1" binPath="D:\MyWorkerServiceCore1\bin\Debug\net5.0\MyWorkerServiceCore1.exe"
Шаг 6. Запускаем наш Windows Service в системе Windows
Откроем Services и увидим что сервис установился в системе Windows:
 
Увидим что после запуска My Worker Service Core1 откроется Notepad
 
На заметку!
Чтобы удалить сервис из системы сначала нажмите Stop
А потом в командной строке выполните:
  Command Prompt (Win Console)  
sc.exe delete "My Worker Service Core1"
 
← Предыдущая тема
Загрузка параметров из appsettings.json для приложения C# Windows Service (библиотека .NET Core и использую Worker)
 
Следующая тема →
Делаем publish проекта (компилируем и собираем проект) "C# Windows Service" | библиотека .NET Core используя Worker
 
Ваши Отзывы ... комментарии ...
   
Вашe имя
Ваш комментарий (www ссылки может добавлять только залогиненный пользователь)

Картинки

Windows Service (используя C#)  
Технология .NET Framework
Создаем новое приложение C# Windows Service (.NET Framework)
C# Windows Service (.NET Framework) с получением имени пользователя. Событие при входе/выходе пользователя из Windows
Создать папку "My Application" в папке "Application and Services logs" | Event Viewer
Технология .NET Core
Создаем новое приложение C# Windows Service (библиотека .NET Core и использую Worker)
Загрузка параметров из appsettings.json для приложения C# Windows Service (библиотека .NET Core и использую Worker)
Как открыть Notepad приложение из C# Windows Service | библиотека .NET Core и использую Worker
Делаем publish проекта (компилируем и собираем проект) "C# Windows Service" | библиотека .NET Core используя Worker
Как зарегистрировать exe file как Windows Service. Запуск/остановка Windows Service в системе Windows | библиотека .NET Core используя Worker

  Ваши вопросы присылайте по почте: info@dir.by  
Яндекс.Метрика