¿Cómo iniciar un proceso de 32 bits en C# sin usar Shell Execut en una máquina de 64 bits?
-
25-10-2019 - |
Pregunta
Tengo una aplicación web ASP .NET en una máquina de 64 bits que necesita ejecutar una aplicación heredada de informes de 32 bits.
Cuando ejecuto el programa con UseShellExecute = false
, el programa sale con el código de salida:
-1073741502
No puedo usar Shell Execute porque tengo que ejecutar el proceso como un usuario diferente. Sin embargo, cuando Shell Ejecute es verdadero, el proceso se ejecutará bien (aunque tengo que cambiar el usuario que ASP .NET se está ejecutando).
¿Cómo puedo iniciar este programa de 32 bits usando C# sin usar Shell Execute?
Aquí está el código que tengo ahora mismo:
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();
Solución
¿Qué pasa si rodeaste tu código, incluido UseShellExecute = true
, con el método de "Logonuser" nativo de Windows? He usado esto con éxito en algunos proyectos para hacer algo. 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 hizo un artículo sobre esto y escribió una clase de suplantación de la muestra: -> http://www.freshclickmedia.com/blog/2008/11/programmatic-impersonation-in-c/
Pero para completar, aquí está mi versión:
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);
}
Usarlo en su caso sería:
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();
}