zoukankan      html  css  js  c++  java
  • How to create Windows service and launch desktop app

    A good artical introduce how to create and install Windows service via C#. The artical link is attached for future refer.

    http://www.cnblogs.com/wuhuacong/archive/2009/02/11/1381428.html

    Call a program via Windows service is not easy as we used before. We cannot use Process to launch an program with UI. Following method got from MSDN forum is very useful:

    using System;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    
    namespace WindowsServiceLaunchingExe
    {
        class NativeMethods
        {
            [StructLayout(LayoutKind.Sequential)]
            public struct PROCESS_INFORMATION {
                public IntPtr hProcess;
                public IntPtr hThread;
                public System.UInt32 dwProcessId;
                public System.UInt32 dwThreadId;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct SECURITY_ATTRIBUTES {
                public System.UInt32 nLength;
                public IntPtr lpSecurityDescriptor;
                public bool bInheritHandle;
            }
            
            [StructLayout(LayoutKind.Sequential)] 
            public struct STARTUPINFO {
                public System.UInt32 cb;
                public string lpReserved;
                public string lpDesktop;
                public string lpTitle;
                public System.UInt32 dwX;
                public System.UInt32 dwY;
                public System.UInt32 dwXSize;
                public System.UInt32 dwYSize;
                public System.UInt32 dwXCountChars;
                public System.UInt32 dwYCountChars;
                public System.UInt32 dwFillAttribute;
                public System.UInt32 dwFlags;
                public short wShowWindow;
                public short cbReserved2;
                public IntPtr lpReserved2;
                public IntPtr hStdInput;
                public IntPtr hStdOutput;
                public IntPtr hStdError;
            }
            
            [StructLayout(LayoutKind.Sequential)]
            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;
            }
            
            internal enum SECURITY_IMPERSONATION_LEVEL {
                SecurityAnonymous = 0,
                SecurityIdentification = 1,
                SecurityImpersonation = 2,
                SecurityDelegation = 3
            }
    
            internal enum TOKEN_TYPE {
                TokenPrimary = 1,
                TokenImpersonation = 2
            }
    
            [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private 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, ref PROCESS_INFORMATION lpProcessInformation);
    
            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern bool DuplicateTokenEx(IntPtr hExistingToken, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpTokenAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, TOKEN_TYPE TokenType, ref IntPtr phNewToken);
    
            [DllImport("advapi32.dll", SetLastError = true)]
            private static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);
    
            [DllImport("userenv.dll", SetLastError = true)]
            private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
    
            [DllImport("userenv.dll", SetLastError = true)]
            private static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
    
            private const short SW_SHOW = 1;
            private const short SW_SHOWMAXIMIZED = 7;
            private const int TOKEN_QUERY = 8;
            private const int TOKEN_DUPLICATE = 2;
            private const int TOKEN_ASSIGN_PRIMARY = 1;
            private const int GENERIC_ALL_ACCESS = 268435456;
            private const int STARTF_USESHOWWINDOW = 1;
            private const int STARTF_FORCEONFEEDBACK = 64;
            private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
            private const string gs_EXPLORER = "explorer";
    
            public static void LaunchProcess(string Ps_CmdLine)
            {
                IntPtr li_Token = default(IntPtr);
                IntPtr li_EnvBlock = default(IntPtr);
                Process[] lObj_Processes = Process.GetProcessesByName(gs_EXPLORER);
    
                // Get explorer.exe id
    
                // If process not found
                if (lObj_Processes.Length == 0)
                {
                    // Exit routine
                    return;
                }
    
                // Get primary token for the user currently logged in
                li_Token = GetPrimaryToken(lObj_Processes[0].Id);
    
                // If token is nothing
                if (li_Token.Equals(IntPtr.Zero))
                {
                    // Exit routine
                    return;
                }
    
                // Get environment block
                li_EnvBlock = GetEnvironmentBlock(li_Token);
    
                // Launch the process using the environment block and primary token
                LaunchProcessAsUser(Ps_CmdLine, li_Token, li_EnvBlock);
    
                // If no valid enviroment block found
                if (li_EnvBlock.Equals(IntPtr.Zero))
                {
                    // Exit routine
                    return;
                }
    
                // Destroy environment block. Free environment variables created by the 
                // CreateEnvironmentBlock function.
                DestroyEnvironmentBlock(li_EnvBlock);
            }
    
            private static IntPtr GetPrimaryToken(int Pi_ProcessId) {
    
                IntPtr li_Token = IntPtr.Zero;
                IntPtr li_PrimaryToken = IntPtr.Zero;
                bool lb_ReturnValue = false;
                Process lObj_Process = Process.GetProcessById(Pi_ProcessId);
                SECURITY_ATTRIBUTES lObj_SecurityAttributes = default(SECURITY_ATTRIBUTES);
    
                // Get process by id
                // Open a handle to the access token associated with a process. The access token 
                // is a runtime object that represents a user account.
                lb_ReturnValue = OpenProcessToken(lObj_Process.Handle, TOKEN_DUPLICATE, ref li_Token);
    
                // If successfull in opening handle to token associated with process
                if (lb_ReturnValue) {
    
                    // Create security attributes to pass to the DuplicateTokenEx function
                    lObj_SecurityAttributes = new SECURITY_ATTRIBUTES();
                    lObj_SecurityAttributes.nLength = Convert.ToUInt32(Marshal.SizeOf(lObj_SecurityAttributes));
    
                    // Create a new access token that duplicates an existing token. This function 
                    // can create either a primary token or an impersonation token.
                    lb_ReturnValue = DuplicateTokenEx(li_Token, Convert.ToUInt32(TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY), ref lObj_SecurityAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TOKEN_TYPE.TokenPrimary, ref li_PrimaryToken);
    
                    // If un-successful in duplication of the token
                    if (!lb_ReturnValue) {
                        // Throw exception
                        throw new Exception(string.Format("DuplicateTokenEx Error: {0}", Marshal.GetLastWin32Error()));
                    }
                }
                else {
                    // If un-successful in opening handle for token then throw exception
                    throw new Exception(string.Format("OpenProcessToken Error: {0}", Marshal.GetLastWin32Error()));
                }
    
                // Return primary token
                return li_PrimaryToken;
            }
    
            private static IntPtr GetEnvironmentBlock(IntPtr Pi_Token) {
    
                IntPtr li_EnvBlock = IntPtr.Zero;
                bool lb_ReturnValue = CreateEnvironmentBlock(ref li_EnvBlock, Pi_Token, false);
    
                // Retrieve the environment variables for the specified user. 
                // This block can then be passed to the CreateProcessAsUser function.
    
                // If not successful in creation of environment block then  
                if (!lb_ReturnValue) {
                    // Throw exception
                    throw new Exception(string.Format("CreateEnvironmentBlock Error: {0}", Marshal.GetLastWin32Error()));
                }
    
                // Return the retrieved environment block
                return li_EnvBlock;
            }
    
            private static void LaunchProcessAsUser(string Ps_CmdLine, IntPtr Pi_Token, IntPtr Pi_EnvBlock) {
                bool lb_Result = false;
                PROCESS_INFORMATION lObj_ProcessInformation = default(PROCESS_INFORMATION);
                SECURITY_ATTRIBUTES lObj_ProcessAttributes = default(SECURITY_ATTRIBUTES);
                SECURITY_ATTRIBUTES lObj_ThreadAttributes = default(SECURITY_ATTRIBUTES);
                STARTUPINFO lObj_StartupInfo = default(STARTUPINFO);
    
                // Information about the newly created process and its primary thread.
                lObj_ProcessInformation = new PROCESS_INFORMATION();
    
                // Create security attributes to pass to the CreateProcessAsUser function
                lObj_ProcessAttributes = new SECURITY_ATTRIBUTES();
                lObj_ProcessAttributes.nLength = Convert.ToUInt32(Marshal.SizeOf(lObj_ProcessAttributes));
                lObj_ThreadAttributes = new SECURITY_ATTRIBUTES();
                lObj_ThreadAttributes.nLength = Convert.ToUInt32(Marshal.SizeOf(lObj_ThreadAttributes));
    
                // To specify the window station, desktop, standard handles, and appearance of the 
                // main window for the new process.
                lObj_StartupInfo = new STARTUPINFO();
                lObj_StartupInfo.cb = Convert.ToUInt32(Marshal.SizeOf(lObj_StartupInfo));
                lObj_StartupInfo.lpDesktop = null;
                lObj_StartupInfo.dwFlags = Convert.ToUInt32(STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK);
                lObj_StartupInfo.wShowWindow = SW_SHOW;
    
                // Creates a new process and its primary thread. The new process runs in the 
                // security context of the user represented by the specified token.
                lb_Result = CreateProcessAsUser(Pi_Token, null, Ps_CmdLine, ref lObj_ProcessAttributes, ref lObj_ThreadAttributes, true, CREATE_UNICODE_ENVIRONMENT, Pi_EnvBlock, null, ref lObj_StartupInfo, ref lObj_ProcessInformation);
    
                // If create process return false then
                if (!lb_Result) {
                    // Throw exception
                    throw new Exception(string.Format("CreateProcessAsUser Error: {0}", Marshal.GetLastWin32Error()));
                }
            }
        }
    }

    To use the code, create a new windows service project, and add code like the following one:

    using System;
    using System.Diagnostics;
    using System.ServiceProcess;
    using System.Timers;
    
    namespace WindowsServiceLaunchingExe
    {
        public partial class ExeLauncherSvc : ServiceBase
        {
            public ExeLauncherSvc() {
                InitializeComponent();
            }
    
            Timer timer;
    
            protected override void OnStart(string[] args) {
                timer = new Timer(5000);
                timer.Elapsed += (sender, e) => {
                    try {
                        timer.Stop();
                        EventLog.WriteEntry("WindowsServiceLaunchingExe", "Launching process...");
                        NativeMethods.LaunchProcess(@"C:Windows
    otepad.exe");
                    } catch (Exception ex) {
                        EventLog.WriteEntry("WindowsServiceLaunchingExe", ex.Message);
                    }
                };
    
                timer.Start();
            }
    
    
            protected override void OnStop() {
            }
        }
    }

    More details and code, please refer http://social.msdn.microsoft.com/Forums/en-US/990e7c4a-afa7-47aa-b9a6-d5b6beb19f41/call-a-program-via-windows-service.

  • 相关阅读:
    Linux文件查询笔记
    C语言学习和回顾
    hive的数据压缩
    进程线程那些事儿
    hive的数据存储格式
    hive的内置函数
    Hive自定义函数
    spark编译
    Impala的安装和使用
    数据库的读写分离
  • 原文地址:https://www.cnblogs.com/Blackeye286/p/3208104.html
Copyright © 2011-2022 走看看