Windows 2004更新后,无法以其他用户身份运行EXCEL.EXE

问题描述

我需要以不同于当前用户的用户身份运行EXCEL.EXE;过去我这样做没有任何问题,但是在将系统更新为Windows 10 Pro 2004版(19041.508)之后,此方法不再起作用。

我正在使用以下课程(感谢Impersonate user in Windows Service):

public class CreateProcess
{

    #region Constants

    const UInt32 INFINITE = 0xFFFFFFFF;
    const UInt32 WAIT_FAILED = 0xFFFFFFFF;

    #endregion


    #region ENUMS

    [Flags]
    public enum LogonType
    {
        LOGON32_LOGON_INTERACTIVE = 2,LOGON32_LOGON_NETWORK = 3,LOGON32_LOGON_BATCH = 4,LOGON32_LOGON_SERVICE = 5,LOGON32_LOGON_UNLOCK = 7,LOGON32_LOGON_NETWORK_CLEARTEXT = 8,LOGON32_LOGON_NEW_CREDENTIALS = 9
    }


    [Flags]
    public enum LogonProvider
    {
        LOGON32_PROVIDER_DEFAULT = 0,LOGON32_PROVIDER_WINNT35,LOGON32_PROVIDER_WINNT40,LOGON32_PROVIDER_WINNT50
    }

    #endregion


    #region Structs

    [StructLayout(LayoutKind.Sequential)]
    public struct STARTUPINFO
    {
        public Int32 cb;
        public String lpReserved;
        public String lpDesktop;
        public String lpTitle;
        public Int32 dwX;
        public Int32 dwY;
        public Int32 dwXSize;
        public Int32 dwYSize;
        public Int32 dwXCountChars;
        public Int32 dwYCountChars;
        public Int32 dwFillAttribute;
        public Int32 dwFlags;
        public Int16 wShowWindow;
        public Int16 cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }


    [StructLayout(LayoutKind.Sequential)]
    public struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public Int32 dwProcessId;
        public Int32 dwThreadId;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public int nLength;
        public unsafe byte* lpSecurityDescriptor;
        public int bInheritHandle;
    }

    public enum TOKEN_TYPE
    {
        TokenPrimary = 1,TokenImpersonation
    }

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

    #endregion


    #region FUNCTIONS (P/INVOKE)

    [DllImport("advapi32.dll",CharSet = CharSet.Auto,SetLastError = true)]
    static extern bool RevertToSelf();

    [DllImport("advapi32.dll",SetLastError = true)]
    static extern int DuplicateToken(IntPtr hToken,int impersonationLevel,ref IntPtr hNewToken);


    [DllImport("advapi32.dll",CharSet = CharSet.Unicode,SetLastError = true)]
    public static extern Boolean LogonUser
    (
        String UserName,String Domain,String Password,LogonType dwLogonType,LogonProvider dwLogonProvider,out IntPtr phToken
    );


    [DllImport("advapi32.dll",SetLastError = true)]
    public static extern Boolean CreateProcessAsUser
    (
        IntPtr hToken,String lpApplicationName,String lpCommandLine,IntPtr lpProcessAttributes,IntPtr lpThreadAttributes,Boolean bInheritHandles,Int32 dwCreationFlags,IntPtr lpEnvironment,String lpCurrentDirectory,ref STARTUPINFO lpStartupInfo,out PROCESS_INFORMATION lpProcessInformation
    );





    [DllImport("kernel32.dll",SetLastError = true)]
    public static extern UInt32 WaitForSingleObject
    (
        IntPtr hHandle,UInt32 dwMilliseconds
    );

    [DllImport("kernel32",SetLastError = true)]
    public static extern Boolean CloseHandle(IntPtr handle);

    #endregion

    #region Functions

    public static int LaunchCommand(string command,string domain,string account,string password)
    {
        int ProcessId = -1;
        PROCESS_INFORMATION processInfo = new PROCESS_INFORMATION();
        STARTUPINFO startInfo = new STARTUPINFO();
        Boolean bResult = false;

        UInt32 uiResultWait = WAIT_FAILED;

        var token = ValidateParametersAndGetFirstLoginToken(domain,account,password);

        var duplicateToken = IntPtr.Zero;
        try
        {

            startInfo.cb = Marshal.SizeOf(startInfo);
            startInfo.lpDesktop = "winsta0\\default";

            bResult = CreateProcessAsUser(
                token,null,command,IntPtr.Zero,false,ref startInfo,out processInfo
            );

            if (!bResult) { throw new Exception("CreateProcessAsUser error #" + Marshal.GetLastWin32Error()); }

            // Wait for process to end
            uiResultWait = WaitForSingleObject(processInfo.hProcess,INFINITE);

            ProcessId = processInfo.dwProcessId;

            if (uiResultWait == WAIT_FAILED) { throw new Exception("WaitForSingleObject error #" + Marshal.GetLastWin32Error()); }

        }
        finally
        {
            if (token != IntPtr.Zero)
                CloseHandle(token);
            if (duplicateToken != IntPtr.Zero)
                CloseHandle(duplicateToken);
            CloseHandle(processInfo.hProcess);
            CloseHandle(processInfo.hThread);
        }

        return ProcessId;
    }


    private static IntPtr ValidateParametersAndGetFirstLoginToken(string domain,string username,string password)
    {


        if (!RevertToSelf())
        {
            Console.WriteLine("RevertToSelf call to remove any prior impersonations failed");
            throw new Exception("RevertToSelf call to remove any prior impersonations failed");
        }

        IntPtr token;

        var result = LogonUser(username,domain,password,LogonType.LOGON32_LOGON_INTERACTIVE,LogonProvider.LOGON32_PROVIDER_DEFAULT,out token);
        if (!result)
        {
            var errorCode = Marshal.GetLastWin32Error();

            Console.WriteLine(string.Format("Could not impersonate the elevated user.  LogonUser: {2}\\{1} returned error code: {0}.",errorCode,username,domain));
            throw new Exception("Logon for user " + username + " failed.");
        }
        return token;
    }

    #endregion

}

通过这种方式:

var otherUserInSystemName = "probanduela";
                var otherUserInSystemPassword = "chapuza";

                var regularWin32AppPath = @"C:\Program Files (x86)\WinMerge\WinMergeU.exe";
                var officeWin32AppPath = @"C:\Program Files (x86)\Microsoft Office\root\Office16\EXCEL.EXE";
    var ProcessId = CreateProcess.LaunchCommand(officeWin32AppPath,Environment.MachineName,otherUserInSystemName,otherUserInSystemPassword);

我总是遇到错误:

1312: A specified logon session does not exist. It may already have been terminated.

也尝试过CreateProcessWithLogonW,结果相同。

如果我尝试通过PowerShell或“ runas”运行它,也会发生类似的问题。

此方法在升级到Windows 10 2004版本之前有效,我已经在其他计算机上复制了此方法。

有什么问题?我该如何实现自己想做的事?

-编辑-

刚刚发现使用Excel v2002 build 12527.21104可以正常工作;但是使用Excel v2008内部版本13127.20408失败。

Windows 10 v2004 + Office 2019 v2008的组合显然是导致此问题的原因。

-Edit2-

如果我复制EXCEL.EXE并给它起另一个名字,例如“ EXCEL_COPY.EXE”,它就会起作用:S

解决方法

我向微软报告了这个问题,在提高了几个级别后,他们已经解决并修复了。已于 Windows 10 Build 19042.844

修复

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...