Reputation: 44155
I am trying to execute a console app with arguments inside asp.net (C#) on Windows XP. I have tried diagnostics.Process but I just can't get it to work so I am switching to CreateProcessWithLogonW. I used the code sample from http://www.pinvoke.net/default.aspx/advapi32.createprocesswithlogonw but the console app doesn't seem to run and the return value from the CreateProcessWithLogonW api call is false.
My console app syntax is like: "C:\Program Files\business Intelligence\mycommand.exe" arg1 arg2 arg3 arg4 which runs fine if I run it interactively in a dos window.
In the C# code I am adding the double quotes before and after the program name. When the code runs I noticed that the task manager processes count didn't increase ath the second I run it which tells me the app didn't run. The processInfo structure has all 0's.
My questions: 1- Do the two 'command' parameters for the 'CreateProcessWithLogonW' call need to have the double quotes? Right now I am putting the whole command line in each.
2- How do I capture the standard Output so I know what has happened?
Upvotes: 2
Views: 9739
Reputation: 46713
If the process doesn't run at all, you should get an exception. Do you get an exception when you call it, and if so which exception? (please add this additonal info to your question).
If you don't get an exception, it's almost certainly the case that the app is executing, but something is failing inside that app-- and it's exiting quickly enough that you don't see it executing. To verify or exclude this possibility, you can add a Thread.Sleep(20000) call as the first line of your mycommand.exe app, which should keep the app around for 20 seconds so you can spot it with task manager and shift your debugging effort from the caller app to the callee app.
Answer to your question #1: yes you'll need quotes since your EXE's path has spaces.
Answer to your #2: yes, you can do this, but it's probably better for you to split that out into a separate SO question once you've answered the first, more pressing issue.
Upvotes: 0
Reputation: 20492
An example from pInvoke is defenitelly works, can you try it first with smth simple like ping? I've modified code from pInvoke to execute ping 127.0.0.1, please see below if it works for you. Answering your questions: 1 - I guess no need to do it but would work both ways, 2 - you can do it, but if the application doesn't start on the first place it wouldn't help you.
Sample code:
public const UInt32 Infinite = 0xffffffff;
public const Int32 Startf_UseStdHandles = 0x00000100;
public const Int32 StdOutputHandle = -11;
public const Int32 StdErrorHandle = -12;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct StartupInfo
{
public int cb;
public String reserved;
public String desktop;
public String title;
public int x;
public int y;
public int xSize;
public int ySize;
public int xCountChars;
public int yCountChars;
public int fillAttribute;
public int flags;
public UInt16 showWindow;
public UInt16 reserved2;
public byte reserved3;
public IntPtr stdInput;
public IntPtr stdOutput;
public IntPtr stdError;
}
public struct ProcessInformation
{
public IntPtr process;
public IntPtr thread;
public int processId;
public int threadId;
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CreateProcessWithLogonW(
String userName,
String domain,
String password,
UInt32 logonFlags,
String applicationName,
String commandLine,
UInt32 creationFlags,
UInt32 environment,
String currentDirectory,
ref StartupInfo startupInfo,
out ProcessInformation processInformation);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetExitCodeProcess(IntPtr process, ref UInt32 exitCode);
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern UInt32 WaitForSingleObject(IntPtr handle, UInt32 milliseconds);
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(IntPtr handle);
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr handle);
private void button1_Click(object sender, RoutedEventArgs e)
{
StartupInfo startupInfo = new StartupInfo();
startupInfo.reserved = null;
startupInfo.flags &= Startf_UseStdHandles;
startupInfo.stdOutput = (IntPtr)StdOutputHandle;
startupInfo.stdError = (IntPtr)StdErrorHandle;
UInt32 exitCode = 123456;
ProcessInformation processInfo = new ProcessInformation();
String command = @"c:\windows\system32\ping.exe 127.0.0.1";
String user = "admin";
String domain = System.Environment.MachineName;
String password = "password";
String currentDirectory = System.IO.Directory.GetCurrentDirectory();
try
{
CreateProcessWithLogonW(
user,
domain,
password,
(UInt32)1,
null,
command,
(UInt32)0,
(UInt32)0,
currentDirectory,
ref startupInfo,
out processInfo);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.WriteLine("Running ...");
WaitForSingleObject(processInfo.process, Infinite);
GetExitCodeProcess(processInfo.process, ref exitCode);
Console.WriteLine("Exit code: {0}", exitCode);
CloseHandle(processInfo.process);
CloseHandle(processInfo.thread);
}
hope this helps, regards
Upvotes: 1