dir.by  
  Search  
Programming, development, testing
Windows Service (using C#)
How to open a Notepad app from C# Windows Service | library .NET Core and use Worker
  Looked at 1600 times    
 How to open a Notepad app from C# Windows Service | library .NET Core and use Worker 
last updated: 29 June 2023
Download the service with the source code:
MyWorkerServiceCore1_LaunchApp.zip ...
Size: 7 kb
Step 1. Open Visual Studio
If you do not have Visual Studio installed you need install Visual Studio...
Open Visual Studio 2022
or
Open Visual Studio 2019
Step 2. Open the project C# Windows Service
Step 3. Let's create a new file LaunchUtils.cs
 
Let's write the file name LaunchUtils.cs:
Step 4. In the file LaunchUtils.cs write the code
Note! To run an application (for example, notepad) you need to call:
  C#  
Process.Start("C:\Windows\System32\notepad.exe");

But windows service always runs the application as invisible.
Probably because Windows Service itself works in invisible mode or works with other rights.

I have been looking for a solution for a long time and in the end I run the application using the C++ method CreateProcessAsUser.
That is, the application is launched under user rights.
It turned out like this:
  C#     File 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;
          }
     }
}

It will turn out like this:
Step 5. Let's register the service in the system
First, let's compile the application.
To do this, press Build → Build Solution
 
Let's register our exe file as a service:
  Command Prompt (Win Console)  
sc.exe create "My Worker Service Core1" binPath="D:\MyWorkerServiceCore1\bin\Debug\net5.0\MyWorkerServiceCore1.exe"
Step 6. Run our Windows Service in the system Windows
Open Services and see that the service is installed in the system Windows:
 
We will see that after starting My Worker Service Core1 Notepad will open
 
Note!
To remove a service from the system, first press Stop
And then, at the command prompt, run:
  Command Prompt (Win Console)  
sc.exe delete "My Worker Service Core1"
 
← Previous topic
Loading parameters from appsettings.json for application C# Windows Service (library .NET Core and using Worker)
 
Next topic →
Doing publish a project (compiling and assembling a project) "C# Windows Service" | library .NET Core using Worker
 
Your feedback ... Comments ...
   
Your Name
Your comment (www links can only be added by a logged-in user)

  Объявления  
  Объявления  
 
Technology .NET Framework
Create a new application C# Windows Service (.NET Framework)
C# Windows Service (.NET Framework) with the username. Event when user logs in/out of Windows
Create folder "My Application" under folder "Application and Services logs" | Event Viewer
Technology .NET Core
Create a new application C# Windows Service (library .NET Core and use Worker)
Loading parameters from appsettings.json for application C# Windows Service (library .NET Core and using Worker)
How to open a Notepad app from C# Windows Service | library .NET Core and use Worker
Doing publish a project (compiling and assembling a project) "C# Windows Service" | library .NET Core using Worker
How to register your exe file as Windows Service. Start/stop your Windows Service on the system Windows | library .NET Core using Worker

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