2011-04-28 40 views
2

我在需要運行傳統32位報告應用程序的64位機器上安裝了ASP .NET Web應用程序。如何在C#中啓動32位進程而無需在64位機器上執行shell?

當我與UseShellExecute = false運行該程序,該程序退出,退出代碼:

-1073741502

我不能使用殼牌執行,因爲我要運行該過程作爲一個不同的用戶。但是,當Shell Execute爲true時,該進程將正常運行(儘管我必須更改ASP .NET正在執行的用戶)。

如何在不使用shell執行的情況下使用C#啓動此32位程序?

下面的代碼我現在所擁有的:

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(); 
+0

你強調這是一個32位的過程。那是因爲它對64位進程工作正常嗎? – Gabe 2011-04-28 02:01:33

+1

從64位應用程序啓動進程不會確定子應用程序將是64位。子應用程序是一個獨立的進程,它的32/64位的確定方式與其他程序的確定方式相同。未明確編譯爲64或32的.Net應用程序將是操作系統的本地應用程序。 64位操作系統將以64位運行,但32位操作系統將以32位運行。 – 2011-04-28 02:45:13

+1

如果ASP.NET以LocalSystem帳戶運行,則調用'CreateProcessWithLogonW'函數(使用behing場景)將失敗:http://msdn.microsoft.com/en-us/library/ms682431(VS.85) .aspx – Gabe 2011-04-28 02:47:39

回答

3

如果你包圍你的代碼,包括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 

新鮮點擊媒體做了關於此問題的文章,並寫了一個樣品模擬類: - >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(); 
} 
+0

OP需要'UseShellExecute = false'。 – Gabe 2011-04-28 02:48:37

+0

@Gabe:如果由於模擬而導致進程作爲其他用戶啓動,則不適用。 – 2011-04-28 03:34:41

+0

該解決方案效果很好。 – Ryan 2011-04-28 13:27:33

相關問題