├── 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://github.com/falahati/StartupHelper/blob/master/LICENSE)
3 | [](https://github.com/falahati/StartupHelper/commits/master)
4 | [](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://www.nuget.org/packages/StartupHelper)
10 | [](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://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://zarinp.al/@falahati)
18 | [](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 | 
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 | }
--------------------------------------------------------------------------------