Why is this process crashing as soon as it is launched?
I ended up opening a case with Microsoft, and this is the information I was given:
Process.Start internally calls CreateProcessWithLogonW(CPLW) when credentials are specified. CreateProcessWithLogonW cannot be called from a Windows Service Environment (such as an IIS WCF service). It can only be called from an Interactive Process (an application launched by a user who logged on via CTRL-ALT-DELETE).
(that's verbatim from the support engineer; emphasis mine)
They recommended I use CreateProcessAsUser
instead. They gave me some useful sample code, which I then adapted to my needs, and now everything works great!
The end result was this:
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
public class ProcessHelper
{
static ProcessHelper()
{
UserToken = IntPtr.Zero;
}
private static IntPtr UserToken { get; set; }
public int StartProcess(ProcessStartInfo processStartInfo)
{
LogInOtherUser(processStartInfo);
Native.STARTUPINFO startUpInfo = new Native.STARTUPINFO();
startUpInfo.cb = Marshal.SizeOf(startUpInfo);
startUpInfo.lpDesktop = string.Empty;
Native.PROCESS_INFORMATION processInfo = new Native.PROCESS_INFORMATION();
bool processStarted = Native.CreateProcessAsUser(UserToken, processStartInfo.FileName, processStartInfo.Arguments,
IntPtr.Zero, IntPtr.Zero, true, 0, IntPtr.Zero, null,
ref startUpInfo, out processInfo);
if (!processStarted)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
uint processId = processInfo.dwProcessId;
Native.CloseHandle(processInfo.hProcess);
Native.CloseHandle(processInfo.hThread);
return (int) processId;
}
private static void LogInOtherUser(ProcessStartInfo processStartInfo)
{
if (UserToken == IntPtr.Zero)
{
IntPtr tempUserToken = IntPtr.Zero;
string password = SecureStringToString(processStartInfo.Password);
bool loginResult = Native.LogonUser(processStartInfo.UserName, processStartInfo.Domain, password,
Native.LOGON32_LOGON_BATCH, Native.LOGON32_PROVIDER_DEFAULT,
ref tempUserToken);
if (loginResult)
{
UserToken = tempUserToken;
}
else
{
Native.CloseHandle(tempUserToken);
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
private static String SecureStringToString(SecureString value)
{
IntPtr stringPointer = Marshal.SecureStringToBSTR(value);
try
{
return Marshal.PtrToStringBSTR(stringPointer);
}
finally
{
Marshal.FreeBSTR(stringPointer);
}
}
public static void ReleaseUserToken()
{
Native.CloseHandle(UserToken);
}
}
internal class Native
{
internal const int LOGON32_LOGON_INTERACTIVE = 2;
internal const int LOGON32_LOGON_BATCH = 4;
internal const int LOGON32_PROVIDER_DEFAULT = 0;
[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
internal struct STARTUPINFO
{
public int cb;
[MarshalAs(UnmanagedType.LPStr)]
public string lpReserved;
[MarshalAs(UnmanagedType.LPStr)]
public string lpDesktop;
[MarshalAs(UnmanagedType.LPStr)]
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public System.UInt32 nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[DllImport("advapi32.dll", EntryPoint = "LogonUserW", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
internal extern static bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUserA", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
internal extern static bool CreateProcessAsUser(IntPtr hToken, [MarshalAs(UnmanagedType.LPStr)] string lpApplicationName,
[MarshalAs(UnmanagedType.LPStr)] string lpCommandLine, IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes, bool bInheritHandle, uint dwCreationFlags, IntPtr lpEnvironment,
[MarshalAs(UnmanagedType.LPStr)] string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
internal extern static bool CloseHandle(IntPtr handle);
}
There are some pre-requisites to making this code work. The user running it must have the user right to 'Replace a process level token' and 'Adjust memory quotas for a process', while the 'other user' must have the user right to 'Log on as a batch job'. These settings can be found under the Local Security Policy (or possibly through Group Policy). If you change them, a restart will be required.
UserToken
is a property that can be closed via ReleaseUserToken
because we will call StartProcess
repeatedly and we were told not to log the other user on again and again.
That SecureStringToString()
method was taken from this question. Using SecureString
was not part of Microsoft's recommendation; I did it this way so as not to break compatibility with some other code.
Process crashes when started from systemd
Ok guys, the actual issue with my process-A was that it had some sort of dependency with another process-C during startup and took some inputs from another process-C which usually would be garbage during startup. This garbage input was reason for crash when launched through Systemd during startup. Later on manual start the input values used to be valid, thats why no crash.
Thanks for the help anyways.
Also points mentioned by @Mark Stosberg are useful and valid for debugging systemd related bugs.
Let know in case of any questions.
see ya.
App crashing when launching from AppStore or TestFlight but working fine elseways
I found the solution of my problem.
As expected it was coming from func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
Inside the function I had let userInfo = launchOpts[UIApplicationLaunchOptionsRemoteNotificationKey] as! NSDictionary
.
I changed it to let userInfo = launchOpts[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary
and then checked if userInfo != nil
to make all the code running userInfo
into the bracket.
If it helps anyone or if anyone is struggling with this issue, check all yours !
and swap these to ?
if needed (on didFinishLaunchingWithOptions
) since launching from TestFlight/AppStore seems to have different options than from installed application (just a guess, not pro enough to claim it).
Debugging a C# executable that crashes on launch
Crashing at launch might be due to a missing dependency. Run fuslogvw.exe
before starting your application and see whether any of the binding operations fail.
If that doesn't help, it is generally a good practice to have diagnostic logging in place. You can use a dedicated logging library, e.g. log4net, or at least you should be using the simplest form of logging via System.Diagnostics.Trace
. You can listen to the trace messages by either configuring a trace listener in the app.config or using third-party tools like a debugger or DebugView from Sysinternals.
If you actually want to attach a debugger you can insert a breakpoint programmatically:
System.Diagnostics.Debugger.Break();
I haven't checked how this works with a remote debugger, but as a last resort you can have your application sleep long enough to allow you to attach a debugger:
System.Threading.Thread.Sleep(30000);
Application crashing on startup using Process.Start
Your code is not how one starts a process:
Console.WriteLine("Running");
Process pr = new Process();
pr.StartInfo.FileName = "Notepad.exe";
pr.StartInfo.Arguments = "test.dat";
pr.Start();
while (pr.HasExited == false)
if ((DateTime.Now.Second % 5) == 0)
{
// Show a tick every five seconds.
Console.Write(".");
System.Threading.Thread.Sleep(1000);
}
I go into further detail in my blog post How to Launch an External Application in C#:
Related Topics
Mapping Database Views to Ef 5.0 Code First W/Migrations
..The Underlying Connection Was Closed: an Unexpected Error Occurred on a Receive
Automatically Rename a File If It Already Exists in Windows Way
How to Create a Sequence of Integers in C#
Thread Safety of a Dictionary<Tkey, Tvalue>
Log Off User from Win Xp Programmatically in C#
Formatting Datetime in ASP.NET Core 3.0 Using System.Text.JSON
Bug: Can't Choose Dates on a Datepicker That Fall Outside a Floating VSto Add-In
Winforms Application Hang Due to Systemevents.Onuserpreferencechanged Event
"The Semaphore Timeout Period Has Expired" Error for Usb Connection
How to Connect to Any of the Specified MySQL Hosts. C# MySQL
Identifying Nhibernate Proxy Classes
How to Convert String to Integer in C#
Regex Word Boundary Expressions