Как запустить 32-разрядный процесс в C # без использования shell execute на 64-разрядной машине?

#c# #32bit-64bit #startprocessinfo #start-process

#c# #32bit-64bit #startprocessinfo #запустить процесс

Вопрос:

У меня есть ASP.СЕТЕВОЕ веб-приложение на 64-разрядной машине, на котором необходимо запустить устаревшее 32-разрядное приложение для создания отчетов.

Когда я запускаю программу с помощью UseShellExecute = false , программа завершается с кодом выхода:

-1073741502

Я не могу использовать Shell Execute, потому что я должен запустить процесс от имени другого пользователя. Тем не менее, когда значение Shell Execute равно true, процесс будет выполняться нормально (хотя мне придется сменить пользователя, под которым выполняется ASP .NET).

Как я могу запустить эту 32-разрядную программу с помощью C # без использования 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();
  

Комментарии:

1. Вы подчеркиваете, что это 32-разрядный процесс. Это потому, что он отлично работает для 64-разрядных процессов?

2. Запуск процесса из 64-разрядного приложения не определяет, что дочернее приложение будет 64-разрядным. Дочернее приложение является отдельным процессом, и его разрядность 32/64 определяется таким же образом, как и для любой другой программы. Приложения .Net, которые явно не скомпилированы как 64 или 32, будут собственными для ОС. 64-разрядная ОС будет запускать их как 64-разрядные, но 32-разрядная ОС будет запускаться как 32-разрядная.

3. Если ASP.NET выполняется от имени учетной записи LocalSystem, вызов функции CreateProcessWithLogonW (используемой в сценах) завершится ошибкой: msdn.microsoft.com/en-us/library/ms682431 (VS.85).aspx

4. @Gabe — В ответ на ваш первый вопрос, я не пытался запускать 64-разрядный процесс в этом контексте (в основном потому, что у меня не было необходимости), хотя в прошлом я успешно запускал процессы с ShellExecute = false. Итак, я не знаю, будет ли это нормально работать для 64-разрядного процесса, но я бы предположил, что будет.

5. есть какое-нибудь окончательное решение с полным примером исходного кода, работающее над этим?

Ответ №1:

Что, если бы вы окружили свой код, в том числе UseShellExecute = true , собственным методом Windows «LogonUser»? Я успешно использовал это в нескольких проектах, чтобы сделать что-то подобное.

 [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 /

Но для полноты картины, вот моя версия этого:

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

Комментарии:

1. Требуется операционная система UseShellExecute = false .

2. @Gabe: Нет, если процесс запущен от имени другого пользователя в результате олицетворения.

3. Я получаю эту ошибку, если перенаправляю Outputo: System. Исключение InvalidOperationException: для объекта Process свойству UseShellExecute должно быть присвоено значение false, чтобы перенаправлять потоки ввода-вывода.