You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 09:10:39