Skip to content

Commit

Permalink
Fix the MenuAnimation login account issue.
Browse files Browse the repository at this point in the history
  • Loading branch information
dima-iholkin committed Dec 16, 2023
1 parent 938aa3f commit 77c4486
Show file tree
Hide file tree
Showing 9 changed files with 369 additions and 162 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1015,7 +1015,7 @@
"RemovePreviousVersions" = "11:TRUE"
"DetectNewerInstalledVersion" = "11:TRUE"
"InstallAllUsers" = "11:FALSE"
"ProductVersion" = "8:2.1.0"
"ProductVersion" = "8:2.1.1"
"Manufacturer" = "8:Dima Iholkin"
"ARPHELPTELEPHONE" = "8:"
"ARPHELPLINK" = "8:https://github.com/dima-iholkin/SwitchApps"
Expand Down
133 changes: 133 additions & 0 deletions src/Installer/SwitchApps_Library/MenuAnimation/ImpersonationUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using Serilog.Core;

namespace SwitchApps_Library.MenuAnimation
{
internal static class ImpersonationUtils
{
// Const:

private const int TOKEN_QUERY = 0x0008;
private const int TOKEN_DUPLICATE = 0x0002;
private const int TOKEN_ASSIGN_PRIMARY = 0x0001;
private const int TOKEN_IMPERSONATE = 0x0004;
private const int TOKEN_QUERY_SOURCE = 0x0010;
private const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
private const int TOKEN_ADJUST_GROUPS = 0x0040;
private const int TOKEN_ADJUST_DEFAULT = 0x0080;
private const int TOKEN_ADJUST_SESSIONID = 0x0100;
private const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;

private const int TOKEN_ALL_ACCESS =
STANDARD_RIGHTS_REQUIRED |
TOKEN_ASSIGN_PRIMARY |
TOKEN_DUPLICATE |
TOKEN_IMPERSONATE |
TOKEN_QUERY |
TOKEN_QUERY_SOURCE |
TOKEN_ADJUST_PRIVILEGES |
TOKEN_ADJUST_GROUPS |
TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID;

[StructLayout(LayoutKind.Sequential)]
private struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}

private enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}

private enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}

// External calls:

[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool DuplicateTokenEx(
IntPtr hExistingToken, int dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes,
int ImpersonationLevel, int dwTokenType, ref IntPtr phNewToken
);

[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hObject);

// Public methods:

public static WindowsImpersonationContext ImpersonateLoginUser(Logger logger)
{
try
{
Process process = Process.GetProcessesByName("explorer").FirstOrDefault();

IntPtr userToken = ImpersonationUtils.GetPrimaryToken(process);

if (userToken == IntPtr.Zero)
{
logger.Warning("UserToken == Zero. Failed at impersonating the login user.");
}

WindowsIdentity identity = new WindowsIdentity(userToken);

return identity.Impersonate();
}
catch (Exception ex)
{
logger.Error(ex, "Failed at impersonating the login user.");

return WindowsIdentity.GetCurrent().Impersonate();
}
}

// Private methods:

internal static IntPtr GetPrimaryToken(Process process)
{
IntPtr token = IntPtr.Zero;
IntPtr primaryToken = IntPtr.Zero;

bool openProcessTokenSuccess = OpenProcessToken(process.Handle, TOKEN_DUPLICATE, ref token);

if (openProcessTokenSuccess == false)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "OpenProcessToken failed");
}

SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.nLength = Marshal.SizeOf(sa);

bool duplicateTokenSuccess = DuplicateTokenEx(
token, TOKEN_ALL_ACCESS, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
(int)TOKEN_TYPE.TokenPrimary, ref primaryToken
);

if (duplicateTokenSuccess == false)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "DuplicateTokenEx failed");
}

CloseHandle(token);

