如何在C#中启动32位进程而不在64位机器上使用shell execute?

如何在C#中启动32位进程而不在64位机器上使用shell execute?,c#,32bit-64bit,startprocessinfo,start-process,C#,32bit 64bit,Startprocessinfo,Start Process,我在64位计算机上有一个ASP.NET web应用程序,它需要运行一个旧的32位报告应用程序 当我使用UseShellExecute=false运行程序时,程序将使用退出代码退出: -1073741502 我不能使用Shell Execute,因为我必须以其他用户的身份运行该进程。然而,当Shell Execute为true时,进程将正常运行(尽管我必须更改ASP.NET正在执行的用户) 如何使用C#启动此32位程序而不使用shell execute 以下是我现在掌握的代码: var pxs =

我在64位计算机上有一个ASP.NET web应用程序,它需要运行一个旧的32位报告应用程序

当我使用
UseShellExecute=false运行程序时,程序将使用退出代码退出:

-1073741502

我不能使用Shell Execute,因为我必须以其他用户的身份运行该进程。然而,当Shell Execute为true时,进程将正常运行(尽管我必须更改ASP.NET正在执行的用户)

如何使用C#启动此32位程序而不使用shell execute

以下是我现在掌握的代码:

var pxs = new ProcessStartInfo
{
    Arguments = arguments,
    CreateNoWindow = true,
    Domain = ConfigurationManager.AppSettings["reportUserDomain"],
    UserName = ConfigurationManager.AppSettings["reportUserName"],
    Password = GetSecureString(ConfigurationManager.AppSettings["reportUserPassword"]),
    LoadUserProfile = true,
    FileName = ConfigurationManager.AppSettings["reportRuntime"],
    UseShellExecute = false             

};

var px = new Process
{
    StartInfo = pxs
};

px.Start();
px.WaitForExit();

如果使用windows本机的“LogonUser”方法包围代码,包括
UseShellExecute=true
,会怎么样?我已经在一些项目中成功地使用它来做类似的事情

Fresh Click Media为此撰写了一篇文章,并编写了一个模拟类示例:-->

但为了完整起见,以下是我的版本:

public class Impersonator : IDisposable
{
    private WindowsImpersonationContext _impersonatedUser = null;
    private IntPtr _userHandle;

    // constructor for a local account. username and password are arguments.
    public Impersonator(string username, string passwd)
    {
        _userHandle = new IntPtr(0);

        string user = username;
        string userDomain = "."; // The domain for a local user is by default "."
        string password = passwd;

        bool returnValue = LogonUser(user, userDomain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref _userHandle);

        if (!returnValue)
            throw new ApplicationException("Could not impersonate user");

        WindowsIdentity newId = new WindowsIdentity(_userHandle);
        _impersonatedUser = newId.Impersonate();
    }

    // constructor where username, password and domain are passed as parameters
    public Impersonator(string username, string passwd, string domain)
    {
        _userHandle = new IntPtr(0);

        string user = username;
        string userDomain = domain;
        string password = passwd;

        bool returnValue = LogonUser(user, userDomain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref _userHandle);

        if (!returnValue)
            throw new ApplicationException("Could not impersonate user");

        WindowsIdentity newId = new WindowsIdentity(_userHandle);
        _impersonatedUser = newId.Impersonate();
    }

    public void Dispose()
    {
        if (_impersonatedUser != null)
        {
            _impersonatedUser.Undo();
            CloseHandle(_userHandle);
        }
    }

    public const int LOGON32_LOGON_INTERACTIVE = 2;
    public const int LOGON32_LOGON_SERVICE = 3;
    public const int LOGON32_PROVIDER_DEFAULT = 0;

    [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
    public static extern bool LogonUser(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public extern static bool CloseHandle(IntPtr handle);
}
在您的案例中使用它将是:

var domain = ConfigurationManager.AppSettings["reportUserDomain"];
var username = ConfigurationManager.AppSettings["reportUserName"];
var password = ConfigurationManager.AppSettings["reportUserPassword"];

using (Impersonator impersonator = new Impersonator(username, password, domain))
{
    var pxs = new ProcessStartInfo
    {
        Arguments = arguments,
        CreateNoWindow = true,
        LoadUserProfile = true,
        FileName = ConfigurationManager.AppSettings["reportRuntime"],
        UseShellExecute = true
    };

    var px = new Process
    {
        StartInfo = pxs
    };

    px.Start();
    px.WaitForExit();
}

您强调这是一个32位进程。这是因为它适用于64位进程吗?从64位应用程序启动进程并不确定子应用程序是否为64位。子应用程序是一个单独的进程,其32/64位的确定方式与其他程序相同。未显式编译为64或32的Net应用程序将是操作系统的本机应用程序。64位操作系统将以64位运行,但32位操作系统将以32位运行。如果ASP.NET以LocalSystem帐户运行,则对
CreateProcessWithLogonW
(在场景后使用)的函数调用将失败:@Gabe-在回答第一个问题时,我没有尝试在此上下文中启动64位进程(主要是因为我没有必要这么做),尽管我在过去成功地启动了ShellExecute=false的进程。因此,我不知道它是否适用于64位进程,但我认为它可以。是否有完整源代码示例的最终解决方案可以解决此问题?OP需要
UseShellExecute=false
@Gabe:如果进程作为结果以不同的用户启动,则不需要lt模拟。@Ryan-很高兴它有帮助!Happy Codeing;-)如果我重定向Outputo:System.InvalidOperationException:Process对象必须将UseShellExecute属性设置为false才能重定向IO流,则会出现此错误。
var domain = ConfigurationManager.AppSettings["reportUserDomain"];
var username = ConfigurationManager.AppSettings["reportUserName"];
var password = ConfigurationManager.AppSettings["reportUserPassword"];

using (Impersonator impersonator = new Impersonator(username, password, domain))
{
    var pxs = new ProcessStartInfo
    {
        Arguments = arguments,
        CreateNoWindow = true,
        LoadUserProfile = true,
        FileName = ConfigurationManager.AppSettings["reportRuntime"],
        UseShellExecute = true
    };

    var px = new Process
    {
        StartInfo = pxs
    };

    px.Start();
    px.WaitForExit();
}