如何在 C# 中启动 32 位进程而不在 64 位机器上使用 shell 执行? [英] How to start a 32-bit process in C# without using shell execute on 64-bit machine?

查看:34
本文介绍了如何在 C# 中启动 32 位进程而不在 64 位机器上使用 shell 执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an ASP .NET web application on a 64-bit machine that needs to run a legacy 32-bit reporting application.

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

When I run the program with UseShellExecute = false, the program exits with exit code:

-1073741502

我无法使用 Shell Execute,因为我必须以不同的用户身份运行该进程.然而,当 Shell Execute 为 true 时,该进程将运行良好(尽管我必须更改 ASP .NET 在其下执行的用户).

I can't use Shell Execute because I have to run the process as a different user. Yet, when Shell Execute is true, the process will run fine (although I have to change the user that ASP .NET is executing under).

如何在不使用 shell 执行的情况下使用 C# 启动这个 32 位程序?

How can I start this 32-bit program using C# without use shell execute?

这是我现在拥有的代码:

Here's the code I have right now:

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 会怎样?我已经在一些项目中成功地使用了它来做类似的.

What if you surrounded your code, including UseShellExecute = true, with the windows native "LogonUser" method? I've used this successfully in a few projects to do something similar.

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

Fresh Click Media 写了一篇关于这个的文章并写了一个模拟类示例:--> http://www.freshclickmedia.com/blog/2008/11/programmatic-impersonation-in-c/

Fresh Click Media did an article about this and wrote a sample Impersonate class: --> http://www.freshclickmedia.com/blog/2008/11/programmatic-impersonation-in-c/

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

But for completeness, here's my version of it:

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);
}

在您的情况下使用它是:

Using it in your case would be:

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();
}

这篇关于如何在 C# 中启动 32 位进程而不在 64 位机器上使用 shell 执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