├── screenshot.jpg ├── StartupHelper ├── Icon.png ├── RegistrationScope.cs ├── StartupProviders.cs ├── readme.txt ├── StartupHelper.targets ├── StartupHelper.csproj └── StartupManager.cs ├── StartupHelper.Sample ├── StartupHelper.Sample.sln ├── Properties │ └── AssemblyInfo.cs ├── Program.cs └── StartupHelper.Sample.csproj ├── LICENSE ├── StartupHelper.sln ├── .gitignore └── README.md /screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/falahati/StartupHelper/HEAD/screenshot.jpg -------------------------------------------------------------------------------- /StartupHelper/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/falahati/StartupHelper/HEAD/StartupHelper/Icon.png -------------------------------------------------------------------------------- /StartupHelper/RegistrationScope.cs: -------------------------------------------------------------------------------- 1 | namespace StartupHelper 2 | { 3 | /// 4 | /// Scopes for registering a startup directive 5 | /// 6 | public enum RegistrationScope 7 | { 8 | /// 9 | /// Localuser 10 | /// 11 | Local, 12 | /// 13 | /// Machine 14 | /// 15 | Global 16 | } 17 | } -------------------------------------------------------------------------------- /StartupHelper/StartupProviders.cs: -------------------------------------------------------------------------------- 1 | namespace StartupHelper 2 | { 3 | /// 4 | /// Methods for implementing startup functionality. 5 | /// 6 | public enum StartupProviders 7 | { 8 | /// 9 | /// Task Scheduler 10 | /// 11 | Task, 12 | /// 13 | /// Windows Registry 14 | /// 15 | Registry 16 | } 17 | } -------------------------------------------------------------------------------- /StartupHelper/readme.txt: -------------------------------------------------------------------------------- 1 | StartupHelper 2 | A simple class to manage your program startup 3 | 4 | =============================================================== 5 | 6 | USAGE 7 | Simply create an instance of the StartupManager and keeps 8 | it as a static property/field of the Program.cs file for 9 | easier accessing. Then use the StartupManager.IsRegistered 10 | property and StartupManager.Register() and 11 | StartupManager.Unregister() methods to add or remove your 12 | program from the startup list. 13 | 14 | CODE SAMPLE: 15 | internal class Program 16 | { 17 | public static StartupManager StartupController = 18 | new StartupManager("SAMPLE PROGRAM", 19 | RegistrationScope.Local); -------------------------------------------------------------------------------- /StartupHelper/StartupHelper.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /StartupHelper.Sample/StartupHelper.Sample.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StartupHelper.Sample", "StartupHelper.Sample\StartupHelper.Sample.csproj", "{D7818B4E-6D49-462E-BDBB-E1B9CDFC8D65}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {D7818B4E-6D49-462E-BDBB-E1B9CDFC8D65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {D7818B4E-6D49-462E-BDBB-E1B9CDFC8D65}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {D7818B4E-6D49-462E-BDBB-E1B9CDFC8D65}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {D7818B4E-6D49-462E-BDBB-E1B9CDFC8D65}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Soroush 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /StartupHelper.Sample/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("StartupHelper.Sample")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("StartupHelper")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("d7818b4e-6d49-462e-bdbb-e1b9cdfc8d65")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /StartupHelper.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StartupHelper", "StartupHelper\StartupHelper.csproj", "{5D71AD0C-A697-4CB1-B7A4-8395BA7D6D4C}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StartupHelper.Sample", "StartupHelper.Sample\StartupHelper.Sample.csproj", "{D7818B4E-6D49-462E-BDBB-E1B9CDFC8D65}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {5D71AD0C-A697-4CB1-B7A4-8395BA7D6D4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {5D71AD0C-A697-4CB1-B7A4-8395BA7D6D4C}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {5D71AD0C-A697-4CB1-B7A4-8395BA7D6D4C}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {5D71AD0C-A697-4CB1-B7A4-8395BA7D6D4C}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {D7818B4E-6D49-462E-BDBB-E1B9CDFC8D65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {D7818B4E-6D49-462E-BDBB-E1B9CDFC8D65}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {D7818B4E-6D49-462E-BDBB-E1B9CDFC8D65}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {D7818B4E-6D49-462E-BDBB-E1B9CDFC8D65}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /StartupHelper.Sample/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace StartupHelper.Sample 4 | { 5 | internal class Program 6 | { 7 | public static StartupManager StartupController = 8 | new StartupManager("SAMPLE PROGRAM", 9 | RegistrationScope.Local); 10 | 11 | private static void Main() 12 | { 13 | Console.WriteLine("---------------------INFO---------------------"); 14 | Console.WriteLine("Arguments: " + string.Join(" ", StartupController.CommandLineArguments)); 15 | Console.WriteLine("Is this session elevated? " + StartupManager.IsElevated); 16 | if (StartupController.IsStartedUp) 17 | { 18 | Console.WriteLine("This program started automatically"); 19 | Console.WriteLine("Press 'Enter' to exit."); 20 | Console.ReadLine(); 21 | } 22 | else 23 | { 24 | if (!StartupController.IsRegistered) 25 | { 26 | Console.WriteLine("Program not registered, registering ..."); 27 | Console.WriteLine(StartupController.Register("--nice /argument") ? "Done" : "Failed"); 28 | } 29 | else 30 | { 31 | Console.WriteLine("Program already registered"); 32 | } 33 | Console.WriteLine("----------------------------------------------"); 34 | Console.WriteLine("This program started manually"); 35 | Console.WriteLine("Press 'Enter' to exit, or any other key to unregister."); 36 | if (Console.ReadKey().Key != ConsoleKey.Enter) 37 | { 38 | Console.Clear(); 39 | Console.WriteLine("Unregistering ..."); 40 | Console.WriteLine(StartupController.Unregister() ? "Done" : "Failed"); 41 | Console.WriteLine("Press 'Enter' to exit."); 42 | Console.ReadLine(); 43 | } 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /StartupHelper/StartupHelper.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0;net4 5 | 1.0.3.4 6 | falahati.net 7 | A .Net library to add or remove your program to the startup list as well as detecting the startup session. Supporting Windows XP+ with and without administrator rights. 8 | Soroush Falahati 9 | Copyright © Soroush Falahati 2016-2020 (falahati.net) 10 | AnyCPU 11 | StartupHelper 12 | https://github.com/falahati/StartupHelper 13 | https://github.com/falahati/StartupHelper/blob/master/LICENSE 14 | https://github.com/falahati/StartupHelper/blob/master/StartupHelper/Icon.png?raw=true 15 | true 16 | true 17 | AnyCPU 18 | Startup Helper (Win XP+) 19 | StartupHelper 20 | 21 | 22 | dev 23 | 4 24 | ..\Debug 25 | 26 | 27 | True 28 | dev 29 | true 30 | ..\Release 31 | ..\Release\StartupHelper.xml 32 | 33 | 34 | 35 | all 36 | runtime; build; native; contentfiles; analyzers 37 | 38 | 39 | 40 | 41 | 42 | true 43 | \ 44 | 45 | 46 | true 47 | \ 48 | 49 | 50 | -------------------------------------------------------------------------------- /StartupHelper.Sample/StartupHelper.Sample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {D7818B4E-6D49-462E-BDBB-E1B9CDFC8D65} 8 | Exe 9 | Properties 10 | StartupHelper.Sample 11 | StartupHelper.Sample 12 | v4.0 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | {5d71ad0c-a697-4cb1-b7a4-8395ba7d6d4c} 49 | StartupHelper 50 | 51 | 52 | 53 | 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # Uncomment if necessary however generally it will be regenerated when needed 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | *.[Cc]ache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | bower_components/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ 188 | 189 | # Node.js Tools for Visual Studio 190 | .ntvs_analysis.dat 191 | 192 | # Visual Studio 6 build log 193 | *.plg 194 | 195 | # Visual Studio 6 workspace options file 196 | *.opt 197 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Startup Helper Class Library 2 | [![](https://img.shields.io/github/license/falahati/StartupHelper.svg?style=flat-square)](https://github.com/falahati/StartupHelper/blob/master/LICENSE) 3 | [![](https://img.shields.io/github/commit-activity/y/falahati/StartupHelper.svg?style=flat-square)](https://github.com/falahati/StartupHelper/commits/master) 4 | [![](https://img.shields.io/github/issues/falahati/StartupHelper.svg?style=flat-square)](https://github.com/falahati/StartupHelper/issues) 5 | 6 | A .Net library to add or remove your program to the startup list as well as detecting the startup session. Supporting Windows XP+ with and without administrator rights. 7 | 8 | ## How to get 9 | [![](https://img.shields.io/nuget/dt/StartupHelper.svg?style=flat-square)](https://www.nuget.org/packages/StartupHelper) 10 | [![](https://img.shields.io/nuget/v/StartupHelper.svg?style=flat-square)](https://www.nuget.org/packages/StartupHelper) 11 | 12 | This library is available as a NuGet package at [nuget.org](https://www.nuget.org/packages/StartupHelper/). 13 | 14 | ## Help me fund my own Death Star 15 | 16 | [![](https://img.shields.io/badge/crypto-CoinPayments-8a00a3.svg?style=flat-square)](https://www.coinpayments.net/index.php?cmd=_donate&reset=1&merchant=820707aded07845511b841f9c4c335cd&item_name=Donate¤cy=USD&amountf=20.00000000&allow_amount=1&want_shipping=0&allow_extra=1) 17 | [![](https://img.shields.io/badge/shetab-ZarinPal-8a00a3.svg?style=flat-square)](https://zarinp.al/@falahati) 18 | [![](https://img.shields.io/badge/usd-Paypal-8a00a3.svg?style=flat-square)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=ramin.graphix@gmail.com&lc=US&item_name=Donate&no_note=0&cn=&curency_code=USD&bn=PP-DonationsBF:btn_donateCC_LG.gif:NonHosted) 19 | 20 | **--OR--** 21 | 22 | You can always donate your time by contributing to the project or by introducing it to others. 23 | 24 | ## How to use 25 | First you need to create a `StartupManager` object for your program. I recomment doing so by defining a new public field or property in the `Program` class of your application. 26 | ```C# 27 | public static StartupManager Startup = 28 | new StartupManager("SAMPLE PROGRAM", RegistrationScope.Local); 29 | ``` 30 | 31 | You can also specify if your program needs administrative rights, or if you prefer the registry method to register the rule as well as other settings using other constractor overloads. 32 | Then, using this object, you can query your application startup status, register and unregister your application for auto start and detect if the current session started as startup. 33 | 34 | Check the 'UACHelper.Sample' project for basic usage of the class. 35 | ![Screenshot](/screenshot.jpg?raw=true "Screenshot") 36 | 37 | ## Documentation 38 | ### [Primary Members] 39 | * `StartupManager.IsStartedUp` This property indicates if the current session started automatically 40 | * `StartupManager.Register()` Using this method you can register your program for auto start. You can also specify required arguments to be send to your application. 41 | * `StartupManager.Unregister()` Unregisters the startup rule. 42 | 43 | ### [Other Useful Members] 44 | * `StartupManager.CommandLineArguments` Returns the arguments used to start the program. Except the auto startup indicator argument, if presented 45 | * `StartupManager.WorkingDirectory` Can be used to set or get the expected working directory to be used for registering the rule 46 | * `StartupManager.IsElevated` Returns a `Boolean` indicating the current elevation status of the application. 47 | 48 | ## License 49 | The MIT License (MIT) 50 | 51 | Copyright (c) 2016-2020 Soroush 52 | 53 | Permission is hereby granted, free of charge, to any person obtaining a copy 54 | of this software and associated documentation files (the "Software"), to deal 55 | in the Software without restriction, including without limitation the rights 56 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 57 | copies of the Software, and to permit persons to whom the Software is 58 | furnished to do so, subject to the following conditions: 59 | 60 | The above copyright notice and this permission notice shall be included in all 61 | copies or substantial portions of the Software. 62 | 63 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 64 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 65 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 66 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 67 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 68 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 69 | SOFTWARE. 70 | -------------------------------------------------------------------------------- /StartupHelper/StartupManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reflection; 4 | using System.Security; 5 | using System.Security.Principal; 6 | using Microsoft.Win32; 7 | using Microsoft.Win32.TaskScheduler; 8 | 9 | namespace StartupHelper 10 | { 11 | /// 12 | /// A class for managing the startup of the application. 13 | /// 14 | public class StartupManager 15 | { 16 | // ReSharper disable once PrivateMembersMustHaveComments 17 | private static bool? _isFileSystemCaseSensitive; 18 | 19 | /// 20 | /// Simplest form for initializing an instance of the class, with 21 | /// providing a for the program and specifying 22 | /// an . 23 | /// 24 | /// 25 | /// A unique name for the rule as an alias for the program 26 | /// 27 | /// 28 | /// Scope in which startup rule should be created or managed 29 | /// 30 | public StartupManager(string name, RegistrationScope scope) 31 | : this(name, scope, IsElevated) 32 | { 33 | } 34 | 35 | /// 36 | /// Initializing an instance of the class, with providing a 37 | /// for the program, specifying an 38 | /// and explicitly specifying the dependency on 39 | /// administrator privileges. 40 | /// 41 | /// 42 | /// A unique name for the rule as an alias for the program 43 | /// 44 | /// 45 | /// Scope in which startup rule should be created or managed 46 | /// 47 | /// 48 | /// Set to True if the program should be executed with administrator's 49 | /// rights 50 | /// 51 | public StartupManager(string name, RegistrationScope scope, bool needsAdminPrivileges) 52 | : this(Assembly.GetEntryAssembly()?.Location, name, scope, needsAdminPrivileges) 53 | { 54 | FixWorkingDirectory(); 55 | } 56 | 57 | /// 58 | /// Initializing an instance of the class, with providing the filename 59 | /// of the starting executable file, a for the 60 | /// program, specifying an and explicitly 61 | /// specifying the dependency on administrator privileges. 62 | /// 63 | /// 64 | /// The address of the executable file of the application 65 | /// 66 | /// 67 | /// A unique name for the rule as an alias for the program 68 | /// 69 | /// 70 | /// Scope in which startup rule should be created or managed 71 | /// 72 | /// 73 | /// Set to True if the program should be executed with administrator's 74 | /// rights 75 | /// 76 | public StartupManager(string applicationImage, string name, RegistrationScope scope, bool needsAdminPrivileges) 77 | : 78 | this(applicationImage, name, scope, needsAdminPrivileges, "--startup") 79 | { 80 | } 81 | 82 | 83 | /// 84 | /// Initializing an instance of the class, with providing the filename 85 | /// of the starting executable file, a for the 86 | /// program, specifying an and explicitly 87 | /// specifying the dependency on administrator privileges. 88 | /// 89 | /// 90 | /// The address of the executable file of the application 91 | /// 92 | /// 93 | /// A unique name for the rule as an alias for the program 94 | /// 95 | /// 96 | /// Scope in which startup rule should be created or managed 97 | /// 98 | /// 99 | /// Method that is expected to be used for registering the program 100 | /// startup 101 | /// 102 | /// 103 | /// Set to True if the program should be executed with administrator's 104 | /// rights 105 | /// 106 | public StartupManager(string applicationImage, string name, RegistrationScope scope, StartupProviders provider, 107 | bool needsAdminPrivileges) 108 | : 109 | this(applicationImage, name, scope, needsAdminPrivileges, provider, "--startup") 110 | { 111 | } 112 | 113 | /// 114 | /// Initializing an instance of the class, with providing the filename 115 | /// of the starting executable file, a for the 116 | /// program, specifying an and explicitly 117 | /// specifying the dependency on administrator privileges. Using this 118 | /// constructor you can specify a custom string to be used as the 119 | /// startup indicator. Make sure that there is no other string similar 120 | /// to this string in your expected command line arguments to conflict 121 | /// with it. 122 | /// 123 | /// 124 | /// The address of the executable file of the application 125 | /// 126 | /// 127 | /// A unique name for the rule as an alias for the program 128 | /// 129 | /// 130 | /// Scope in which startup rule should be created or managed 131 | /// 132 | /// 133 | /// Set to True if the program should be executed with administrator's 134 | /// rights 135 | /// 136 | /// 137 | /// A special string to send to the program when started and to detect 138 | /// the automatic startup 139 | /// 140 | /// Bad argument value. 141 | public StartupManager(string applicationImage, string name, RegistrationScope scope, bool needsAdminPrivileges, 142 | string startupSpecialArgument) 143 | : this( 144 | applicationImage, name, scope, needsAdminPrivileges, 145 | Environment.OSVersion.Version.Major >= 6 && 146 | (needsAdminPrivileges || Environment.OSVersion.Version.Minor >= 2) 147 | ? StartupProviders.Task 148 | : StartupProviders.Registry, startupSpecialArgument) 149 | { 150 | } 151 | 152 | /// 153 | /// Initializing an instance of the class, with providing the filename 154 | /// of the starting executable file, a for the 155 | /// program, specifying an and explicitly 156 | /// specifying the dependency on administrator privileges. Using this 157 | /// constructor you can specify a custom string to be used as the 158 | /// startup indicator. Make sure that there is no other string similar 159 | /// to this string in your expected command line arguments to conflict 160 | /// with it. 161 | /// 162 | /// 163 | /// The address of the executable file of the application 164 | /// 165 | /// 166 | /// A unique name for the rule as an alias for the program 167 | /// 168 | /// 169 | /// Scope in which startup rule should be created or managed 170 | /// 171 | /// 172 | /// Set to True if the program should be executed with administrator's 173 | /// rights 174 | /// 175 | /// 176 | /// Method that is expected to be used for registering the program 177 | /// startup 178 | /// 179 | /// 180 | /// A special string to send to the program when started and to detect 181 | /// the automatic startup 182 | /// 183 | /// Bad argument value. 184 | public StartupManager(string applicationImage, string name, RegistrationScope scope, bool needsAdminPrivileges, 185 | StartupProviders provider, string startupSpecialArgument) 186 | { 187 | if (string.IsNullOrEmpty(applicationImage) || !File.Exists(applicationImage)) 188 | { 189 | throw new ArgumentException("File doesn't exist.", nameof(applicationImage)); 190 | } 191 | if (string.IsNullOrEmpty(name.Trim())) 192 | { 193 | throw new ArgumentException("Bad name for application.", nameof(name)); 194 | } 195 | if (string.IsNullOrEmpty(startupSpecialArgument.Trim()) || IsAnyWhitespaceIn(startupSpecialArgument.Trim())) 196 | { 197 | throw new ArgumentException("Bad string provided as special argument for startup detection.", 198 | nameof(startupSpecialArgument)); 199 | } 200 | ApplicationImage = applicationImage; 201 | WorkingDirectory = Path.GetDirectoryName(applicationImage); 202 | Name = name.Trim(); 203 | NeedsAdministrativePrivileges = needsAdminPrivileges; 204 | RegistrationScope = scope; 205 | StartupSpecialArgument = startupSpecialArgument.Trim(); 206 | Provider = provider; 207 | } 208 | 209 | /// 210 | /// Value of this property shows if the OS's file system is case 211 | /// sensitive. 212 | /// 213 | public static bool IsFileSystemCaseSensitive 214 | { 215 | get 216 | { 217 | if (_isFileSystemCaseSensitive == null) 218 | { 219 | var tempFile = Path.GetTempFileName(); 220 | _isFileSystemCaseSensitive = !File.Exists(tempFile.ToLower()) || !File.Exists(tempFile.ToUpper()); 221 | File.Delete(tempFile); 222 | } 223 | return _isFileSystemCaseSensitive.Value; 224 | } 225 | } 226 | 227 | /// 228 | /// Value of this property shows if the current program executed with 229 | /// administrator rights. 230 | /// 231 | public static bool IsElevated 232 | { 233 | get 234 | { 235 | var currentUser = WindowsIdentity.GetCurrent(); 236 | return new WindowsPrincipal(currentUser).IsInRole(WindowsBuiltInRole.Administrator); 237 | } 238 | } 239 | 240 | /// 241 | /// A special string to be used as the argument to the program when started to detect auto start sessions 242 | /// 243 | public string StartupSpecialArgument { get; } 244 | 245 | 246 | /// 247 | /// Indicates if the registered rule should make sure that program is 248 | /// going to be executed with administrator rights 249 | /// 250 | public bool NeedsAdministrativePrivileges { get; } 251 | 252 | 253 | /// 254 | /// Indicates the working directory in which the program should be 255 | /// executed with 256 | /// 257 | public string WorkingDirectory { get; set; } 258 | 259 | /// 260 | /// Shows the scope in which the rule for auto start is going to be 261 | /// registered/removed or modified 262 | /// 263 | public RegistrationScope RegistrationScope { get; } 264 | 265 | /// 266 | /// Address of the executable file 267 | /// 268 | public string ApplicationImage { get; } 269 | 270 | 271 | /// 272 | /// A unique name to be used as the rule name 273 | /// 274 | public string Name { get; } 275 | 276 | /// 277 | /// The underlying method that is used by the class to manage the 278 | /// startup functionality 279 | /// 280 | public StartupProviders Provider { get; } 281 | 282 | 283 | /// 284 | /// Indicates if this session is started as startup 285 | /// 286 | public bool IsStartedUp 287 | => 288 | (Environment.GetCommandLineArgs().Length > 0 && 289 | Environment.GetCommandLineArgs()[0].ToLower().Trim() == StartupSpecialArgument) || 290 | (Environment.GetCommandLineArgs().Length > 1 && 291 | Environment.GetCommandLineArgs()[1].ToLower().Trim() == StartupSpecialArgument); 292 | 293 | /// 294 | /// Returns the correct command line arguments used to start this 295 | /// session without special startup argument, if presented 296 | /// 297 | public string[] CommandLineArguments 298 | => Environment.GetCommandLineArgs().Length > 0 299 | ? SkipFirstElements(Environment.GetCommandLineArgs() 300 | , IsStartedUp && Environment.GetCommandLineArgs()[1].ToLower().Trim() == StartupSpecialArgument 301 | ? 2 302 | : 1) 303 | : new string[0]; 304 | 305 | /// 306 | /// Indicates if there is any active rule by the unique name provided 307 | /// 308 | public bool IsRegistered 309 | { 310 | get 311 | { 312 | if (Provider == StartupProviders.Task) 313 | { 314 | using (var taskService = new TaskService()) 315 | { 316 | var task = taskService.FindTask(Name, false); 317 | if (task != null) 318 | { 319 | using (task) 320 | { 321 | return string.IsNullOrEmpty(task.Definition.Principal.UserId.Trim()) || 322 | (RegistrationScope == RegistrationScope.Local && 323 | IsCurrentUser(task.Definition.Principal.UserId)); 324 | } 325 | } 326 | } 327 | } 328 | using (var registryKey = Registry.CurrentUser.OpenSubKey 329 | (@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true)) 330 | { 331 | if (registryKey?.GetValue(Name, null) != null) 332 | { 333 | if (Provider == StartupProviders.Task) 334 | { 335 | registryKey.DeleteValue(Name, false); 336 | } 337 | else 338 | { 339 | return true; 340 | } 341 | } 342 | } 343 | try 344 | { 345 | using (var registryKey = Registry.LocalMachine.OpenSubKey 346 | (@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", IsElevated)) 347 | { 348 | if (registryKey?.GetValue(Name, null) != null) 349 | { 350 | if (Provider == StartupProviders.Task && IsElevated) 351 | { 352 | registryKey.DeleteValue(Name, false); 353 | } 354 | else 355 | { 356 | return true; 357 | } 358 | } 359 | } 360 | } 361 | catch (SecurityException) 362 | { 363 | // ignore 364 | } 365 | return false; 366 | } 367 | } 368 | 369 | /// 370 | /// Removes the rule if exists 371 | /// 372 | /// 373 | /// A value indicating the success of the operation 374 | /// 375 | public bool Unregister() 376 | { 377 | if (Provider == StartupProviders.Task) 378 | { 379 | using (var taskService = new TaskService()) 380 | { 381 | var task = taskService.FindTask(Name, false); 382 | if (task != null) 383 | { 384 | taskService.RootFolder.DeleteTask(Name, false); 385 | task.Dispose(); 386 | } 387 | } 388 | } 389 | if (RegistrationScope == RegistrationScope.Local) 390 | { 391 | using (var registryKey = Registry.CurrentUser.OpenSubKey 392 | (@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true)) 393 | { 394 | registryKey?.DeleteValue(Name, false); 395 | } 396 | } 397 | if (IsElevated) 398 | { 399 | using (var registryKey = Registry.LocalMachine.OpenSubKey 400 | (@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true)) 401 | { 402 | registryKey?.DeleteValue(Name, false); 403 | } 404 | } 405 | return !IsRegistered; 406 | } 407 | 408 | 409 | /// 410 | /// Creates or replace the existing rule 411 | /// 412 | /// 413 | /// Special arguments to be sent to the application at startup 414 | /// 415 | /// 416 | /// A value indicating the success of the operation 417 | /// 418 | public bool Register(string arguments = null) 419 | { 420 | Unregister(); 421 | if (Provider == StartupProviders.Task) 422 | { 423 | using (var taskService = new TaskService()) 424 | { 425 | using (var newTask = taskService.NewTask()) 426 | { 427 | var taskAction = new ExecAction(ApplicationImage, 428 | $"{StartupSpecialArgument} {(arguments ?? string.Empty)}", 429 | WorkingDirectory); 430 | var taskTrigger = new LogonTrigger(); 431 | newTask.Settings.DisallowStartIfOnBatteries = false; 432 | newTask.Settings.ExecutionTimeLimit = TimeSpan.Zero; 433 | if (taskService.HighestSupportedVersion >= new Version(1, 2)) 434 | { 435 | newTask.Settings.AllowDemandStart = false; 436 | newTask.Settings.AllowHardTerminate = false; 437 | newTask.Settings.Compatibility = TaskCompatibility.V2; 438 | newTask.Settings.StartWhenAvailable = true; 439 | newTask.Principal.RunLevel = NeedsAdministrativePrivileges 440 | ? TaskRunLevel.Highest 441 | : TaskRunLevel.LUA; 442 | if (RegistrationScope == RegistrationScope.Local) 443 | { 444 | taskTrigger.UserId = WindowsIdentity.GetCurrent().Name; 445 | } 446 | } 447 | else 448 | { 449 | newTask.Settings.RunOnlyIfLoggedOn = true; 450 | } 451 | if (RegistrationScope == RegistrationScope.Global) 452 | { 453 | newTask.Principal.GroupId = 454 | new SecurityIdentifier( 455 | NeedsAdministrativePrivileges 456 | ? WellKnownSidType.BuiltinAdministratorsSid 457 | : WellKnownSidType.BuiltinUsersSid, null).Translate(typeof (NTAccount)).Value; 458 | } 459 | else 460 | { 461 | newTask.Principal.LogonType = TaskLogonType.InteractiveToken; 462 | newTask.Principal.UserId = WindowsIdentity.GetCurrent().Name; 463 | } 464 | newTask.Actions.Add(taskAction); 465 | newTask.Triggers.Add(taskTrigger); 466 | taskService.RootFolder.RegisterTaskDefinition(Name, newTask); 467 | } 468 | } 469 | } 470 | else 471 | { 472 | using (var registryKey = (RegistrationScope == RegistrationScope.Local 473 | ? Registry.CurrentUser.OpenSubKey 474 | (@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true) 475 | : Registry.LocalMachine.OpenSubKey 476 | (@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true))) 477 | { 478 | registryKey?.SetValue(Name, 479 | $"\"{ApplicationImage}\" {StartupSpecialArgument} {(arguments ?? string.Empty)}"); 480 | } 481 | } 482 | return IsRegistered; 483 | } 484 | 485 | /// 486 | /// Fixes the working directory of the current session if it is not the 487 | /// same as the directory in which the executable file resists. Put 488 | /// this line in your application's program.cs file. There is no 489 | /// need to do so if you use the constructor without specifying the 490 | /// address of the executable file. 491 | /// 492 | public void FixWorkingDirectory() 493 | { 494 | if (!Path.GetFullPath(Directory.GetCurrentDirectory()) 495 | .Equals(Path.GetFullPath(WorkingDirectory), 496 | IsFileSystemCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)) 497 | { 498 | Directory.SetCurrentDirectory(WorkingDirectory); 499 | } 500 | } 501 | 502 | 503 | // ReSharper disable once PrivateMembersMustHaveComments 504 | private static bool IsCurrentUser(string username) 505 | { 506 | try 507 | { 508 | return ((SecurityIdentifier) (new NTAccount(username).Translate(typeof (SecurityIdentifier)))) == 509 | WindowsIdentity.GetCurrent().User; 510 | } 511 | catch 512 | { 513 | return false; 514 | } 515 | } 516 | 517 | // ReSharper disable once PrivateMembersMustHaveComments 518 | private static T[] SkipFirstElements(T[] array, int count) 519 | { 520 | var newArray = new T[array.Length - count]; 521 | Array.Copy(array, count, newArray, 0, newArray.Length); 522 | return newArray; 523 | } 524 | 525 | // ReSharper disable once PrivateMembersMustHaveComments 526 | private static bool IsAnyWhitespaceIn(string str) 527 | { 528 | for (var i = 0; i < str.Length; i++) 529 | { 530 | if (char.IsWhiteSpace(str, i)) 531 | return true; 532 | } 533 | return false; 534 | } 535 | } 536 | } --------------------------------------------------------------------------------