【问题标题】:Help with using CreateProcessWithLogonW in C#帮助在 C# 中使用 CreateProcessWithLogonW
【发布时间】:2010-12-30 16:01:58
【问题描述】:

我正在尝试在 Windows XP 上使用 asp.net (C#) 中的参数执行控制台应用程序。我已经尝试过 diagnostics.Process,但我无法让它工作,所以我切换到 CreateProcessWithLogonW。我使用了来自http://www.pinvoke.net/default.aspx/advapi32.createprocesswithlogonw 的代码示例,但控制台应用程序似乎没有运行,并且 CreateProcessWithLogonW api 调用的返回值为 false。

我的控制台应用程序语法类似于:“C:\Program Files\business Intelligence\mycommand.exe”arg1 arg2 arg3 arg4 如果我在 dos 窗口中以交互方式运行它,它运行良好。

在 C# 代码中,我在程序名称前后添加了双引号。当代码运行时,我注意到任务管理器进程计数​​在我运行它的第二秒并没有增加,这告诉我应用程序没有运行。 processInfo 结构全为 0。

我的问题: 1-“CreateProcessWithLogonW”调用的两个“命令”参数是否需要双引号?现在我将整个命令行放入其中。

2- 如何捕获标准输出以便知道发生了什么?

【问题讨论】:

    标签: c# asp.net winapi


    【解决方案1】:

    【讨论】:

    • 我知道,但是 SO 不会让您在 24 小时内接受自己的答案,我还有 7 小时的时间。
    【解决方案2】:

    如果进程根本无法运行,则应获得异常。当您称之为时,您是否会出现异常,如果有这样的例外情况? (请将此附加信息添加到您的问题)。

    如果您没有出现异常,那么应用程序正在执行的情况几乎是这种情况,但是在该应用程序内部失败了 - 它迅速退出,使您没有看到它的执行。要验证或排除这种可能性,您可以添加一个Thread.sleep(20000)调用作为MyCommand.exe应用程序的第一行,这应该将应用程序保持在20秒内,以便您可以使用任务管理器点击并转移调试来自来电应用程序到Callee App的努力。

    回答你的问题#1:是的,你需要引号,因为你的exe的路径有空格。

    回答你的#2:是的,你可以做到这一点,但是你可能会让你分成一个单独的问题,所以一旦你回答第一个,更紧迫的问题。

    【讨论】:

    • 没有异常。 mycommand.exe是第三方工具,所以我无法添加任何东西。如果应用程序正在执行,则任务管理器中的计数器应至少增加1,然后即使在第二个中将下降1。 span>
    【解决方案3】:

    pInvoke 的一个例子是绝对有效的,你可以先用 ping 之类的简单方法试试吗?我已经修改了 pInvoke 的代码来执行 ping 127.0.0.1,如果它适合你,请看下面。回答您的问题:1 - 我想没有必要这样做,但可以双向工作,2 - 你可以这样做,但如果应用程序没有从一开始就启动它不会帮助你。

    示例代码:

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

    希望这会有所帮助,问候

    【讨论】:

    • 当我启动notepad.exe之类的东西时,该代码有效。但是我需要从我的应用程序中捕获输出。这可以告诉我应用程序是否正常运行但遇到错误,甚至“找不到文件”有帮助,这可以告诉我我没有正确构建命令。
    • 为了重定向标准输出,您必须设置 StartupInfo 结构的 stdInput、stdOutput、stdError 字段。您可以使用反射器检查 System.Diagnostics.Process 类的 StartWithCreateProcess 方法,以获取如何执行此操作的示例。简而言之,您需要创建管道(CreatePipe api 调用),将管道的句柄分配给 StartupInfo 的 stdInput、stdOutput 和 stdError 字段,然后使用 FileStreams 从管道读取\写入数据
    猜你喜欢
    • 2011-06-07
    • 1970-01-01
    • 2011-07-21
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    • 2014-09-13
    • 1970-01-01
    • 2011-07-20
    相关资源
    最近更新 更多