return primaryToken;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Security.Principal;
using Microsoft.Win32;
using Serilog.Core;
using SwitchApps.Library.Registry.Exceptions;
Expand All @@ -8,52 +9,104 @@ namespace SwitchApps_Library.MenuAnimation
{
internal class MenuAnimationManager
{
// Const:

private const string BackupEntryName = "MenuAnimation";
private const bool DefaultValue = true;

// Init:

private readonly Logger _logger;
private readonly MenuAnimationUtility _menuAnimationUtility;

public MenuAnimationManager(Logger logger)
{
this._logger = logger;
this._menuAnimationUtility = new MenuAnimationUtility(logger);
}

private readonly Logger _logger;
private readonly MenuAnimationUtility _menuAnimationUtility;

// Public methods:

public void BackupSetting()
{
this.BackupSettingPrivate();

this._logger.Information("The MenuAnimation setting backup finished.");
}

public void ModifySetting()
{
using (WindowsImpersonationContext context = ImpersonationUtils.ImpersonateLoginUser(this._logger))
{
this._logger.Information(
"Using impersonation WindowsIdentity: {WindowsIdentityImpersonationUsername}.",
WindowsIdentity.GetCurrent().Name
);

this.ModifySettingPrivate();

this._logger.Information("The MenuAnimation setting modification finished.");
}

this._logger.Information(
"Using install WindowsIdentity: {WindowsIdentityImpersonationUsername}.",
WindowsIdentity.GetCurrent().Name
);
}

public void RestoreSetting()
{
using (WindowsImpersonationContext context = ImpersonationUtils.ImpersonateLoginUser(this._logger))
{
this._logger.Information(
"Using impersonation WindowsIdentity: {WindowsIdentityImpersonationUsername}.",
WindowsIdentity.GetCurrent().Name
);

this.RestoreSettingPrivate();

this._logger.Information("The MenuAnimation setting restore finished.");
}

this._logger.Information(
"Using install WindowsIdentity: {WindowsIdentityImpersonationUsername}.",
WindowsIdentity.GetCurrent().Name
);
}

// Private methods:

private void BackupSettingPrivate()
{
bool? menuAnimationValue = this._menuAnimationUtility.GetMenuAnimation();

if (menuAnimationValue == null)
{
this._logger.Warning("Backup entry {BackupEntryName} not set.", MenuAnimationManager.BackupEntryName);
this._logger.Warning(
"Backup entry {BackupEntryName} was not set.", MenuAnimationManager.BackupEntryName
);

return;
}

BackupSubkey.Instance.SetValue(
MenuAnimationManager.BackupEntryName,
(bool)menuAnimationValue ? 1 : 0,
RegistryValueKind.DWord
MenuAnimationManager.BackupEntryName, (bool)menuAnimationValue ? 1 : 0, RegistryValueKind.DWord
);

this._logger.Information("Backup entry {BackupEntryName} value {Value} written into the backup registry.",
MenuAnimationManager.BackupEntryName,
(bool)menuAnimationValue ? 1 : 0
this._logger.Information(
"Backup entry {BackupEntryName} value {Value} written into the backup registry.",
MenuAnimationManager.BackupEntryName, (bool)menuAnimationValue ? 1 : 0
);
}

public void ModifySetting()
private void ModifySettingPrivate()
{
this._menuAnimationUtility.SetMenuAnimation(false);

this._logger.Information("MenuAnimation UI modified to {MenuAnimationUI}.", false);
}

public void RestoreSetting()
private void RestoreSettingPrivate()
{
// Get backup value:

Expand Down Expand Up @@ -101,7 +154,9 @@ public void RestoreSetting()
{
this._menuAnimationUtility.SetMenuAnimation(MenuAnimationManager.DefaultValue);

this._logger.Information("MenuAnimation UI setting set to {MenuAnimationUI}.", MenuAnimationManager.DefaultValue);
this._logger.Information(
"MenuAnimation UI setting set to {MenuAnimationUI}.", MenuAnimationManager.DefaultValue
);
}
else if (backupValue.HasValue && currentValue != backupValue.Value)
{
Expand All @@ -112,10 +167,7 @@ public void RestoreSetting()

// Delete the backup entry:

BackupSubkey.Instance.DeleteValue(
MenuAnimationManager.BackupEntryName,
throwOnMissingValue: false
);
BackupSubkey.Instance.DeleteValue(MenuAnimationManager.BackupEntryName, throwOnMissingValue: false);

this._logger.Information(
"Backup entry {BackupEntryName} was deleted from the backup registry.",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
using Serilog.Core;

// Thanks to this honorable man we have this working https://gist.github.com/skepticMike/caa8a43db86f6d027e400ad9196e100a
// And thanks to this forum too https://www.tenforums.com/tutorials/6377-change-visual-effects-settings-windows-10-a-6.html
// Thanks to this honorable man https://gist.github.com/skepticMike/caa8a43db86f6d027e400ad9196e100a
// And thanks to this forum https://www.tenforums.com/tutorials/6377-change-visual-effects-settings-windows-10-a-6.html

namespace SwitchApps_Library.MenuAnimation
{
internal class MenuAnimationUtility
{
// Init:

private readonly Logger _logger;

public MenuAnimationUtility(Logger logger)
{
this._logger = logger;
}

private readonly Logger _logger;

// External function signatures:
// External calls:

// Used to set the new Menu Animation value.
[DllImport("user32.dll", SetLastError = true)]
Expand All @@ -42,11 +41,15 @@ public MenuAnimationUtility(Logger logger)

if (exitValue == false)
{
this._logger.Error("Win32 function call failed with error code {Win32ErrorCode}.", Marshal.GetLastWin32Error());
this._logger.Error(
"Win32 function call failed with error code {Win32ErrorCode}.", Marshal.GetLastWin32Error()
);

return null;
}

this._logger.Information("Menu animation is {MenuAnimationIsEnabled}.", menuAnimationIsEnabled);
this._logger.Information("Menu animation was {MenuAnimationIsEnabled}.", menuAnimationIsEnabled);

return menuAnimationIsEnabled;
}

Expand All @@ -62,12 +65,16 @@ public void SetMenuAnimation(bool newValue)

if (exitValue == false)
{
this._logger.Error("Win32 function call failed with error code {Win32ErrorCode}.", Marshal.GetLastWin32Error());
}
else
{
this._logger.Information("Menu animation set to {MenuAnimationNewValue}.", newValue);
this._logger.Error(
"Win32 function call failed with error code {Win32ErrorCode}.", Marshal.GetLastWin32Error()
);

return;
}

this._logger.Information("Menu animation set to {MenuAnimationNewValue}.", newValue);

return;
}
}
}
Loading

0 comments on commit 77c4486

Please sign in to comment.