├── App.config
├── Program.cs
├── Properties
├── App.config
└── AssemblyInfo.cs
├── RightClickTools.csproj
├── RightClickTools.csproj.user
├── RightClickTools.ico
├── RightClickTools.sln
└── app.manifest
/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32;
2 | using System;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Text;
6 | using System.Windows.Forms;
7 | using System.Drawing;
8 | using System.Drawing.Drawing2D;
9 | using System.Runtime.InteropServices;
10 | using System.Security.Principal;
11 | using System.Linq;
12 | using System.ServiceProcess;
13 | using System.Threading;
14 |
15 | namespace RightClickTools
16 | {
17 | class Program
18 | {
19 | static string myName = typeof(Program).Namespace;
20 | static string myPath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
21 | static string myExe = System.Reflection.Assembly.GetExecutingAssembly().Location;
22 | static string TempPath = Path.GetTempPath(); //Includes trailing backslash
23 | static string ElevateCfg = $@"{TempPath}Elevate.cfg";
24 | static string appParts = $@"{myPath}\AppParts";
25 | static string myIniFile = $@"{appParts}\{myName}.ini";
26 | static string myIcon = $@"{myPath}\AppParts\Icons\{myName}.ico";
27 | static string AdvKey = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced";
28 | static string perKey = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
29 | static string ExpKey = @"HKEY_LOCAL_MACHINE\Software\Classes\AppID\{CDCBCFCA-3CDC-436f-A4E2-0E02075250C2}";
30 | static string bitPath = "64";
31 | static bool Hidden = false;
32 | static string NTkey = @"HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion";
33 | static int buildNumber = int.Parse(Registry.GetValue(NTkey, "CurrentBuild", "").ToString());
34 | static bool Win11 = buildNumber >= 21996;
35 | static bool Win11Install = false;
36 | static bool AnyInstall = false;
37 | static string CCMfolder = FindCustomCommandsFolder(true);
38 | static string CCMA = @"Software\Classes\CLSID\{86CA1AA0-34AA-4E8B-A509-50C905BAE2A2}";
39 | static string CCMB = $@"{CCMA}\InprocServer32";
40 | static bool Win10ContextMenu = false;
41 |
42 | static string sMain = "Right-Click Tools";
43 | static string sSetup = "Install or Remove this tool";
44 | static string sOK = "OK";
45 | static string sYes = "Yes";
46 | static string sNo = "No";
47 | static string sInstall = "Install";
48 | static string sRemove = "Remove";
49 | static string sDone = "Done";
50 | static string[] CmdKeys = { "CmdHere", "CmdAdminHere", "CmdTrustedHere", "PowerShellHere", "PowerShellAdminHere", "PowerShellTrustedHere", "RegEdit", "RegEditAdmin", "RegEditTrusted", "ClearHistory", "TakeOwnHere", "AddDelPathHere", "ShowHide", "RefreshShellHere", "RestartExplorerHere", "FileManagerHere" };
51 | static string[] CmdLabels = { "Cmd here", "Cmd here as Administrator", "Cmd here as TrustedInstaller", "PowerShell here", "PowerShell here as Administrator", "PowerShell here as TrustedInstaller", "RegEdit as User", "RegEdit as Administrator", "RegEdit as TrustedInstaller", "Clear History", "Take ownership and get access", "Add or Remove folder in Path variable", "Toggle display of hidden and system files", "Refresh shell", "Restart Explorer", "Privileged file manager here" };
52 | static string sClearHistory = CmdLabels[9];
53 | static string sTakeOwnHere = CmdLabels[10];
54 | static string sRestartExplorer = CmdLabels[14];
55 | static string sFolderNotAllowed = "Not allowed for this folder";
56 | static string sWarningTakeOwn = "WARNING: Other users may lose access";
57 | static string sUserPath = "User Path";
58 | static string sSystemPath = "System Path";
59 | static string sRecent = "Recent items";
60 | static string sAutoSuggest = "Auto-suggest items";
61 | static string sTemp = "Temporary files";
62 | static string sDefender = "Defender history";
63 | static string sCCM = "Classic context menu";
64 | static string sRestartPC = "A restart is required to clear the Protection history. Restart now?";
65 | static string sOpenFileManager = "Open file manager as...";
66 | static string sAdministrator = "Administrator";
67 | static string sTrustedInstaller = "Trusted Installer";
68 | static string sShellRefresh = "Shell refresh only";
69 | static string sResetIcons = "Reset icon cache";
70 | static string sResetThumbs = "Reset thumbnail cache";
71 | static string sFileManager = "File Manager";
72 | static string sInstallTask = "Privilege elevation task";
73 |
74 | static string Option = "";
75 | static string StartDirectory = "";
76 | static string CommandLine = "";
77 |
78 | static float ScaleFactor = GetScale();
79 | static bool Dark = isDark();
80 | static bool isAdmin = false;
81 | static bool isFullAdmin = false;
82 | static bool ctrlKey = false;
83 | static bool fLatCB = true;
84 | static bool addTask = true;
85 | static bool removeTask = true;
86 |
87 | static string UserKey = @"HKEY_CURRENT_USER\Environment";
88 | static string SystemKey = @"HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment";
89 | static string UserPath = (string)Registry.GetValue(UserKey, "Path", "");
90 | static string SystemPath = (string)Registry.GetValue(SystemKey, "Path", "");
91 | static bool InUserPath = false;
92 | static bool InSystemPath = false;
93 | static int pathLength = UserPath.Length + SystemPath.Length;
94 | static string UIkey = @"HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Authentication\LogonUI";
95 | static string userSID = "";
96 |
97 | static string CmdExe = @"C:\Windows\System32\Cmd.exe";
98 | static string PowerShellExe = @"C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe";
99 | static string RegEditExe = @"C:\Windows\RegEdit.exe";
100 | static string SchTasksExe = @"C:\Windows\System32\SchTasks.exe";
101 |
102 | static string UserName = Environment.GetEnvironmentVariable("UserName");
103 | static string TaskName = $@"MyTasks\{myName}-{UserName}";
104 | static string helpPage = "install-and-remove";
105 | static int bwidth = 75;
106 |
107 | static CheckBox userPathCheckbox;
108 | static CheckBox systemPathCheckbox;
109 |
110 | static CheckBox ShellRefreshCheckbox;
111 | static CheckBox iconCacheCheckbox;
112 | static CheckBox thumbCacheCheckbox;
113 |
114 | static CheckBox RecentItemsCheckbox;
115 | static CheckBox AutoSuggestCheckbox;
116 | static CheckBox TempFilesCheckbox;
117 | static CheckBox DefenderCheckbox;
118 | static CheckBox checkboxCCM;
119 | static CheckBox checkboxTask;
120 |
121 | [STAThread]
122 | static void Main(string[] args)
123 | {
124 | // If the current folder is a long path, the Elevate function will fail, so let's make C:\ the current folder.
125 | Directory.SetCurrentDirectory(@"C:\");
126 |
127 | ctrlKey = (GetAsyncKeyState(0x11) & 0x8000) != 0; //Detect if Ctrl key is pressed
128 |
129 | if (!Environment.Is64BitOperatingSystem) bitPath = "32";
130 |
131 | LoadLanguageStrings();
132 | Application.EnableVisualStyles();
133 | Application.SetCompatibleTextRenderingDefault(false);
134 |
135 | isAdmin = IsCurrentUserInAdminGroup();
136 | isFullAdmin = isAdmin && TaskExists();
137 |
138 | try { Hidden = (int)Registry.GetValue(AdvKey, "Hidden", 0) == 1; } catch { }
139 |
140 | try { userSID = (string)Registry.GetValue(UIkey, "LastLoggedOnUserSID", ""); } catch { }
141 |
142 | if (userSID == "") findUserSID();
143 |
144 | if (args.Length == 0) { InstallRemove(); return; }
145 |
146 | Option = args[0];
147 |
148 | if (args.Length > 1)
149 | {
150 | StartDirectory = args[1].Replace("|", "");
151 | }
152 |
153 | switch (Option.ToLower())
154 | {
155 | case "/dark":
156 | SetExplorerOptions(0);
157 | break;
158 |
159 | case "/light":
160 | SetExplorerOptions(1);
161 | break;
162 |
163 | case "/install":
164 | Install(false);
165 | break;
166 |
167 | case "/installmin":
168 | addTask = false;
169 | Install(false);
170 | break;
171 |
172 | case "/remove":
173 | Remove(false);
174 | break;
175 |
176 | case "/removemin":
177 | removeTask = false;
178 | Remove(false);
179 | break;
180 |
181 | case "/hkuinstall":
182 | HKUInstall();
183 | break;
184 |
185 | case "/hkuinstallmin":
186 | addTask = false;
187 | HKUInstall();
188 | break;
189 |
190 | case "/hkuremove":
191 | HKURemove();
192 | break;
193 |
194 | case "/taskinstall":
195 | TaskInstall(true);
196 | break;
197 |
198 | case "/taskremove":
199 | TaskRemove(true);
200 | break;
201 |
202 | case "/taskinstallquiet":
203 | TaskInstall(false);
204 | break;
205 |
206 | case "/taskremovequiet":
207 | TaskRemove(false);
208 | break;
209 |
210 | case "/elevate":
211 | if (args.Length > 1) { ElevateCfg = args[1]; }
212 | Elevate();
213 | break;
214 |
215 | case "/cmdhere":
216 | RunAsUser(CmdExe);
217 | break;
218 |
219 | case "/cmdadminhere":
220 | RunAsAdmin(CmdExe);
221 | break;
222 |
223 | case "/cmdtrustedhere":
224 | RunAsTrusted(CmdExe);
225 | break;
226 |
227 | case "/powershellhere":
228 | GetPSPath();
229 | RunAsUser(PowerShellExe);
230 | break;
231 |
232 | case "/powershelladminhere":
233 | GetPSPath();
234 | RunAsAdmin(PowerShellExe);
235 | break;
236 |
237 | case "/powershelltrustedhere":
238 | GetPSPath();
239 | RunAsTrusted(PowerShellExe);
240 | break;
241 |
242 | case "/regedit":
243 | Environment.SetEnvironmentVariable("__COMPAT_LAYER", "RUNASINVOKER");
244 | if (ctrlKey) clearRegEdit();
245 | CommandLine = "/m";
246 | RunAsUser(RegEditExe);
247 | break;
248 |
249 | case "/regeditadmin":
250 | CommandLine = "/m";
251 | RunAsAdmin(RegEditExe);
252 | break;
253 |
254 | case "/regedittrusted":
255 | CommandLine = "/m";
256 | RunAsTrusted(RegEditExe);
257 | break;
258 |
259 | case "/allowelevatedexplorer":
260 | object runAsValue = Registry.GetValue(ExpKey, "RunAs", null);
261 | if (runAsValue != null && runAsValue.ToString() == "Interactive User")
262 | {
263 | Registry.SetValue(ExpKey, "RunAs", "", RegistryValueKind.String);
264 | Thread.Sleep(5000);
265 | Registry.SetValue(ExpKey, "RunAs", "Interactive User", RegistryValueKind.String);
266 | }
267 | break;
268 |
269 | case "/minifilemanager":
270 | OpenFileDialog fd = new OpenFileDialog
271 | {
272 | Title = sFileManager,
273 | Filter = "",
274 | InitialDirectory = StartDirectory,
275 | Multiselect = true
276 | };
277 | fd.ShowDialog();
278 | break;
279 |
280 | case "/filemanagerhere":
281 | FileManagerHere();
282 | break;
283 |
284 | case "/takeownhere":
285 | RunTakeOwnHerePS1AsAdmin();
286 | break;
287 |
288 | case "/adddelpathhere":
289 | AddDelPathHere();
290 | break;
291 |
292 | case "/addpathadmin":
293 | AddPathAdmin();
294 | break;
295 |
296 | case "/delpathadmin":
297 | DelPathAdmin();
298 | break;
299 |
300 | case "/showhide":
301 | ShowHide();
302 | break;
303 |
304 | case "/clearhistory":
305 | ClearHistory();
306 | break;
307 |
308 | case "/clearhistoryadmin":
309 | ClearDefenderHistoryTask();
310 | break;
311 |
312 | case "/refreshshellhere":
313 | RefreshShellHere();
314 | break;
315 |
316 | case "/restartexplorerhere":
317 | helpPage = "restart-explorer";
318 | DialogResult result = CustomMessageBox.Show($"{sRestartExplorer}?", sMain);
319 | if (result == DialogResult.Cancel) return;
320 | RestartExplorer();
321 | break;
322 |
323 | default:
324 | return;
325 | }
326 | }
327 |
328 | static void GetPSPath()
329 | {
330 | string PSPath = ReadString(myIniFile, "PowerShellHere", "Exe", "");
331 | if (File.Exists(PSPath)) PowerShellExe = PSPath;
332 | }
333 |
334 | static void SetExplorerOptions(int light)
335 | {
336 | Registry.SetValue(perKey, "AppsUseLightTheme", light, RegistryValueKind.DWord);
337 | Registry.SetValue(perKey, "SystemUsesLightTheme", light, RegistryValueKind.DWord);
338 | Registry.SetValue(AdvKey, "Hidden", 1, RegistryValueKind.DWord);
339 | Registry.SetValue(AdvKey, "ShowSuperHidden", 1, RegistryValueKind.DWord);
340 | Registry.SetValue(AdvKey, "HideFileExt", 0, RegistryValueKind.DWord);
341 | Registry.SetValue(AdvKey, "UseCompactMode", 1, RegistryValueKind.DWord);
342 | }
343 |
344 | static void findUserSID()
345 | {
346 | string userName = "";
347 | try { userName = (string)Registry.GetValue(UIkey, "LastLoggedOnUser", ""); } catch { }
348 | if (userName == "") return;
349 | userName = userName.Substring(userName.LastIndexOf('\\') + 1);
350 |
351 | using (RegistryKey hkeyUsers = Registry.Users)
352 | {
353 | foreach (string userSid in hkeyUsers.GetSubKeyNames())
354 | {
355 | try
356 | {
357 | using (RegistryKey volatileEnvKey = hkeyUsers.OpenSubKey($@"{userSid}\Volatile Environment"))
358 | {
359 | if (volatileEnvKey != null)
360 | {
361 | object usernameValue = volatileEnvKey.GetValue("USERNAME");
362 | if (usernameValue != null && usernameValue.ToString().Equals(userName, StringComparison.OrdinalIgnoreCase))
363 | {
364 | userSID = userSid;
365 | return;
366 | }
367 | }
368 | }
369 | }
370 | catch { }
371 | }
372 | }
373 | userSID = "";
374 | }
375 |
376 | static bool IsCurrentUserInAdminGroup()
377 | {
378 | var claims = new WindowsPrincipal(WindowsIdentity.GetCurrent()).Claims;
379 | var adminClaimID = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null).Value;
380 | return claims.Any(c => c.Value == adminClaimID);
381 | }
382 |
383 | static bool TaskExists()
384 | {
385 | Process process = new Process();
386 | process.StartInfo.FileName = "schtasks.exe";
387 | process.StartInfo.Arguments = $"/query /tn {TaskName}";
388 | process.StartInfo.RedirectStandardOutput = true;
389 | process.StartInfo.RedirectStandardError = true;
390 | process.StartInfo.UseShellExecute = false;
391 | process.StartInfo.CreateNoWindow = true;
392 | process.Start();
393 | process.WaitForExit();
394 | return process.ExitCode == 0;
395 | }
396 |
397 | static void RunUAC(string fileName)
398 | {
399 | Process p = new Process();
400 | p.StartInfo.FileName = fileName;
401 | p.StartInfo.Arguments = CommandLine;
402 | p.StartInfo.UseShellExecute = true;
403 | p.StartInfo.CreateNoWindow = true;
404 | p.StartInfo.Verb = "runas";
405 | p.Start();
406 | p.WaitForExit();
407 | }
408 |
409 | static void FileManagerHere()
410 | {
411 | helpPage = "privileged-file-manager-here";
412 | bwidth = 120;
413 | DialogResult result = TwoChoiceBox.Show(sOpenFileManager, sMain, sAdministrator, sTrustedInstaller);
414 | if (result == DialogResult.Cancel) return;
415 |
416 | CommandLine = $"\"{StartDirectory}\"";
417 |
418 | string FMExe = ReadString(myIniFile, "FileManagerHere", "Exe", "");
419 |
420 | // Set file manager to Explorer if no valid third-party file manager is set
421 | if (FMExe == "" || $@"\{FMExe}".ToLower().EndsWith("\\explorer.exe") || !File.Exists(FMExe))
422 | {
423 | if (Win11 && result == DialogResult.No)
424 | {
425 | CommandLine = $"/MiniFileManager \"{StartDirectory}\"";
426 | FMExe = myExe;
427 | }
428 | else
429 | {
430 | FMExe = "explorer.exe";
431 |
432 | // Check registry value that prevents Explorer to run elevated
433 | object runAsValue = Registry.GetValue(ExpKey, "RunAs", null);
434 | if (runAsValue != null && runAsValue.ToString() == "Interactive User")
435 | {
436 | if (isFullAdmin)
437 | {
438 | // Temporarily allow Explorer to run elevated
439 | CommandLine = "/AllowElevatedExplorer";
440 | RunAsTrusted(myExe);
441 | // Wait for registry entry to be updated
442 | for (int i = 0; i < 100; i++)
443 | {
444 | Thread.Sleep(20);
445 | runAsValue = Registry.GetValue(ExpKey, "RunAs", null);
446 | if (runAsValue == null || runAsValue.ToString() != "Interactive User") break;
447 | }
448 | CommandLine = $"\"{StartDirectory}\"";
449 | }
450 | else
451 | {
452 | CommandLine = $"/MiniFileManager \"{StartDirectory}\"";
453 | FMExe = myExe;
454 | }
455 | }
456 | }
457 | };
458 |
459 | if (result == DialogResult.Yes) RunAsAdmin(FMExe);
460 | if (result == DialogResult.No) RunAsTrusted(FMExe);
461 | }
462 |
463 | static void AddPathAdmin()
464 | {
465 | char[] trimThis = { '\\' };
466 | string path = StartDirectory.Trim(trimThis);
467 | InUserPath = IsPathInEnvironmentVariable(path, UserPath);
468 | InSystemPath = IsPathInEnvironmentVariable(path, SystemPath);
469 | AddPathToEnvironmentVariable(path, SystemPath, SystemKey, false);
470 | }
471 |
472 | static void DelPathAdmin()
473 | {
474 | char[] trimThis = { '\\' };
475 | string path = StartDirectory.Trim(trimThis);
476 | InUserPath = IsPathInEnvironmentVariable(path, UserPath);
477 | InSystemPath = IsPathInEnvironmentVariable(path, SystemPath);
478 | RemovePathFromEnvironmentVariable(path, SystemPath, SystemKey, false);
479 | }
480 |
481 | static void ClearHistory()
482 | {
483 | DialogResult result = ClearHistoryDialog.Show(sClearHistory, sMain);
484 |
485 | if (result == DialogResult.Cancel) return;
486 |
487 | if (RecentItemsCheckbox.Checked)
488 | {
489 | string Recent = Environment.GetFolderPath(Environment.SpecialFolder.Recent);
490 | try
491 | {
492 | Directory.GetFiles(Recent, "*", SearchOption.TopDirectoryOnly).ToList().ForEach(File.Delete);
493 | Directory.GetFiles($@"{Recent}\AutomaticDestinations", "*", SearchOption.TopDirectoryOnly).ToList().ForEach(File.Delete);
494 | Directory.GetFiles($@"{Recent}\CustomDestinations", "*", SearchOption.TopDirectoryOnly).ToList().ForEach(File.Delete);
495 | }
496 | catch
497 | {
498 | }
499 | }
500 |
501 | if (AutoSuggestCheckbox.Checked)
502 | {
503 | string parentKey = @"Software\Microsoft\Windows\CurrentVersion\Explorer";
504 | ClearRegValues($@"{parentKey}\RunMRU");
505 | ClearRegValues($@"{parentKey}\TypedPaths");
506 |
507 | Process p = new Process();
508 | p.StartInfo.FileName = "Rundll32.exe";
509 | p.StartInfo.Arguments = "InetCpl.cpl,ClearMyTracksByProcess 1";
510 | p.StartInfo.WorkingDirectory = @"C:\";
511 | p.StartInfo.UseShellExecute = false;
512 | p.StartInfo.CreateNoWindow = true;
513 | p.Start();
514 | }
515 |
516 | if (TempFilesCheckbox.Checked)
517 | {
518 | var filesAndFolders = Directory.GetFileSystemEntries(TempPath, "*", SearchOption.TopDirectoryOnly);
519 |
520 | foreach (var entry in filesAndFolders)
521 | {
522 | try
523 | {
524 | if (File.Exists(entry))
525 | {
526 | File.Delete(entry);
527 | }
528 | else if (Directory.Exists(entry))
529 | {
530 | Directory.Delete(entry, true);
531 | }
532 | }
533 | catch
534 | {
535 | }
536 | }
537 | }
538 |
539 | if (DefenderCheckbox.Checked)
540 | {
541 | ClearDefenderHistory();
542 | }
543 | }
544 |
545 | static void ClearRegValues(string keyPath)
546 | {
547 | try
548 | {
549 | using (RegistryKey key = Registry.CurrentUser.OpenSubKey(keyPath, true))
550 | {
551 | if (key != null)
552 | {
553 | foreach (string valueName in key.GetValueNames())
554 | {
555 | key.DeleteValue(valueName);
556 | }
557 | }
558 | }
559 | }
560 | catch
561 | {
562 | }
563 | }
564 |
565 | static void AddDelPathHere()
566 | {
567 | string path = StartDirectory;
568 |
569 | InUserPath = IsPathInEnvironmentVariable(path, UserPath);
570 | InSystemPath = IsPathInEnvironmentVariable(path, SystemPath);
571 |
572 | if (path.EndsWith(":")) path += "\\";
573 |
574 | DialogResult result = AddDelPathDialog.Show(path, sMain);
575 |
576 | if (result == DialogResult.Cancel) return;
577 |
578 | if (userPathCheckbox.Checked != InUserPath)
579 | {
580 | if (userPathCheckbox.Checked)
581 | AddPathToEnvironmentVariable(path, UserPath, UserKey, true);
582 | else
583 | RemovePathFromEnvironmentVariable(path, UserPath, UserKey, true);
584 | }
585 |
586 | if (systemPathCheckbox.Checked != InSystemPath)
587 | {
588 |
589 | if (systemPathCheckbox.Checked)
590 | {
591 | CommandLine = $"/AddPathAdmin \"{StartDirectory}\"";
592 | }
593 | else
594 | {
595 | CommandLine = $"/DelPathAdmin \"{StartDirectory}\"";
596 | }
597 | RunElevated(myExe, "Administrator");
598 | }
599 | }
600 |
601 | static bool IsPathInEnvironmentVariable(string pathToCheck, string environmentVariable)
602 | {
603 | string[] paths = environmentVariable.Split(';');
604 | char[] trimThis = { '\\' };
605 | foreach (string p in paths)
606 | {
607 | if (string.Equals(p.Trim(trimThis), pathToCheck, StringComparison.OrdinalIgnoreCase))
608 | {
609 | return true;
610 | }
611 | }
612 | return false;
613 | }
614 |
615 | static void AddPathToEnvironmentVariable(string pathToAdd, string environmentVariable, string Key, bool User)
616 | {
617 | if (User && InUserPath) return;
618 | if (!User && InSystemPath) return;
619 |
620 | if ((pathLength + pathToAdd.Length) > 4095) return;
621 |
622 | string newPath = $"{environmentVariable};{pathToAdd}";
623 | newPath = newPath.Replace(";;",";");
624 | Registry.SetValue(Key, "Path", newPath, RegistryValueKind.ExpandString);
625 | }
626 |
627 | static void RemovePathFromEnvironmentVariable(string pathToRemove, string environmentVariable, string Key, bool User)
628 | {
629 | if (User && !InUserPath) return;
630 | if (!User && !InSystemPath) return;
631 |
632 | string[] paths = environmentVariable.Split(';');
633 | char[] trimThis = { '\\' };
634 | pathToRemove = pathToRemove.Trim(trimThis);
635 | string newPath = "";
636 | foreach (string p in paths)
637 | {
638 | if (!string.Equals(p.Trim(trimThis), pathToRemove, StringComparison.OrdinalIgnoreCase))
639 | {
640 | if (!string.IsNullOrEmpty(newPath))
641 | {
642 | newPath += ";";
643 | }
644 | newPath += p;
645 | }
646 | }
647 | newPath = newPath.Replace(";;", ";");
648 | Registry.SetValue(Key, "Path", newPath, RegistryValueKind.ExpandString);
649 | }
650 |
651 | static void ShowHide()
652 | {
653 | ToggleHiddenFiles(!Hidden);
654 | }
655 |
656 | static void RefreshShell()
657 | {
658 | SHChangeNotify(0x08000000, 0x1000, IntPtr.Zero, IntPtr.Zero);
659 |
660 | if (buildNumber >= 14393)
661 | {
662 | ToggleHiddenFiles(!Hidden);
663 | ToggleHiddenFiles(Hidden);
664 | }
665 | }
666 |
667 | static void RefreshShellHere()
668 | {
669 | DialogResult result = ShellRefreshDialog.Show("", sMain);
670 |
671 | if (result == DialogResult.Cancel) return;
672 |
673 | RefreshShell();
674 |
675 | if (iconCacheCheckbox.Checked || thumbCacheCheckbox.Checked)
676 | {
677 | if (StartDirectory.ToLower().EndsWith("\\desktop"))
678 | {
679 | if (!DesktopWindowFound()) StartDirectory = "";
680 | }
681 |
682 | using (Process p = new Process())
683 | {
684 | p.StartInfo = new ProcessStartInfo
685 | {
686 | FileName = "taskkill.exe",
687 | Arguments = "/f /im explorer.exe",
688 | WindowStyle = ProcessWindowStyle.Hidden,
689 | UseShellExecute = true,
690 | CreateNoWindow = true,
691 | };
692 | p.Start();
693 | p.WaitForExit();
694 | }
695 |
696 | Thread.Sleep(2000);
697 |
698 | if (iconCacheCheckbox.Checked) DeleteCacheFiles("iconcache_*.db");
699 |
700 | if (thumbCacheCheckbox.Checked) DeleteCacheFiles("thumbcache_*.db");
701 |
702 | Process.Start("explorer.exe");
703 | if (StartDirectory != "") Process.Start("explorer.exe", StartDirectory);
704 | }
705 | }
706 |
707 | static void DeleteCacheFiles(string searchPattern)
708 | {
709 | string targetDirectory = $@"{Environment.GetEnvironmentVariable("LocalAppData")}\Microsoft\Windows\Explorer";
710 |
711 | try
712 | {
713 | string[] files = Directory.GetFiles(targetDirectory, searchPattern, SearchOption.TopDirectoryOnly);
714 |
715 | foreach (string file in files)
716 | {
717 | try { File.Delete(file); }
718 | catch { }
719 | }
720 | }
721 | catch { }
722 | }
723 |
724 | static void ToggleHiddenFiles(bool bShow)
725 | {
726 | if (buildNumber >= 14393)
727 | {
728 | Structures.SHELLSTATE state = new Structures.SHELLSTATE();
729 | state.FShowAllObjects = (uint)(bShow ? 1 : 2);
730 | state.FShowSuperHidden = (uint)(bShow ? 1 : 0);
731 | SHGetSetSettings(ref state, Structures.SSF.SSF_SHOWALLOBJECTS | Structures.SSF.SSF_SHOWSUPERHIDDEN, true);
732 | }
733 | else
734 | {
735 | int h1 = 1; int h2 = 1;
736 | if (Hidden) { h1 = 2; h2 = 0; }
737 | Registry.SetValue(AdvKey, "Hidden", h1, RegistryValueKind.DWord);
738 | Registry.SetValue(AdvKey, "ShowSuperHidden", h2, RegistryValueKind.DWord);
739 | Thread.Sleep(100);
740 | SendKeys.SendWait("{F5}");
741 | }
742 | }
743 |
744 | [DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = true)]
745 | public static extern void SHChangeNotify(uint wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);
746 |
747 | [DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = true)]
748 | public extern static void SHGetSetSettings(ref Structures.SHELLSTATE lpss, Structures.SSF dwMask, bool bSet);
749 |
750 | internal static class Structures
751 | {
752 | [Flags]
753 | public enum SSF : int
754 | {
755 | SSF_SHOWALLOBJECTS = 0x00000001,
756 | SSF_SHOWSUPERHIDDEN = 0x00040000,
757 | }
758 | [StructLayout(LayoutKind.Sequential)]
759 | public struct SHELLSTATE
760 | {
761 | public uint bitvector;
762 |
763 | public uint FShowAllObjects
764 | {
765 | get => this.bitvector & 1;
766 | set => this.bitvector = value | this.bitvector;
767 | }
768 |
769 | public uint FShowSuperHidden
770 | {
771 | get => (this.bitvector & 0x8000) / 0x8000;
772 | set => this.bitvector = (value * 0x8000) | this.bitvector;
773 | }
774 | }
775 | }
776 |
777 | [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
778 | private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
779 |
780 | [DllImport("user32.dll", SetLastError = true)]
781 | private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
782 |
783 | static bool DesktopWindowFound()
784 | {
785 | bool desktopFound = false;
786 | IntPtr hwnd = IntPtr.Zero;
787 | do
788 | {
789 | hwnd = FindWindowEx(IntPtr.Zero, hwnd, "CabinetWClass", null);
790 |
791 | if (hwnd != IntPtr.Zero)
792 | {
793 | StringBuilder windowTitle = new StringBuilder(256);
794 | GetWindowText(hwnd, windowTitle, windowTitle.Capacity);
795 | string t = windowTitle.ToString().ToLower();
796 | if (t == "desktop" || t == "desktop - file explorer")
797 | {
798 | desktopFound = true;
799 | break;
800 | }
801 | }
802 | }
803 | while (hwnd != IntPtr.Zero);
804 | return desktopFound;
805 | }
806 |
807 | static void RestartExplorer()
808 | {
809 | if (StartDirectory.ToLower().EndsWith("\\desktop"))
810 | {
811 | if (!DesktopWindowFound()) StartDirectory = "";
812 | }
813 |
814 | RefreshShell();
815 |
816 | var processes = Process.GetProcessesByName("explorer");
817 | foreach (var process in processes)
818 | {
819 | try
820 | {
821 | process.Kill();
822 | process.WaitForExit();
823 | }
824 | catch { }
825 | }
826 | if (StartDirectory != "") Process.Start("explorer.exe", StartDirectory);
827 | }
828 |
829 | static void CreateChangeDirectoryFile(string EXEFilename)
830 | {
831 | if (EXEFilename == CmdExe)
832 | {
833 | string cdFile = $@"{TempPath}ChangeDirectory.cmd";
834 | StartDirectory = StartDirectory.Replace("%", "%%"); //Escape percent signs
835 | string Data = $"@echo off\r\nchcp 65001>nul\r\ncd /d \"{StartDirectory}\"";
836 | Data += "\r\nstart /b \"\" cmd /c del \"%~f0\"";
837 | File.WriteAllText(cdFile, Data);
838 | CommandLine = $"/k \"{cdFile}\"";
839 | }
840 |
841 | if (EXEFilename == PowerShellExe)
842 | {
843 | string cdFile = $@"{TempPath}ChangeDirectory.ps1";
844 | StartDirectory = StartDirectory.Replace("'", "''"); //Escape single quotes
845 | string Data = $@"Set-Location -LiteralPath '{StartDirectory}'";
846 | if (StartDirectory.Contains("~")) Data += "\r\nfunction Prompt {$shortPath = (New-Object -ComObject Scripting.FileSystemObject).GetFolder($pwd).ShortPath; return \"PS $($shortPath)> \"}";
847 | Data += "\r\nStart-Sleep -Milliseconds 100; Remove-Item $MyInvocation.MyCommand.Path -Force\r\n"; //Delete itself when done
848 | File.WriteAllText(cdFile, Data, Encoding.UTF8); //UTF-8 with BOM
849 | CommandLine = $"-NoLogo -NoExit -NoProfile -ExecutionPolicy Bypass -file \"{cdFile}\"";
850 | }
851 | }
852 |
853 | static void CreateTakeOwnHerePS1()
854 | {
855 | StartDirectory = StartDirectory.Replace("'", "''"); //Escape single quotes
856 | string PS1Data = $"$SetACL = '{appParts.Replace("'", "''")}\\{bitPath}\\SetACL.exe'\r\n";
857 | PS1Data += "$UserName = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name\r\n";
858 | PS1Data += $"& $SetACL -on '{StartDirectory}' -ot file -actn setowner -ownr \"n:$UserName\" -rec cont_obj\r\n";
859 | PS1Data += $"& $SetACL -on '{StartDirectory}' -ot file -actn setprot -op \"dacl:np;sacl:np\" -rec cont_obj\r\n";
860 | PS1Data += "Start-Sleep -Milliseconds 100; Remove-Item $MyInvocation.MyCommand.Path -Force\r\n"; //Delete itself when done
861 | string PS1File = $@"{TempPath}TakeOwn.ps1";
862 | File.WriteAllText(PS1File, PS1Data, Encoding.UTF8);
863 | ctrlKey = (GetAsyncKeyState(0x11) & 0x8000) != 0;
864 | string NoExit = ""; if (ctrlKey) NoExit = "-NoExit";
865 | CommandLine = $"{NoExit} -NoLogo -NoProfile -ExecutionPolicy Bypass -file \"{PS1File}\"";
866 | }
867 |
868 | static void RunAsUser(string EXEFilename)
869 | {
870 | CreateChangeDirectoryFile(EXEFilename);
871 |
872 | Process p = new Process();
873 | p.StartInfo.FileName = EXEFilename;
874 | p.StartInfo.Arguments = CommandLine;
875 | p.StartInfo.WorkingDirectory = @"C:\";
876 | p.StartInfo.UseShellExecute = false;
877 | p.StartInfo.CreateNoWindow = false;
878 | p.Start();
879 | }
880 |
881 | static void RunAsAdmin(string EXEFilename)
882 | {
883 | RunElevated(EXEFilename, "Administrator");
884 | }
885 |
886 | static void RunAsTrusted(string EXEFilename)
887 | {
888 | RunElevated(EXEFilename, "TrustedInstaller");
889 | }
890 |
891 | [DllImport("user32.dll")]
892 | public static extern short GetAsyncKeyState(int vKey);
893 |
894 | static void clearRegEdit()
895 | {
896 | try
897 | {
898 | Registry.CurrentUser.DeleteSubKey(@"Software\Microsoft\Windows\CurrentVersion\Applets\Regedit", false);
899 | }
900 | catch
901 | {
902 | }
903 | }
904 |
905 | static void Elevate()
906 | {
907 | string iniFile = ElevateCfg;
908 |
909 | string EXEFilename = ReadString(iniFile, "Process", "EXEFilename", "");
910 | string CommandLine = ReadString(iniFile, "Process", "CommandLine", "");
911 | string RunAs = ReadString(iniFile, "Process", "RunAs", "");
912 | string Dark = ReadString(iniFile, "Process", "Dark", "false");
913 | bool dark = Dark == "True";
914 |
915 | File.Delete(ElevateCfg);
916 |
917 | if (RunAs == "TrustedInstaller")
918 | {
919 | ServiceController sc = new ServiceController
920 | {
921 | ServiceName = "TrustedInstaller",
922 | };
923 |
924 | if (sc.Status != ServiceControllerStatus.Running) sc.Start();
925 |
926 | Process[] proc = Process.GetProcessesByName("TrustedInstaller");
927 |
928 | if (dark) TrustedInstaller.Run(proc[0].Id, $"{myExe} /Dark");
929 | if (!dark) TrustedInstaller.Run(proc[0].Id, $"{myExe} /Light");
930 |
931 | Thread.Sleep(100);
932 | proc = Process.GetProcessesByName("TrustedInstaller");
933 | TrustedInstaller.Run(proc[0].Id, $"{EXEFilename} {CommandLine}");
934 | }
935 | else
936 | {
937 | if (ctrlKey && (EXEFilename == RegEditExe)) clearRegEdit();
938 |
939 | Process p = new Process();
940 | p.StartInfo.FileName = EXEFilename;
941 | p.StartInfo.Arguments = CommandLine;
942 | p.StartInfo.WorkingDirectory = @"C:\";
943 | p.StartInfo.UseShellExecute = false;
944 | p.StartInfo.CreateNoWindow = false;
945 | p.Start();
946 | }
947 | }
948 |
949 | static void RunElevated(string EXEFilename, string mode)
950 | {
951 | CreateChangeDirectoryFile(EXEFilename);
952 |
953 | string cfg = $"[Process]\r\nEXEFilename={EXEFilename}\r\nCommandLine={CommandLine}\r\nRunAs={mode}\r\nDark={Dark}";
954 |
955 | File.WriteAllText(ElevateCfg, cfg);
956 |
957 | if (isFullAdmin)
958 | {
959 | Process p = new Process();
960 | p.StartInfo.FileName = SchTasksExe;
961 | p.StartInfo.Arguments = $"/run /tn \"{TaskName}\"";
962 | p.StartInfo.UseShellExecute = false;
963 | p.StartInfo.CreateNoWindow = true;
964 | p.Start();
965 | }
966 | else
967 | {
968 | if (mode == "Administrator")
969 | {
970 | RunUAC(EXEFilename);
971 | }
972 | else
973 | {
974 | Process p = new Process();
975 | p.StartInfo.FileName = myExe;
976 | p.StartInfo.Arguments = $"/Elevate \"{ElevateCfg}\"";
977 | p.StartInfo.UseShellExecute = true;
978 | p.StartInfo.CreateNoWindow = true;
979 | p.StartInfo.Verb = "runas";
980 | p.Start();
981 | }
982 | }
983 | }
984 |
985 | static void RunTakeOwnHerePS1AsAdmin()
986 | {
987 | string sStopAll = ReadString(myIniFile, "TakeOwnHere", "StopAll", "");
988 | string[] StopAll = sStopAll.Split(new char[] { '|' });
989 |
990 | string sStopRoot = ReadString(myIniFile, "TakeOwnHere", "StopRoot", "");
991 | string[] StopRoot = sStopRoot.Split(new char[] { '|' });
992 |
993 | bool Stop = false;
994 |
995 | for (int i = 0; i < StopAll.Length; i++)
996 | {
997 | if (StartsWith(StopAll[i], StartDirectory)) { Stop = true; break; }
998 | }
999 |
1000 | for (int i = 0; i < StopRoot.Length; i++)
1001 | {
1002 | if (StrCmp(StopRoot[i], StartDirectory)) { Stop = true; break; }
1003 | }
1004 |
1005 | helpPage = "take-ownership-and-get-access";
1006 |
1007 | if (Stop) { CustomMessageBox.Show($"{sFolderNotAllowed}:\n\n{StartDirectory}\n\n", sMain); return; }
1008 |
1009 | string UserProfile = Environment.GetEnvironmentVariable("UserProfile");
1010 | string sMsg = sTakeOwnHere;
1011 | if (StartsWith(StartDirectory, "C:\\Users\\") && !StartsWith(StartDirectory, UserProfile)) sMsg = $"{sWarningTakeOwn}\r\n\r\n{sTakeOwnHere}";
1012 |
1013 | DialogResult result = CustomMessageBox.Show($"{sMsg}?\n\n{StartDirectory}\n\n", sMain);
1014 |
1015 | if (result == DialogResult.Cancel) return;
1016 |
1017 | CreateTakeOwnHerePS1();
1018 |
1019 | string cfg = $"[Process]\r\nEXEFilename={PowerShellExe}\r\nCommandLine={CommandLine}\r\nRunAs=Administrator";
1020 |
1021 | File.WriteAllText(ElevateCfg, cfg);
1022 |
1023 | if (isFullAdmin)
1024 | {
1025 | Process p = new Process();
1026 | p.StartInfo.FileName = SchTasksExe;
1027 | p.StartInfo.Arguments = $"/run /tn \"{TaskName}\"";
1028 | p.StartInfo.UseShellExecute = false;
1029 | p.StartInfo.CreateNoWindow = true;
1030 | p.Start();
1031 | }
1032 | else
1033 | {
1034 | RunUAC(PowerShellExe);
1035 | }
1036 | }
1037 |
1038 | static void ClearDefenderHistory()
1039 | {
1040 | CommandLine = "/ClearHistoryAdmin";
1041 |
1042 | string cfg = $"[Process]\r\nEXEFilename={myExe}\r\nCommandLine={CommandLine}\r\nRunAs=Administrator";
1043 |
1044 | File.WriteAllText(ElevateCfg, cfg);
1045 |
1046 | if (isFullAdmin)
1047 | {
1048 | Process p = new Process();
1049 | p.StartInfo.FileName = SchTasksExe;
1050 | p.StartInfo.Arguments = $"/run /tn \"{TaskName}\"";
1051 | p.StartInfo.UseShellExecute = false;
1052 | p.StartInfo.CreateNoWindow = true;
1053 | p.Start();
1054 | }
1055 | else
1056 | {
1057 | RunUAC(myExe);
1058 | }
1059 |
1060 | }
1061 |
1062 | static void ClearDefenderHistoryTask()
1063 | {
1064 | string scans = @"C:\ProgramData\Microsoft\Windows Defender\Scans";
1065 | string service = $@"{scans}\History\Service";
1066 | string db = $@"{scans}\mpenginedb.db*";
1067 |
1068 | Process p = new Process();
1069 | p.StartInfo.FileName = SchTasksExe;
1070 | p.StartInfo.Arguments = $"/create /f /tn MyTasks\\DWDH /xml \"{appParts}\\DWDH.cfg\"";
1071 | p.StartInfo.UseShellExecute = false;
1072 | p.StartInfo.CreateNoWindow = true;
1073 | p.Start();
1074 | p.WaitForExit();
1075 |
1076 | helpPage = "clear-history";
1077 |
1078 | DialogResult result = CustomMessageBox.Show(sRestartPC, sMain);
1079 |
1080 | if (result == DialogResult.Cancel) return;
1081 |
1082 | Process.Start("shutdown", "/r /t 0");
1083 | }
1084 |
1085 | static bool StrCmp(string str1, string str2)
1086 | {
1087 | return string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase);
1088 | }
1089 |
1090 | static bool StartsWith(string str1, string str2)
1091 | {
1092 | int length = Math.Min(str1.Length, str2.Length);
1093 | return string.Equals(str1.Substring(0, length), str2.Substring(0, length), StringComparison.OrdinalIgnoreCase);
1094 | }
1095 |
1096 | // Get current screen scaling factor
1097 | static float GetScale()
1098 | {
1099 | using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero))
1100 | {
1101 | float dpiX = graphics.DpiX;
1102 | return dpiX / 96;
1103 | }
1104 | }
1105 |
1106 | // Determine if dark colors (theme) are being used
1107 | public static bool isDark()
1108 | {
1109 | const string keyPath = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
1110 | const string valueName = "AppsUseLightTheme";
1111 |
1112 | using (RegistryKey key = Registry.CurrentUser.OpenSubKey(keyPath))
1113 | {
1114 | if (key != null)
1115 | {
1116 | object value = key.GetValue(valueName);
1117 | if (value is int intValue)
1118 | {
1119 | return intValue == 0;
1120 | }
1121 | }
1122 | }
1123 | return false; // Return false if the key or value is missing
1124 | }
1125 |
1126 | // Make dialog title bar black
1127 | public enum DWMWINDOWATTRIBUTE : uint
1128 | {
1129 | DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
1130 | }
1131 |
1132 | [DllImport("dwmapi.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
1133 | public static extern void DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref int pvAttribute, uint cbAttribute);
1134 |
1135 | static void DarkTitleBar(IntPtr hWnd)
1136 | {
1137 | var preference = Convert.ToInt32(true);
1138 | DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref preference, sizeof(uint));
1139 |
1140 | }
1141 |
1142 | // Load language strings from INI file
1143 | static void LoadLanguageStrings()
1144 | {
1145 | string iniFile = $@"{appParts}\language.ini";
1146 |
1147 | if (!File.Exists(iniFile)) return;
1148 |
1149 | string lang = GetLang();
1150 |
1151 | sMain = ReadString(iniFile, lang, "sMain", sMain);
1152 | sSetup = ReadString(iniFile, lang, "sSetup", sSetup);
1153 | sOK = ReadString(iniFile, lang, "sOK", sOK);
1154 | sYes = ReadString(iniFile, lang, "sYes", sYes);
1155 | sNo = ReadString(iniFile, lang, "sNo", sNo);
1156 | sInstall = ReadString(iniFile, lang, "sInstall", sInstall);
1157 | sRemove = ReadString(iniFile, lang, "sRemove", sRemove);
1158 | sDone = ReadString(iniFile, lang, "sDone", sDone);
1159 | sFolderNotAllowed = ReadString(iniFile, lang, "sFolderNotAllowed", sFolderNotAllowed);
1160 | sWarningTakeOwn = ReadString(iniFile, lang, "sWarningTakeOwn", sWarningTakeOwn);
1161 | sUserPath = ReadString(iniFile, lang, "sUserPath", sUserPath);
1162 | sSystemPath = ReadString(iniFile, lang, "sSystemPath", sSystemPath);
1163 | sRecent = ReadString(iniFile, lang, "sRecent", sRecent);
1164 | sAutoSuggest = ReadString(iniFile, lang, "sAutoSuggest", sAutoSuggest);
1165 | sTemp = ReadString(iniFile, lang, "sTemp", sTemp);
1166 | sDefender = ReadString(iniFile, lang, "sDefender", sDefender);
1167 | sCCM = ReadString(iniFile, lang, "sCCM", sCCM);
1168 | sRestartPC = ReadString(iniFile, lang, "sRestartPC", sRestartPC);
1169 | sOpenFileManager = ReadString(iniFile, lang, "sOpenFileManager", sOpenFileManager);
1170 | sAdministrator = ReadString(iniFile, lang, "sAdministrator", sAdministrator);
1171 | sTrustedInstaller = ReadString(iniFile, lang, "sTrustedInstaller", sTrustedInstaller);
1172 | sShellRefresh = ReadString(iniFile, lang, "sShellRefresh", sShellRefresh);
1173 | sResetIcons = ReadString(iniFile, lang, "sResetIcons", sResetIcons);
1174 | sResetThumbs = ReadString(iniFile, lang, "sResetThumbs", sResetThumbs);
1175 | sFileManager = ReadString(iniFile, lang, "sFileManager", sFileManager);
1176 | sInstallTask = ReadString(iniFile, lang, "sInstallTask", sInstallTask);
1177 |
1178 | string sCmdLabels = ReadString(iniFile, lang, "CmdLabels", "");
1179 | string[] LangLabels = sCmdLabels.Split(new char[] { '|' });
1180 |
1181 | for (int i = 0; i < Math.Min(CmdLabels.Length, LangLabels.Length); i++)
1182 | {
1183 | CmdLabels[i] = LangLabels[i];
1184 | }
1185 | sClearHistory = CmdLabels[9];
1186 | sTakeOwnHere = CmdLabels[10];
1187 | sRestartExplorer = CmdLabels[14];
1188 | }
1189 |
1190 |
1191 | static string ReadString(string iniFile, string section, string key, string defaultValue)
1192 | {
1193 | try
1194 | {
1195 | if (File.Exists(iniFile))
1196 | {
1197 | return IniFileParser.ReadValue(section, key, defaultValue, iniFile);
1198 | }
1199 | }
1200 | catch { }
1201 |
1202 | return defaultValue;
1203 | }
1204 |
1205 | // INI file parser
1206 | public static class IniFileParser
1207 | {
1208 | public static string ReadValue(string section, string key, string defaultValue, string filePath)
1209 | {
1210 | try
1211 | {
1212 | var lines = File.ReadAllLines(filePath, Encoding.UTF8);
1213 | string currentSection = null;
1214 |
1215 | foreach (var line in lines)
1216 | {
1217 | string trimmedLine = line.Trim();
1218 |
1219 | if (trimmedLine.StartsWith("[") && trimmedLine.EndsWith("]"))
1220 | {
1221 | currentSection = trimmedLine.Substring(1, trimmedLine.Length - 2);
1222 | }
1223 | else if (currentSection == section)
1224 | {
1225 | var parts = trimmedLine.Split(new char[] { '=' }, 2);
1226 | if (parts.Length == 2 && parts[0].Trim() == key)
1227 | {
1228 | return parts[1].Trim();
1229 | }
1230 | }
1231 | }
1232 | }
1233 | catch (Exception)
1234 | {
1235 | }
1236 | return defaultValue;
1237 | }
1238 | }
1239 |
1240 |
1241 | // Get language from INI file or system
1242 | static string GetLang()
1243 | {
1244 | string lang = ReadString(myIniFile, "General", "Lang", "");
1245 | if (lang != "") return lang;
1246 |
1247 | lang = "en";
1248 |
1249 | try
1250 | {
1251 | RegistryKey key = Registry.CurrentUser.OpenSubKey("Control Panel\\International");
1252 | if (key != null)
1253 | {
1254 | lang = key.GetValue("LocaleName") as string;
1255 | key.Close();
1256 | }
1257 | }
1258 | catch { }
1259 |
1260 | try
1261 | {
1262 | RegistryKey key = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop");
1263 | if (key != null)
1264 | {
1265 | string[] preferredLanguages = key.GetValue("PreferredUILanguages") as string[];
1266 | if (preferredLanguages != null && preferredLanguages.Length > 0)
1267 | {
1268 | lang = preferredLanguages[0];
1269 | }
1270 | key.Close();
1271 | }
1272 | }
1273 | catch { }
1274 |
1275 | return lang.Substring(0, 2).ToLower();
1276 | }
1277 |
1278 | static void InstallRemove()
1279 | {
1280 | AnyInstall = true;
1281 |
1282 | if (Win11)
1283 | {
1284 | Win11Install = true;
1285 | using (RegistryKey key = Registry.CurrentUser.OpenSubKey(CCMB))
1286 | {
1287 | Win10ContextMenu = key != null;
1288 | }
1289 | }
1290 |
1291 | DialogResult result = TwoChoiceBox.Show(sSetup, sMain, sInstall, sRemove);
1292 |
1293 | if (result == DialogResult.Yes)
1294 | {
1295 | Install(true);
1296 | }
1297 | if (result == DialogResult.No)
1298 | {
1299 | Remove(true);
1300 | }
1301 | }
1302 |
1303 | static void ContextMenuInstall(bool HKCU)
1304 | {
1305 | RemoveContextMenuEntries(HKCU);
1306 | RemoveContextMenuEntriesCCM(HKCU);
1307 | InstallContextMenuEntries(@"Drive", HKCU);
1308 | InstallContextMenuEntries(@"Directory", HKCU);
1309 | InstallContextMenuEntries(@"Directory\Background", HKCU);
1310 | InstallContextMenuEntriesCCM(HKCU);
1311 | if (HKCU) SetWin11ContextMenu();
1312 | }
1313 | static void ContextMenuRemove(bool HKCU)
1314 | {
1315 | RemoveContextMenuEntries(HKCU);
1316 | RemoveContextMenuEntriesCCM(HKCU);
1317 | if (HKCU) SetWin11ContextMenu();
1318 | }
1319 |
1320 | static void Install(bool interactive)
1321 | {
1322 | ContextMenuInstall(true);
1323 |
1324 | if (!isAdmin)
1325 | {
1326 | if (interactive) CustomMessageBox.Show(sDone, sMain);
1327 | return;
1328 | }
1329 |
1330 | if (interactive) addTask = checkboxTask.Checked;
1331 |
1332 | if (addTask)
1333 | {
1334 | CommandLine = "/TaskInstallQuiet";
1335 | if (interactive) CommandLine = "/TaskInstall";
1336 | RunUAC(myExe);
1337 | }
1338 | else
1339 | {
1340 | if (interactive) CustomMessageBox.Show(sDone, sMain);
1341 | }
1342 | }
1343 |
1344 | static void Remove(bool interactive)
1345 | {
1346 | ContextMenuRemove(true);
1347 |
1348 | if (!isAdmin)
1349 | {
1350 | if (interactive) CustomMessageBox.Show(sDone, sMain);
1351 | return;
1352 | }
1353 |
1354 | if (removeTask && TaskExists())
1355 | {
1356 | CommandLine = "/TaskRemoveQuiet";
1357 | if (interactive) CommandLine = "/TaskRemove";
1358 | RunUAC(myExe);
1359 | }
1360 | else
1361 | {
1362 | if (interactive) CustomMessageBox.Show(sDone, sMain);
1363 | }
1364 |
1365 | }
1366 |
1367 | static void HKUInstall()
1368 | {
1369 | CCMfolder = FindCustomCommandsFolder(false);
1370 | ContextMenuInstall(false);
1371 | if (addTask) TaskInstall(false);
1372 | }
1373 |
1374 | static void HKURemove()
1375 | {
1376 | CCMfolder = FindCustomCommandsFolder(false);
1377 | ContextMenuRemove(false);
1378 | TaskRemove(false);
1379 | }
1380 |
1381 | static void SetWin11ContextMenu()
1382 | {
1383 | if (!Win11) return;
1384 |
1385 | string H = @"HKEY_CURRENT_USER\";
1386 |
1387 | if (checkboxCCM.Checked && !Win10ContextMenu)
1388 | {
1389 | try
1390 | {
1391 | Registry.SetValue($@"{H}{CCMB}", "", "", RegistryValueKind.String);
1392 | StartDirectory = myPath;
1393 | RestartExplorer();
1394 | }
1395 | catch
1396 | {
1397 | }
1398 | }
1399 |
1400 | if (!checkboxCCM.Checked && Win10ContextMenu)
1401 | {
1402 | try
1403 | {
1404 | Registry.CurrentUser.DeleteSubKeyTree(CCMA, false);
1405 | }
1406 | catch
1407 | {
1408 | }
1409 | }
1410 | }
1411 |
1412 | static void TaskInstall(bool interactive)
1413 | {
1414 | Process p = new Process();
1415 | p.StartInfo.FileName = SchTasksExe;
1416 | p.StartInfo.Arguments = $"/delete /f /tn \"{TaskName}\"";
1417 | p.StartInfo.UseShellExecute = false;
1418 | p.StartInfo.CreateNoWindow = true;
1419 | p.Start();
1420 | p.WaitForExit();
1421 |
1422 | string XMLFile = $@"{TempPath}Task.xml";
1423 | string XMLData = File.ReadAllText($@"{appParts}\Task.cfg");
1424 | XMLData = XMLData.Replace("{myPath}", myPath);
1425 | XMLData = XMLData.Replace("{bitPath}", bitPath);
1426 | File.WriteAllText(XMLFile, XMLData, Encoding.Unicode);
1427 |
1428 | p = new Process();
1429 | p.StartInfo.FileName = SchTasksExe;
1430 | p.StartInfo.Arguments = $"/create /f /xml \"{XMLFile}\" /tn \"{TaskName}\"";
1431 | p.StartInfo.UseShellExecute = false;
1432 | p.StartInfo.CreateNoWindow = true;
1433 | p.Start();
1434 | p.WaitForExit();
1435 |
1436 | File.Delete(XMLFile);
1437 |
1438 | if (interactive) CustomMessageBox.Show(sDone, sMain);
1439 | }
1440 |
1441 | static void TaskRemove(bool interactive)
1442 | {
1443 | Process p = new Process();
1444 | p.StartInfo.FileName = SchTasksExe;
1445 | p.StartInfo.Arguments = $"/delete /f /tn \"{TaskName}\"";
1446 | p.StartInfo.UseShellExecute = false;
1447 | p.StartInfo.CreateNoWindow = true;
1448 | p.Start();
1449 | p.WaitForExit();
1450 |
1451 | if (interactive) CustomMessageBox.Show(sDone, sMain);
1452 | }
1453 |
1454 | static void InstallContextMenuEntries(string thiskey, bool HKCU)
1455 | {
1456 | RegistryKey baseKey = Registry.CurrentUser;
1457 |
1458 | if (!HKCU)
1459 | {
1460 | if (userSID == "") return;
1461 | baseKey = Registry.Users.OpenSubKey(userSID, true);
1462 | }
1463 |
1464 | string MyKey = $@"Software\Classes\{thiskey}\shell\{myName}";
1465 |
1466 | using (RegistryKey key = baseKey.CreateSubKey(MyKey))
1467 | {
1468 | key.SetValue("SubCommands", "");
1469 | key.SetValue("", "");
1470 | key.SetValue("MUIVerb", sMain);
1471 | key.SetValue("Icon", myExe);
1472 | }
1473 |
1474 | for (int i = 0; i < CmdKeys.Length; i++)
1475 | {
1476 | using (RegistryKey key = baseKey.CreateSubKey($@"{MyKey}\shell\{i:D2}-{CmdKeys[i]}"))
1477 | {
1478 | key.SetValue("", CmdLabels[i]);
1479 | key.SetValue("Icon", $@"{appParts}\Icons\{CmdKeys[i]}.ico");
1480 |
1481 | using (RegistryKey commandKey = key.CreateSubKey("command"))
1482 | {
1483 | string CmdLine = $"\"{myExe}\" /{CmdKeys[i]}";
1484 | if (CmdKeys[i].Substring(CmdKeys[i].Length - 4) == "Here") CmdLine += " \"%v|\"";
1485 | commandKey.SetValue("", CmdLine);
1486 | }
1487 | }
1488 | }
1489 | }
1490 |
1491 | static void InstallContextMenuEntriesCCM(bool HKCU)
1492 | {
1493 | if (CCMfolder == null) return;
1494 | string exe = myExe.Replace(@"\", @"\\");
1495 |
1496 | for (int i = 0; i < CmdKeys.Length; i++)
1497 | {
1498 | string icon = $@"{appParts}\Icons\{CmdKeys[i]}.ico";
1499 | icon = icon.Replace(@"\", @"\\");
1500 | string JSONFile = $@"{CCMfolder}\{CmdLabels[i]}.JSON";
1501 | string JSONData = File.ReadAllText($@"{appParts}\JSON.cfg");
1502 | JSONData = JSONData.Replace("{i}", $"{i+100}");
1503 | JSONData = JSONData.Replace("{label}", CmdLabels[i]);
1504 | JSONData = JSONData.Replace("{exe}", exe);
1505 | JSONData = JSONData.Replace("{cmdline}", $@"/{CmdKeys[i]}");
1506 | JSONData = JSONData.Replace("{icon}", icon);
1507 | File.WriteAllText(JSONFile, JSONData);
1508 | }
1509 | }
1510 |
1511 | static void RemoveContextMenuEntriesCCM(bool HKCU)
1512 | {
1513 | if (CCMfolder == null) return;
1514 |
1515 | DirectoryInfo directory = new DirectoryInfo(CCMfolder);
1516 |
1517 | foreach (FileInfo file in directory.GetFiles("*.JSON"))
1518 | {
1519 | if (File.ReadAllText(file.FullName).Contains(myName))
1520 | {
1521 | file.Delete();
1522 | }
1523 | }
1524 | }
1525 |
1526 | static void RemoveContextMenuEntries(bool HKCU)
1527 | {
1528 | RegistryKey baseKey = Registry.CurrentUser;
1529 | if (!HKCU) baseKey = Registry.Users.OpenSubKey(userSID, true);
1530 |
1531 | using (RegistryKey key = baseKey.OpenSubKey(@"Software\Classes\Drive\shell", true))
1532 | {
1533 | try { key.DeleteSubKeyTree(myName, false); }
1534 | catch { }
1535 | }
1536 | using (RegistryKey key = baseKey.OpenSubKey(@"Software\Classes\Directory\shell", true))
1537 | {
1538 | try { key.DeleteSubKeyTree(myName, false); }
1539 | catch { }
1540 | }
1541 | using (RegistryKey key = baseKey.OpenSubKey(@"Software\Classes\Directory\Background\shell", true))
1542 | {
1543 | try { key.DeleteSubKeyTree(myName, false); }
1544 | catch { }
1545 | }
1546 |
1547 | }
1548 |
1549 | static string FindCustomCommandsFolder(bool HKCU)
1550 | {
1551 | string packagesFolderPath = $@"{Environment.GetEnvironmentVariable("LocalAppData")}\Packages";
1552 |
1553 | if (!HKCU)
1554 | {
1555 | string keyPath = $@"HKEY_USERS\{userSID}\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders";
1556 | packagesFolderPath = $@"{(string)Registry.GetValue(keyPath, @"Local AppData", "")}\Packages";
1557 | }
1558 |
1559 | if (!Directory.Exists(packagesFolderPath)) return null;
1560 |
1561 | string[] packageFolders = Directory.GetDirectories(packagesFolderPath);
1562 |
1563 | foreach (string packageFolder in packageFolders)
1564 | {
1565 | string customCommandsPath = Path.Combine(packageFolder, @"LocalState\custom_commands");
1566 | if (Directory.Exists(customCommandsPath)) return customCommandsPath;
1567 | }
1568 | return null;
1569 | }
1570 |
1571 |
1572 | // Dialog for simple OK messages
1573 | public class CustomMessageBox : Form
1574 | {
1575 | private Label messageLabel;
1576 | private Label buttonHelp;
1577 | private Button buttonOK;
1578 |
1579 | public CustomMessageBox(string message, string caption)
1580 | {
1581 | message = $"\n{message}";
1582 |
1583 | Icon = new Icon(myIcon);
1584 | StartPosition = FormStartPosition.Manual;
1585 | FormBorderStyle = FormBorderStyle.FixedDialog;
1586 | Text = caption;
1587 | Width = (int)(300 * ScaleFactor);
1588 | Height = (int)(150 * ScaleFactor);
1589 | MaximizeBox = false;
1590 | MinimizeBox = false;
1591 |
1592 | messageLabel = new Label();
1593 | messageLabel.Text = message;
1594 | messageLabel.Font = new Font("Segoe UI", 10);
1595 | messageLabel.TextAlign = ContentAlignment.TopCenter;
1596 | messageLabel.Dock = DockStyle.Fill;
1597 |
1598 | using (Graphics g = CreateGraphics())
1599 | {
1600 | SizeF size = g.MeasureString(message, new Font("Segoe UI", 10), Width);
1601 | Height = Math.Max(Height, (int)(size.Height + (int)(100 * ScaleFactor)));
1602 | }
1603 |
1604 | buttonHelp = new Label();
1605 | Image image = Image.FromFile($@"{appParts}\Icons\Question.png");
1606 | Bitmap scaledImage = new Bitmap((int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1607 | using (Graphics g = Graphics.FromImage(scaledImage))
1608 | {
1609 | g.InterpolationMode = InterpolationMode.HighQualityBicubic;
1610 | g.DrawImage(image, 0, 0, (int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1611 | }
1612 | buttonHelp.BackgroundImage = scaledImage;
1613 | buttonHelp.BackgroundImageLayout = ImageLayout.Stretch;
1614 | buttonHelp.Size = new Size((int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1615 | buttonHelp.FlatStyle = FlatStyle.Flat;
1616 | buttonHelp.Left = ClientSize.Width - (int)(30 * ScaleFactor);
1617 | buttonHelp.Top = (int)(4 * ScaleFactor);
1618 | buttonHelp.Click += ButtonHelp_Click;
1619 |
1620 | messageLabel.Padding = new Padding(0, 0, (int)(26 * ScaleFactor), 0);
1621 |
1622 | buttonOK = new Button();
1623 | buttonOK.Text = sOK;
1624 | buttonOK.DialogResult = DialogResult.OK;
1625 | buttonOK.Font = new Font("Segoe UI", 9);
1626 | buttonOK.Width = (int)(75 * ScaleFactor);
1627 | buttonOK.Height = (int)(26 * ScaleFactor);
1628 | buttonOK.Left = (ClientSize.Width - buttonOK.Width) / 2;
1629 | buttonOK.Top = ClientSize.Height - buttonOK.Height - (int)(10 * ScaleFactor);
1630 | if (Dark)
1631 | {
1632 | buttonOK.FlatStyle = FlatStyle.Flat;
1633 | buttonOK.FlatAppearance.BorderColor = SystemColors.Highlight;
1634 | buttonOK.FlatAppearance.BorderSize = 1;
1635 | buttonOK.BackColor = Color.FromArgb(60, 60, 60);
1636 | buttonOK.FlatAppearance.MouseOverBackColor = Color.Black;
1637 | DarkTitleBar(Handle);
1638 | BackColor = Color.FromArgb(32, 32, 32);
1639 | ForeColor = Color.White;
1640 | }
1641 | Controls.Add(buttonHelp);
1642 | Controls.Add(buttonOK);
1643 | Controls.Add(messageLabel);
1644 |
1645 | Point cursorPosition = Cursor.Position;
1646 | int dialogX = Cursor.Position.X - Width / 2;
1647 | int dialogY = Cursor.Position.Y - Height / 2 - (int)(50 * ScaleFactor);
1648 | Screen screen = Screen.FromPoint(cursorPosition);
1649 | int screenWidth = screen.WorkingArea.Width;
1650 | int screenHeight = screen.WorkingArea.Height;
1651 | int baseX = screen.Bounds.X;
1652 | int baseY = screen.Bounds.Y;
1653 | dialogX = Math.Max(baseX, Math.Min(baseX + screenWidth - Width, dialogX));
1654 | dialogY = Math.Max(baseY, Math.Min(baseY + screenHeight - Height, dialogY));
1655 | Location = new Point(dialogX, dialogY);
1656 | }
1657 | public static DialogResult Show(string message, string caption)
1658 | {
1659 | using (var customMessageBox = new CustomMessageBox(message, caption))
1660 | {
1661 | return customMessageBox.ShowDialog();
1662 | }
1663 | }
1664 |
1665 | }
1666 |
1667 | static void GetCheckboxChoice()
1668 | {
1669 | fLatCB = ReadString(myIniFile, "General", "AlternateCheckbox", "1") == "1";
1670 | }
1671 |
1672 | // Dialog for install/Remove and Yes/No
1673 | public class TwoChoiceBox : Form
1674 | {
1675 | private Label messageLabel;
1676 | private Label buttonHelp;
1677 | private Button buttonYes;
1678 | private Button buttonNo;
1679 |
1680 | public TwoChoiceBox(string message, string caption, string button1, string button2)
1681 | {
1682 | GetCheckboxChoice();
1683 | int b2Width = (int)(bwidth * ScaleFactor);
1684 | using (Graphics g = CreateGraphics())
1685 | {
1686 | SizeF size = g.MeasureString(button2, new Font("Segoe UI", 9));
1687 | b2Width = Math.Max((int)size.Width, b2Width);
1688 | }
1689 | message = $"\n{message}";
1690 |
1691 | Icon = new Icon(myIcon);
1692 | StartPosition = FormStartPosition.Manual;
1693 | Text = caption;
1694 | Width = (int)(300 * ScaleFactor);
1695 | int h = 150; if (AnyInstall) h = 174; if (Win11Install) h = 194;
1696 | Height = (int)(h * ScaleFactor);
1697 | FormBorderStyle = FormBorderStyle.FixedDialog;
1698 | MaximizeBox = false;
1699 | MinimizeBox = false;
1700 |
1701 | messageLabel = new Label();
1702 | messageLabel.Text = message;
1703 | messageLabel.Font = new Font("Segoe UI", 10);
1704 | messageLabel.TextAlign = ContentAlignment.TopCenter;
1705 | messageLabel.Dock = DockStyle.Fill;
1706 |
1707 | using (Graphics g = CreateGraphics())
1708 | {
1709 | SizeF size = g.MeasureString(message, new Font("Segoe UI", 10), Width);
1710 | Height = Math.Max(Height, (int)(size.Height + (int)(100 * ScaleFactor)));
1711 | }
1712 |
1713 | buttonHelp = new Label();
1714 | Image image = Image.FromFile($@"{appParts}\Icons\Question.png");
1715 | Bitmap scaledImage = new Bitmap((int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1716 | using (Graphics g = Graphics.FromImage(scaledImage))
1717 | {
1718 | g.InterpolationMode = InterpolationMode.HighQualityBicubic;
1719 | g.DrawImage(image, 0, 0, (int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1720 | }
1721 | buttonHelp.BackgroundImage = scaledImage;
1722 | buttonHelp.BackgroundImageLayout = ImageLayout.Stretch;
1723 | buttonHelp.Size = new Size((int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1724 | buttonHelp.FlatStyle = FlatStyle.Flat;
1725 | buttonHelp.Left = ClientSize.Width - (int)(30 * ScaleFactor);
1726 | buttonHelp.Top = (int)(4 * ScaleFactor);
1727 | buttonHelp.Click += ButtonHelp_Click;
1728 |
1729 | messageLabel.Padding = new Padding(0, 0, (int)(26 * ScaleFactor), 0);
1730 |
1731 | checkboxTask = new CheckBox();
1732 | checkboxTask.Font = new Font("Segoe UI", 10);
1733 | checkboxTask.Text = sInstallTask;
1734 | checkboxTask.Checked = true;
1735 | checkboxTask.AutoSize = true;
1736 | checkboxTask.Location = new Point((int)(12 * ScaleFactor), (int)(60 * ScaleFactor));
1737 | if (fLatCB) checkboxTask.FlatStyle = FlatStyle.Flat;
1738 |
1739 | checkboxCCM = new CheckBox();
1740 | checkboxCCM.Font = new Font("Segoe UI", 10);
1741 | checkboxCCM.Text = sCCM;
1742 | checkboxCCM.Checked = Win10ContextMenu;
1743 | checkboxCCM.AutoSize = true;
1744 | checkboxCCM.Location = new Point((int)(12 * ScaleFactor), (int)(86 * ScaleFactor));
1745 | if (fLatCB) checkboxCCM.FlatStyle = FlatStyle.Flat;
1746 |
1747 | buttonYes = new Button();
1748 | buttonYes.Text = button1;
1749 | buttonYes.Font = new Font("Segoe UI", 9);
1750 | buttonYes.MinimumSize = new Size((int)(bwidth * ScaleFactor), (int)(26 * ScaleFactor));
1751 | buttonYes.Left = (int)(10 * ScaleFactor);
1752 | buttonYes.Top = ClientSize.Height - buttonYes.Height - (int)(12 * ScaleFactor);
1753 | buttonYes.DialogResult = DialogResult.Yes;
1754 |
1755 | buttonNo = new Button();
1756 | buttonNo.Text = button2;
1757 | buttonNo.Font = new Font("Segoe UI", 9);
1758 | buttonNo.MinimumSize = new Size((int)(bwidth * ScaleFactor), (int)(26 * ScaleFactor));
1759 | buttonNo.Left = ClientSize.Width - b2Width - (int)(16 * ScaleFactor);
1760 | buttonNo.Top = ClientSize.Height - buttonNo.Height - (int)(12 * ScaleFactor);
1761 | buttonNo.DialogResult = DialogResult.No;
1762 |
1763 | if (Dark)
1764 | {
1765 | buttonYes.FlatStyle = FlatStyle.Flat;
1766 | buttonYes.FlatAppearance.BorderColor = SystemColors.Highlight;
1767 | buttonYes.FlatAppearance.BorderSize = 1;
1768 | buttonYes.BackColor = Color.FromArgb(60, 60, 60);
1769 | buttonYes.FlatAppearance.MouseOverBackColor = Color.Black;
1770 | buttonNo.FlatStyle = FlatStyle.Flat;
1771 | buttonNo.FlatAppearance.BorderColor = SystemColors.Highlight;
1772 | buttonNo.FlatAppearance.BorderSize = 1;
1773 | buttonNo.BackColor = Color.FromArgb(60, 60, 60);
1774 | buttonNo.FlatAppearance.MouseOverBackColor = Color.Black;
1775 | DarkTitleBar(Handle);
1776 | BackColor = Color.FromArgb(32, 32, 32);
1777 | ForeColor = Color.White;
1778 | }
1779 |
1780 | if (AnyInstall) Controls.Add(checkboxTask);
1781 | if (Win11Install) Controls.Add(checkboxCCM);
1782 | Controls.Add(buttonHelp);
1783 | Controls.Add(buttonYes);
1784 | Controls.Add(buttonNo);
1785 | Controls.Add(messageLabel);
1786 |
1787 | Point cursorPosition = Cursor.Position;
1788 | int dialogX = Cursor.Position.X - Width / 2;
1789 | int x = 50; if (Win11Install) x = 40;
1790 | int dialogY = Cursor.Position.Y - Height / 2 - (int)(x * ScaleFactor);
1791 | Screen screen = Screen.FromPoint(cursorPosition);
1792 | int screenWidth = screen.WorkingArea.Width;
1793 | int screenHeight = screen.WorkingArea.Height;
1794 | int baseX = screen.Bounds.X;
1795 | int baseY = screen.Bounds.Y;
1796 | dialogX = Math.Max(baseX, Math.Min(baseX + screenWidth - Width, dialogX));
1797 | dialogY = Math.Max(baseY, Math.Min(baseY + screenHeight - Height, dialogY));
1798 | Location = new Point(dialogX, dialogY);
1799 | }
1800 |
1801 | public static DialogResult Show(string message, string caption, string button1, string button2)
1802 | {
1803 | using (var TwoChoiceBox = new TwoChoiceBox(message, caption, button1, button2))
1804 | {
1805 | return TwoChoiceBox.ShowDialog();
1806 | }
1807 | }
1808 |
1809 | }
1810 |
1811 | static void ButtonHelp_Click(object sender, EventArgs e)
1812 | {
1813 | Process.Start("https://lesferch.github.io/RightClickTools#" + helpPage);
1814 | }
1815 |
1816 | // Dialog for Add-Del Path
1817 | public class AddDelPathDialog : Form
1818 | {
1819 | private Label messageLabel;
1820 | private Label buttonHelp;
1821 | private Button buttonOK;
1822 |
1823 | public AddDelPathDialog(string message, string caption)
1824 | {
1825 | GetCheckboxChoice();
1826 | message = $"\n\n\n\n{message}";
1827 |
1828 | Icon = new Icon(myIcon);
1829 | StartPosition = FormStartPosition.Manual;
1830 | FormBorderStyle = FormBorderStyle.FixedDialog;
1831 | Text = caption;
1832 | Width = (int)(300 * ScaleFactor);
1833 | Height = (int)(150 * ScaleFactor);
1834 | MaximizeBox = false;
1835 | MinimizeBox = false;
1836 |
1837 | messageLabel = new Label();
1838 | messageLabel.Text = message;
1839 | messageLabel.Font = new Font("Segoe UI", 10);
1840 | messageLabel.TextAlign = ContentAlignment.TopCenter;
1841 | messageLabel.Dock = DockStyle.Fill;
1842 |
1843 | using (Graphics g = CreateGraphics())
1844 | {
1845 | SizeF size = g.MeasureString(message, new Font("Segoe UI", 10), Width);
1846 | Height = Math.Max(Height, (int)(size.Height + (int)(100 * ScaleFactor)));
1847 | }
1848 |
1849 | buttonHelp = new Label();
1850 | Image image = Image.FromFile($@"{appParts}\Icons\Question.png");
1851 | Bitmap scaledImage = new Bitmap((int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1852 | using (Graphics g = Graphics.FromImage(scaledImage))
1853 | {
1854 | g.InterpolationMode = InterpolationMode.HighQualityBicubic;
1855 | g.DrawImage(image, 0, 0, (int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1856 | }
1857 | buttonHelp.BackgroundImage = scaledImage;
1858 | buttonHelp.BackgroundImageLayout = ImageLayout.Stretch;
1859 | buttonHelp.Size = new Size((int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1860 | buttonHelp.FlatStyle = FlatStyle.Flat;
1861 | buttonHelp.Left = ClientSize.Width - (int)(30 * ScaleFactor);
1862 | buttonHelp.Top = (int)(4 * ScaleFactor);
1863 | buttonHelp.Click += ButtonHelp_Click;
1864 | helpPage = "add-or-remove-folder-in-path-variable";
1865 |
1866 | buttonOK = new Button();
1867 | buttonOK.Text = sOK;
1868 | buttonOK.DialogResult = DialogResult.OK;
1869 | buttonOK.Font = new Font("Segoe UI", 9);
1870 | buttonOK.Width = (int)(75 * ScaleFactor);
1871 | buttonOK.Height = (int)(26 * ScaleFactor);
1872 | buttonOK.Left = (ClientSize.Width - buttonOK.Width) / 2;
1873 | buttonOK.Top = ClientSize.Height - buttonOK.Height - (int)(10 * ScaleFactor);
1874 |
1875 | userPathCheckbox = new CheckBox();
1876 | userPathCheckbox.Font = new Font("Segoe UI", 10);
1877 | userPathCheckbox.Text = sUserPath;
1878 | userPathCheckbox.Checked = InUserPath;
1879 | userPathCheckbox.AutoSize = true;
1880 | userPathCheckbox.Location = new Point((int)(8 * ScaleFactor), (int)(16 * ScaleFactor));
1881 | if (fLatCB) userPathCheckbox.FlatStyle = FlatStyle.Flat;
1882 |
1883 | systemPathCheckbox = new CheckBox();
1884 | systemPathCheckbox.Font = new Font("Segoe UI", 10);
1885 | systemPathCheckbox.Text = sSystemPath;
1886 | systemPathCheckbox.Checked = InSystemPath;
1887 | systemPathCheckbox.AutoSize = true;
1888 | systemPathCheckbox.Location = new Point((int)(8 * ScaleFactor), (int)(40 * ScaleFactor));
1889 | if (fLatCB) systemPathCheckbox.FlatStyle = FlatStyle.Flat;
1890 |
1891 | if (Dark)
1892 | {
1893 | buttonOK.FlatStyle = FlatStyle.Flat;
1894 | buttonOK.FlatAppearance.BorderColor = SystemColors.Highlight;
1895 | buttonOK.FlatAppearance.BorderSize = 1;
1896 | buttonOK.BackColor = Color.FromArgb(60, 60, 60);
1897 | buttonOK.FlatAppearance.MouseOverBackColor = Color.Black;
1898 | DarkTitleBar(Handle);
1899 | BackColor = Color.FromArgb(32, 32, 32);
1900 | ForeColor = Color.White;
1901 | }
1902 |
1903 | Controls.Add(buttonHelp);
1904 | Controls.Add(userPathCheckbox);
1905 | Controls.Add(systemPathCheckbox);
1906 | Controls.Add(buttonOK);
1907 | Controls.Add(messageLabel);
1908 |
1909 | Point cursorPosition = Cursor.Position;
1910 | int dialogX = Cursor.Position.X - Width / 2;
1911 | int dialogY = Cursor.Position.Y - Height / 2 - (int)(50 * ScaleFactor);
1912 | Screen screen = Screen.FromPoint(cursorPosition);
1913 | int screenWidth = screen.WorkingArea.Width;
1914 | int screenHeight = screen.WorkingArea.Height;
1915 | int baseX = screen.Bounds.X;
1916 | int baseY = screen.Bounds.Y;
1917 | dialogX = Math.Max(baseX, Math.Min(baseX + screenWidth - Width, dialogX));
1918 | dialogY = Math.Max(baseY, Math.Min(baseY + screenHeight - Height, dialogY));
1919 | Location = new Point(dialogX, dialogY);
1920 | }
1921 |
1922 | public static DialogResult Show(string message, string caption)
1923 | {
1924 | using (var AddDelPathDialog = new AddDelPathDialog(message, caption))
1925 | {
1926 | return AddDelPathDialog.ShowDialog();
1927 | }
1928 | }
1929 | }
1930 |
1931 | // Dialog for Shell Refresh
1932 | public class ShellRefreshDialog : Form
1933 | {
1934 | private Label messageLabel;
1935 | private Label buttonHelp;
1936 | private Button buttonOK;
1937 |
1938 | public ShellRefreshDialog(string message, string caption)
1939 | {
1940 | GetCheckboxChoice();
1941 | message = $"\n\n\n\n{message}";
1942 |
1943 | Icon = new Icon(myIcon);
1944 | StartPosition = FormStartPosition.Manual;
1945 | FormBorderStyle = FormBorderStyle.FixedDialog;
1946 | Text = caption;
1947 | Width = (int)(300 * ScaleFactor);
1948 | Height = (int)(150 * ScaleFactor);
1949 | MaximizeBox = false;
1950 | MinimizeBox = false;
1951 |
1952 | messageLabel = new Label();
1953 | messageLabel.Text = message;
1954 | messageLabel.Font = new Font("Segoe UI", 10);
1955 | messageLabel.TextAlign = ContentAlignment.TopCenter;
1956 | messageLabel.Dock = DockStyle.Fill;
1957 |
1958 | using (Graphics g = CreateGraphics())
1959 | {
1960 | SizeF size = g.MeasureString(message, new Font("Segoe UI", 10), Width);
1961 | Height = Math.Max(Height, (int)(size.Height + (int)(100 * ScaleFactor)));
1962 | }
1963 |
1964 | buttonHelp = new Label();
1965 | Image image1 = Image.FromFile($@"{appParts}\Icons\Question.png");
1966 | Bitmap scaledImage1 = new Bitmap((int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1967 | using (Graphics g = Graphics.FromImage(scaledImage1))
1968 | {
1969 | g.InterpolationMode = InterpolationMode.HighQualityBicubic;
1970 | g.DrawImage(image1, 0, 0, (int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1971 | }
1972 | Image image2 = Image.FromFile($@"{appParts}\Icons\Question.png");
1973 | Bitmap scaledImage2 = new Bitmap((int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1974 | using (Graphics g = Graphics.FromImage(scaledImage2))
1975 | {
1976 | g.InterpolationMode = InterpolationMode.HighQualityBicubic;
1977 | g.DrawImage(image2, 0, 0, (int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1978 | }
1979 | buttonHelp.BackgroundImage = scaledImage1;
1980 | buttonHelp.BackgroundImageLayout = ImageLayout.Stretch;
1981 | buttonHelp.Size = new Size((int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
1982 | buttonHelp.FlatStyle = FlatStyle.Flat;
1983 | buttonHelp.Left = ClientSize.Width - (int)(30 * ScaleFactor);
1984 | buttonHelp.Top = (int)(4 * ScaleFactor);
1985 | buttonHelp.Click += ButtonHelp_Click;
1986 | helpPage = "refresh-shell";
1987 |
1988 | buttonOK = new Button();
1989 | buttonOK.Text = sOK;
1990 | buttonOK.DialogResult = DialogResult.OK;
1991 | buttonOK.Font = new Font("Segoe UI", 9);
1992 | buttonOK.Width = (int)(75 * ScaleFactor);
1993 | buttonOK.Height = (int)(26 * ScaleFactor);
1994 | buttonOK.Left = (ClientSize.Width - buttonOK.Width) / 2;
1995 | buttonOK.Top = ClientSize.Height - buttonOK.Height - (int)(10 * ScaleFactor);
1996 |
1997 | ShellRefreshCheckbox = new CheckBox();
1998 | ShellRefreshCheckbox.Font = new Font("Segoe UI", 10);
1999 | ShellRefreshCheckbox.Text = sShellRefresh;
2000 | ShellRefreshCheckbox.AutoSize = true;
2001 | ShellRefreshCheckbox.Location = new Point((int)(8 * ScaleFactor), (int)(16 * ScaleFactor));
2002 | ShellRefreshCheckbox.Checked = true;
2003 | ShellRefreshCheckbox.CheckedChanged += new EventHandler(CB1);
2004 | if (fLatCB) ShellRefreshCheckbox.FlatStyle = FlatStyle.Flat;
2005 |
2006 | iconCacheCheckbox = new CheckBox();
2007 | iconCacheCheckbox.Font = new Font("Segoe UI", 10);
2008 | iconCacheCheckbox.Text = sResetIcons;
2009 | iconCacheCheckbox.AutoSize = true;
2010 | iconCacheCheckbox.Location = new Point((int)(8 * ScaleFactor), (int)(40 * ScaleFactor));
2011 | iconCacheCheckbox.CheckedChanged += new EventHandler(CB2);
2012 | if (fLatCB) iconCacheCheckbox.FlatStyle = FlatStyle.Flat;
2013 |
2014 | thumbCacheCheckbox = new CheckBox();
2015 | thumbCacheCheckbox.Font = new Font("Segoe UI", 10);
2016 | thumbCacheCheckbox.Text = sResetThumbs;
2017 | thumbCacheCheckbox.AutoSize = true;
2018 | thumbCacheCheckbox.Location = new Point((int)(8 * ScaleFactor), (int)(64 * ScaleFactor));
2019 | thumbCacheCheckbox.CheckedChanged += new EventHandler(CB2);
2020 | if (fLatCB) thumbCacheCheckbox.FlatStyle = FlatStyle.Flat;
2021 |
2022 | if (Dark)
2023 | {
2024 | buttonOK.FlatStyle = FlatStyle.Flat;
2025 | buttonOK.FlatAppearance.BorderColor = SystemColors.Highlight;
2026 | buttonOK.FlatAppearance.BorderSize = 1;
2027 | buttonOK.BackColor = Color.FromArgb(60, 60, 60);
2028 | buttonOK.FlatAppearance.MouseOverBackColor = Color.Black;
2029 | DarkTitleBar(Handle);
2030 | BackColor = Color.FromArgb(32, 32, 32);
2031 | ForeColor = Color.White;
2032 | }
2033 |
2034 | Controls.Add(buttonHelp);
2035 | Controls.Add(ShellRefreshCheckbox);
2036 | Controls.Add(iconCacheCheckbox);
2037 | Controls.Add(thumbCacheCheckbox);
2038 | Controls.Add(buttonOK);
2039 | Controls.Add(messageLabel);
2040 |
2041 | Point cursorPosition = Cursor.Position;
2042 | int dialogX = Cursor.Position.X - Width / 2;
2043 | int dialogY = Cursor.Position.Y - Height / 2 - (int)(50 * ScaleFactor);
2044 | Screen screen = Screen.FromPoint(cursorPosition);
2045 | int screenWidth = screen.WorkingArea.Width;
2046 | int screenHeight = screen.WorkingArea.Height;
2047 | int baseX = screen.Bounds.X;
2048 | int baseY = screen.Bounds.Y;
2049 | dialogX = Math.Max(baseX, Math.Min(baseX + screenWidth - Width, dialogX));
2050 | dialogY = Math.Max(baseY, Math.Min(baseY + screenHeight - Height, dialogY));
2051 | Location = new Point(dialogX, dialogY);
2052 | }
2053 |
2054 | private void CB1(object sender, EventArgs e)
2055 | {
2056 | if (ShellRefreshCheckbox.Checked)
2057 | {
2058 | iconCacheCheckbox.Checked = false;
2059 | thumbCacheCheckbox.Checked = false;
2060 | }
2061 | if (!iconCacheCheckbox.Checked && !thumbCacheCheckbox.Checked)
2062 | {
2063 | ShellRefreshCheckbox.Checked = true;
2064 | }
2065 |
2066 | }
2067 | private void CB2(object sender, EventArgs e)
2068 | {
2069 | if (iconCacheCheckbox.Checked || thumbCacheCheckbox.Checked)
2070 | {
2071 | ShellRefreshCheckbox.Checked = false;
2072 | }
2073 | else
2074 | {
2075 | ShellRefreshCheckbox.Checked = true;
2076 | }
2077 | }
2078 |
2079 |
2080 | public static DialogResult Show(string message, string caption)
2081 | {
2082 | using (var ShellRefreshDialog = new ShellRefreshDialog(message, caption))
2083 | {
2084 | return ShellRefreshDialog.ShowDialog();
2085 | }
2086 | }
2087 | }
2088 |
2089 | // Dialog for Clear History
2090 | public class ClearHistoryDialog : Form
2091 | {
2092 | private Label messageLabel;
2093 | private Button buttonOK;
2094 | private Label buttonHelp;
2095 |
2096 | public ClearHistoryDialog(string message, string caption)
2097 | {
2098 | GetCheckboxChoice();
2099 | message = $"\n\n\n\n\n\n\n{message}?";
2100 |
2101 | Icon = new Icon(myIcon);
2102 | StartPosition = FormStartPosition.Manual;
2103 | FormBorderStyle = FormBorderStyle.FixedDialog;
2104 | Text = caption;
2105 | Width = (int)(300 * ScaleFactor);
2106 | Height = (int)(150 * ScaleFactor);
2107 | MaximizeBox = false;
2108 | MinimizeBox = false;
2109 |
2110 | messageLabel = new Label();
2111 | messageLabel.Text = message;
2112 | messageLabel.Font = new Font("Segoe UI", 10);
2113 | messageLabel.TextAlign = ContentAlignment.TopCenter;
2114 | messageLabel.Dock = DockStyle.Fill;
2115 |
2116 | using (Graphics g = CreateGraphics())
2117 | {
2118 | SizeF size = g.MeasureString(message, new Font("Segoe UI", 10), Width);
2119 | Height = Math.Max(Height, (int)(size.Height + (int)(100 * ScaleFactor)));
2120 | }
2121 |
2122 | buttonHelp = new Label();
2123 | Image image = Image.FromFile($@"{appParts}\Icons\Question.png");
2124 | Bitmap scaledImage = new Bitmap((int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
2125 | using (Graphics g = Graphics.FromImage(scaledImage))
2126 | {
2127 | g.InterpolationMode = InterpolationMode.HighQualityBicubic;
2128 | g.DrawImage(image, 0, 0, (int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
2129 | }
2130 | buttonHelp.BackgroundImage = scaledImage;
2131 | buttonHelp.BackgroundImageLayout = ImageLayout.Stretch;
2132 | buttonHelp.Size = new Size((int)(26 * ScaleFactor), (int)(26 * ScaleFactor));
2133 | buttonHelp.FlatStyle = FlatStyle.Flat;
2134 | buttonHelp.Left = ClientSize.Width - (int)(30 * ScaleFactor);
2135 | buttonHelp.Top = (int)(4 * ScaleFactor);
2136 | buttonHelp.Click += ButtonHelp_Click;
2137 | helpPage = "clear-history";
2138 |
2139 | buttonOK = new Button();
2140 | buttonOK.Text = sOK;
2141 | buttonOK.DialogResult = DialogResult.OK;
2142 | buttonOK.Font = new Font("Segoe UI", 9);
2143 | buttonOK.Width = (int)(75 * ScaleFactor);
2144 | buttonOK.Height = (int)(26 * ScaleFactor);
2145 | buttonOK.Left = (ClientSize.Width - buttonOK.Width) / 2;
2146 | buttonOK.Top = ClientSize.Height - buttonOK.Height - (int)(10 * ScaleFactor);
2147 | if (Dark)
2148 | {
2149 | buttonOK.FlatStyle = FlatStyle.Flat;
2150 | buttonOK.FlatAppearance.BorderColor = SystemColors.Highlight;
2151 | buttonOK.FlatAppearance.BorderSize = 1;
2152 | buttonOK.BackColor = Color.FromArgb(60, 60, 60);
2153 | buttonOK.FlatAppearance.MouseOverBackColor = Color.Black;
2154 | DarkTitleBar(Handle);
2155 | BackColor = Color.FromArgb(32, 32, 32);
2156 | ForeColor = Color.White;
2157 | }
2158 |
2159 | RecentItemsCheckbox = new CheckBox();
2160 | RecentItemsCheckbox.Font = new Font("Segoe UI", 10);
2161 | RecentItemsCheckbox.Text = sRecent;
2162 | RecentItemsCheckbox.Checked = false;
2163 | RecentItemsCheckbox.AutoSize = true;
2164 | RecentItemsCheckbox.Location = new Point((int)(8 * ScaleFactor), (int)(16 * ScaleFactor));
2165 | if (fLatCB) RecentItemsCheckbox.FlatStyle = FlatStyle.Flat;
2166 |
2167 | AutoSuggestCheckbox = new CheckBox();
2168 | AutoSuggestCheckbox.Font = new Font("Segoe UI", 10);
2169 | AutoSuggestCheckbox.Text = sAutoSuggest;
2170 | AutoSuggestCheckbox.Checked = false;
2171 | AutoSuggestCheckbox.AutoSize = true;
2172 | AutoSuggestCheckbox.Location = new Point((int)(8 * ScaleFactor), (int)(40 * ScaleFactor));
2173 | if (fLatCB) AutoSuggestCheckbox.FlatStyle = FlatStyle.Flat;
2174 |
2175 | TempFilesCheckbox = new CheckBox();
2176 | TempFilesCheckbox.Font = new Font("Segoe UI", 10);
2177 | TempFilesCheckbox.Text = sTemp;
2178 | TempFilesCheckbox.Checked = false;
2179 | TempFilesCheckbox.AutoSize = true;
2180 | TempFilesCheckbox.Location = new Point((int)(8 * ScaleFactor), (int)(64 * ScaleFactor));
2181 | if (fLatCB) TempFilesCheckbox.FlatStyle = FlatStyle.Flat;
2182 |
2183 | DefenderCheckbox = new CheckBox();
2184 | DefenderCheckbox.Font = new Font("Segoe UI", 10);
2185 | DefenderCheckbox.Text = sDefender;
2186 | DefenderCheckbox.Checked = false;
2187 | DefenderCheckbox.AutoSize = true;
2188 | DefenderCheckbox.Location = new Point((int)(8 * ScaleFactor), (int)(88 * ScaleFactor));
2189 | if (fLatCB) DefenderCheckbox.FlatStyle = FlatStyle.Flat;
2190 |
2191 | Controls.Add(buttonHelp);
2192 | Controls.Add(RecentItemsCheckbox);
2193 | Controls.Add(AutoSuggestCheckbox);
2194 | Controls.Add(TempFilesCheckbox);
2195 | Controls.Add(DefenderCheckbox);
2196 | Controls.Add(buttonOK);
2197 | Controls.Add(messageLabel);
2198 |
2199 | Point cursorPosition = Cursor.Position;
2200 | int dialogX = Cursor.Position.X - Width / 2;
2201 | int dialogY = Cursor.Position.Y - Height / 2 - (int)(50 * ScaleFactor);
2202 | Screen screen = Screen.FromPoint(cursorPosition);
2203 | int screenWidth = screen.WorkingArea.Width;
2204 | int screenHeight = screen.WorkingArea.Height;
2205 | int baseX = screen.Bounds.X;
2206 | int baseY = screen.Bounds.Y;
2207 | dialogX = Math.Max(baseX, Math.Min(baseX + screenWidth - Width, dialogX));
2208 | dialogY = Math.Max(baseY, Math.Min(baseY + screenHeight - Height, dialogY));
2209 | Location = new Point(dialogX, dialogY);
2210 | }
2211 |
2212 | public static DialogResult Show(string message, string caption)
2213 | {
2214 | using (var ClearHistoryDialog = new ClearHistoryDialog(message, caption))
2215 | {
2216 | return ClearHistoryDialog.ShowDialog();
2217 | }
2218 | }
2219 | }
2220 | }
2221 |
2222 |
2223 | //Credit for the following TrustedInstaller code: https://github.com/rara64/GetTrustedInstaller
2224 | class TrustedInstaller
2225 | {
2226 | [DllImport("kernel32.dll")]
2227 | [return: MarshalAs(UnmanagedType.Bool)]
2228 | static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
2229 |
2230 | [DllImport("kernel32.dll", SetLastError = true)]
2231 | public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
2232 |
2233 | [DllImport("kernel32.dll", SetLastError = true)]
2234 | public static extern UInt32 WaitForSingleObject(IntPtr handle, UInt32 milliseconds);
2235 |
2236 | [DllImport("kernel32.dll", SetLastError = true)]
2237 | [return: MarshalAs(UnmanagedType.Bool)]
2238 | private static extern bool UpdateProcThreadAttribute(IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue, IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
2239 |
2240 | [DllImport("kernel32.dll", SetLastError = true)]
2241 | [return: MarshalAs(UnmanagedType.Bool)]
2242 | private static extern bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
2243 |
2244 | [DllImport("kernel32.dll", SetLastError = true)]
2245 | static extern bool SetHandleInformation(IntPtr hObject, HANDLE_FLAGS dwMask, HANDLE_FLAGS dwFlags);
2246 |
2247 | [DllImport("kernel32.dll", SetLastError = true)]
2248 | static extern bool CloseHandle(IntPtr hObject);
2249 |
2250 | [DllImport("kernel32.dll", SetLastError = true)]
2251 | [return: MarshalAs(UnmanagedType.Bool)]
2252 | static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, ref IntPtr lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions);
2253 |
2254 | public static void Run(int parentProcessId, string binaryPath)
2255 | {
2256 | const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000;
2257 |
2258 | const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
2259 | const uint CREATE_NEW_CONSOLE = 0x00000010;
2260 |
2261 | var pInfo = new PROCESS_INFORMATION();
2262 | var siEx = new STARTUPINFOEX();
2263 |
2264 | IntPtr lpValueProc = IntPtr.Zero;
2265 | IntPtr hSourceProcessHandle = IntPtr.Zero;
2266 | var lpSize = IntPtr.Zero;
2267 |
2268 | InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize);
2269 | siEx.lpAttributeList = Marshal.AllocHGlobal(lpSize);
2270 | InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, ref lpSize);
2271 |
2272 | IntPtr parentHandle = OpenProcess(ProcessAccessFlags.CreateProcess | ProcessAccessFlags.DuplicateHandle, false, parentProcessId);
2273 |
2274 | lpValueProc = Marshal.AllocHGlobal(IntPtr.Size);
2275 | Marshal.WriteIntPtr(lpValueProc, parentHandle);
2276 |
2277 | UpdateProcThreadAttribute(siEx.lpAttributeList, 0, (IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, lpValueProc, (IntPtr)IntPtr.Size, IntPtr.Zero, IntPtr.Zero);
2278 |
2279 | var ps = new SECURITY_ATTRIBUTES();
2280 | var ts = new SECURITY_ATTRIBUTES();
2281 | ps.nLength = Marshal.SizeOf(ps);
2282 | ts.nLength = Marshal.SizeOf(ts);
2283 |
2284 | // lpCommandLine was used instead of lpApplicationName to allow for arguments to be passed
2285 | bool ret = CreateProcess(null, binaryPath, ref ps, ref ts, true, EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE, IntPtr.Zero, null, ref siEx, out pInfo);
2286 |
2287 | String stringPid = pInfo.dwProcessId.ToString();
2288 |
2289 | }
2290 |
2291 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
2292 | struct STARTUPINFOEX
2293 | {
2294 | public STARTUPINFO StartupInfo;
2295 | public IntPtr lpAttributeList;
2296 | }
2297 |
2298 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
2299 | struct STARTUPINFO
2300 | {
2301 | public Int32 cb;
2302 | public string lpReserved;
2303 | public string lpDesktop;
2304 | public string lpTitle;
2305 | public Int32 dwX;
2306 | public Int32 dwY;
2307 | public Int32 dwXSize;
2308 | public Int32 dwYSize;
2309 | public Int32 dwXCountChars;
2310 | public Int32 dwYCountChars;
2311 | public Int32 dwFillAttribute;
2312 | public Int32 dwFlags;
2313 | public Int16 wShowWindow;
2314 | public Int16 cbReserved2;
2315 | public IntPtr lpReserved2;
2316 | public IntPtr hStdInput;
2317 | public IntPtr hStdOutput;
2318 | public IntPtr hStdError;
2319 | }
2320 |
2321 | [StructLayout(LayoutKind.Sequential)]
2322 | internal struct PROCESS_INFORMATION
2323 | {
2324 | public IntPtr hProcess;
2325 | public IntPtr hThread;
2326 | public int dwProcessId;
2327 | public int dwThreadId;
2328 | }
2329 |
2330 | [StructLayout(LayoutKind.Sequential)]
2331 | public struct SECURITY_ATTRIBUTES
2332 | {
2333 | public int nLength;
2334 | public IntPtr lpSecurityDescriptor;
2335 | [MarshalAs(UnmanagedType.Bool)]
2336 | public bool bInheritHandle;
2337 | }
2338 |
2339 | [Flags]
2340 | public enum ProcessAccessFlags : uint
2341 | {
2342 | All = 0x001F0FFF,
2343 | Terminate = 0x00000001,
2344 | CreateThread = 0x00000002,
2345 | VirtualMemoryOperation = 0x00000008,
2346 | VirtualMemoryRead = 0x00000010,
2347 | VirtualMemoryWrite = 0x00000020,
2348 | DuplicateHandle = 0x00000040,
2349 | CreateProcess = 0x000000080,
2350 | SetQuota = 0x00000100,
2351 | SetInformation = 0x00000200,
2352 | QueryInformation = 0x00000400,
2353 | QueryLimitedInformation = 0x00001000,
2354 | Synchronize = 0x00100000
2355 | }
2356 |
2357 | [Flags]
2358 | enum HANDLE_FLAGS : uint
2359 | {
2360 | None = 0,
2361 | INHERIT = 1,
2362 | PROTECT_FROM_CLOSE = 2
2363 | }
2364 | }
2365 |
2366 | }
2367 |
--------------------------------------------------------------------------------
/Properties/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/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("RightClickTools")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("RightClickTools")]
13 | [assembly: AssemblyCopyright("lesferch@gmail.com")]
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("a2c1801a-cb6b-45b7-8dc5-22b0e2e3abf9")]
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.2.0.0")]
36 | [assembly: AssemblyFileVersion("1.2.0.0")]
37 |
--------------------------------------------------------------------------------
/RightClickTools.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {A2C1801A-CB6B-45B7-8DC5-22B0E2E3ABF9}
8 | WinExe
9 | RightClickTools
10 | RightClickTools
11 | v4.8
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | false
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 | false
36 |
37 |
38 | RightClickTools.ico
39 |
40 |
41 | app.manifest
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | {EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}
72 | 1
73 | 1
74 | 0
75 | tlbimp
76 | False
77 | True
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/RightClickTools.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/RightClickTools.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LesFerch/RightClickTools/7ebc7dd162a23d13ad896bd887a19d1b049a36ae/RightClickTools.ico
--------------------------------------------------------------------------------
/RightClickTools.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.8.34511.84
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RightClickTools", "RightClickTools.csproj", "{A2C1801A-CB6B-45B7-8DC5-22B0E2E3ABF9}"
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 | {A2C1801A-CB6B-45B7-8DC5-22B0E2E3ABF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {A2C1801A-CB6B-45B7-8DC5-22B0E2E3ABF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {A2C1801A-CB6B-45B7-8DC5-22B0E2E3ABF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {A2C1801A-CB6B-45B7-8DC5-22B0E2E3ABF9}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {EA115A65-21FC-4DB9-A603-C297BEDE73BA}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
54 |
55 |
56 |
57 | true
58 | true
59 |
60 |
61 |
62 |
63 |
77 |
78 |
79 |
--------------------------------------------------------------------------------