调用RegenerateUserEnvironment刷新环境变量时触发访问违例错误求助
问题:调用
RegenerateUserEnvironment刷新环境变量触发访问违例错误 我尝试调用RegenerateUserEnvironment方法在不重启进程的情况下刷新环境变量,但运行时触发了**访问违例(Access violation)**错误。我认为进程更新自身内存不应引发此类错误,但不确定原因。
已尝试以下方案:
- 传入当前进程的实际令牌,无效;
- 复制当前进程的令牌并赋予所有可能权限,无效;
- 以管理员身份运行,排查是否与
SeDebugPrivilege等权限相关,仍无效。
请问有什么解决思路吗?
问题代码
using System; using System.Runtime.InteropServices; using System.Security.Principal; using Microsoft.Win32; namespace EnvVarControl { internal static partial class Program { #region Pinvoke public const uint STANDARD_RIGHTS_READ = 0x00020000; public const uint STANDARD_RIGHTS_REQUIRED = 0x000F0000; public const uint TOKEN_ADJUST_DEFAULT = 0x0080; public const uint TOKEN_ADJUST_GROUPS = 0x0040; public const uint TOKEN_ADJUST_PRIVILEGES = 0x0020; public const uint TOKEN_ADJUST_SESSIONID = 0x0100; public const uint 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; public const uint TOKEN_ASSIGN_PRIMARY = 0x0001; public const uint TOKEN_DUPLICATE = 0x0002; public const uint TOKEN_IMPERSONATE = 0x0004; public const uint TOKEN_QUERY = 0x0008; public const uint TOKEN_QUERY_SOURCE = 0x0010; public const uint TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY; public enum SECURITY_IMPERSONATION_LEVEL { SecurityAnonymous, SecurityIdentification, SecurityImpersonation, SecurityDelegation } public enum TOKEN_TYPE { TokenPrimary = 1, TokenImpersonation = 2 } [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES { public int Length; public IntPtr lpSecurityDescriptor; public bool bInheritHandle; } [DllImport("advapi32.dll", SetLastError = true, EntryPoint = "DuplicateTokenEx")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, TOKEN_TYPE TokenType, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, ref IntPtr DuplicateTokenHandle); [LibraryImport("shell32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static partial bool RegenerateUserEnvironment(IntPtr hToken, [MarshalAs(UnmanagedType.Bool)] bool bSet); #endregion Pinvoke public static void Main() { // Subscribe to the UserPreferenceChanged event SystemEvents.UserPreferenceChanged += OnUserPreferenceChanged; Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } private static void CheckPathBeforeAndAfterRegenerateUserEnvironment() { // Get the value of the PATH environment variable before calling RegenerateUserEnvironment var pathBefore = Environment.GetEnvironmentVariable("PATH"); Console.WriteLine($"BEFORE: {pathBefore}\n"); RefreshEnvironmentVariables(); // Get the value of the PATH environment variable after calling RegenerateUserEnvironment var pathAfter = Environment.GetEnvironmentVariable("PATH"); Console.WriteLine($"AFTER: {pathAfter}\n"); // Compare the two values of the PATH environment variable if (pathBefore != pathAfter) { Console.WriteLine("Warning: The value of the PATH environment variable has changed!"); } else { Console.WriteLine("No change."); } } private static void OnUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) { // Check if the environment variables have changed if (e.Category == UserPreferenceCategory.General) { // Check the value of the PATH environment variable before and after calling RegenerateUserEnvironment CheckPathBeforeAndAfterRegenerateUserEnvironment(); } } private static void RefreshEnvironmentVariables() { // Open the process token and duplicate var token = WindowsIdentity.GetCurrent().AccessToken.DangerousGetHandle(); var duplicatededToken = DuplicateToken(token); // Call the RegenerateUserEnvironment function to update the environment variables if (!RegenerateUserEnvironment(duplicatededToken, true)) { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } } private static nint DuplicateToken(nint token) { var sa = new SECURITY_ATTRIBUTES { bInheritHandle = false }; sa.Length = Marshal.SizeOf(sa); sa.lpSecurityDescriptor = 0; const TOKEN_TYPE TokenType = TOKEN_TYPE.TokenPrimary; const SECURITY_IMPERSONATION_LEVEL SecurityImpersonation = SECURITY_IMPERSONATION_LEVEL.SecurityIdentification; var DupedToken = new IntPtr(0); if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, ref sa, TokenType, SecurityImpersonation, ref DupedToken)) { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } return DupedToken; } } }
错误信息
Exception thrown at ... (shell32.dll) in EnvVarControl.exe: ...: Access violation writing location ...
编辑补充:修正后的代码
using System; using System.Runtime.InteropServices; using Microsoft.Win32; namespace EnvVarControl { internal static partial class Program { #region Pinvoke [LibraryImport("shell32.dll", SetLastError = true)] [UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })] [return: MarshalAs(UnmanagedType.Bool)] public static partial bool RegenerateUserEnvironment(out IntPtr pPrevEnv, [MarshalAs(UnmanagedType.Bool)] bool bSetCurrentEnv); #endregion Pinvoke public static void Main() { // Subscribe to the UserPreferenceChanged event SystemEvents.UserPreferenceChanged += OnUserPreferenceChanged; Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } private static void CheckPathBeforeAndAfterRegenerateUserEnvironment() { // Get the value of the PATH environment variable before calling RegenerateUserEnvironment var pathBefore = Environment.GetEnvironmentVariable("PATH"); Console.WriteLine($"BEFORE: {pathBefore}\n"); RefreshEnvironmentVariables(); // Get the value of the PATH environment variable after calling RegenerateUserEnvironment var pathAfter = Environment.GetEnvironmentVariable("PATH"); Console.WriteLine($"AFTER: {pathAfter}\n"); // Compare the two values of the PATH environment variable if (pathBefore != pathAfter) { Console.WriteLine("Warning: The value of the PATH environment variable has changed!"); } else { Console.WriteLine("No change."); } } private static void OnUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) { // Check if the environment variables have changed if (e.Category == UserPreferenceCategory.General) { // Check the value of the PATH environment variable before and after calling RegenerateUserEnvironment CheckPathBeforeAndAfterRegenerateUserEnvironment(); } } private static void RefreshEnvironmentVariables() { // Call the RegenerateUserEnvironment function to update the environment variables if (!RegenerateUserEnvironment(out _, true)) { throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } } } }
内容的提问来源于stack exchange,提问作者Zafer Balkan
相关产品推荐
相关产品推荐

