我可以从.NET/C#获取其他进程的命令行参数吗?

Jon*_*ter 60 .net c#

我有一个项目,我有一个运行的应用程序的多个实例,每个实例都使用不同的命令行参数启动.我希望有一种方法可以从其中一个实例中单击一个按钮,然后关闭所有实例并使用相同的命令行参数重新启动它们.

我可以很容易地通过自己获得进程Process.GetProcessesByName(),但每当我这样做时,StartInfo.Arguments属性总是一个空字符串.看起来这个属性可能只在开始一个进程之前有效.

这个问题有一些建议,但它们都是本机代码,我想直接从.NET做到这一点.有什么建议?

Jes*_*cer 74

这是使用所有托管对象,但它确实深入到WMI领域:

private static void Main()
{
    foreach (var process in Process.GetProcesses())
    {
        try
        {
            Console.WriteLine(process.GetCommandLine());
        }
        catch (Win32Exception ex) when ((uint)ex.ErrorCode == 0x80004005)
        {
            // Intentionally empty - no security access to the process.
        }
        catch (InvalidOperationException)
        {
            // Intentionally empty - the process exited before getting details.
        }

    }
}

private static string GetCommandLine(this Process process)
{
    using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + process.Id))
    using (ManagementObjectCollection objects = searcher.Get())
    {
        return objects.Cast<ManagementBaseObject>().SingleOrDefault()?["CommandLine"]?.ToString();
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 小记; 在我的计算机上(Win 10),WMI返回的命令行包含正在运行的程序的名称,因此无需使用process.MainModule.FileName初始化StringBuilder.仍然是一段很好的代码,它现在在我的项目中.. Thanx! (2认同)
  • 尽我所能尝试,通过“ ManagementObjectSearcher”,WMI速度缓慢。 (2认同)

Soo*_*nts 15

如果您想在没有 WMI 和 ProcCmdLine32.dll 的 Linux 上执行相同的操作,代码如下:

\n\n
string cmdline = File.ReadAllText( $"/proc/{ process.Id }/cmdline" );\n
Run Code Online (Sandbox Code Playgroud)\n

  • 哈。我喜欢这里微妙的 Linux 促销 (2认同)

And*_*ndy 9

如果您不想使用WMI,而是想拥有一种本机的方式,我写了一个DLL,它基本上NtQueryInformationProcess()从返回的信息中调用并派生命令行。

它是用C ++编写的,没有依赖关系,因此它可以在任何Windows系统上工作。

要使用它,只需添加以下导入:

[DllImport("ProcCmdLine32.dll", CharSet = CharSet.Unicode, EntryPoint = "GetProcCmdLine")]
public extern static bool GetProcCmdLine32(uint nProcId, StringBuilder sb, uint dwSizeBuf);

[DllImport("ProcCmdLine64.dll", CharSet = CharSet.Unicode, EntryPoint = "GetProcCmdLine")]
public extern static bool GetProcCmdLine64(uint nProcId, StringBuilder sb, uint dwSizeBuf);
Run Code Online (Sandbox Code Playgroud)

然后这样称呼它:

public static string GetCommandLineOfProcess(Process proc)
{
    // max size of a command line is USHORT/sizeof(WCHAR), so we are going
    // just allocate max USHORT for sanity's sake.
    var sb = new StringBuilder(0xFFFF);
    switch (IntPtr.Size)
    {
        case 4: GetProcCmdLine32((uint)proc.Id, sb, (uint)sb.Capacity); break;
        case 8: GetProcCmdLine64((uint)proc.Id, sb, (uint)sb.Capacity); break;
    }
    return sb.ToString();
}
Run Code Online (Sandbox Code Playgroud)

源代码/ DLL在此处可用。

  • 谢谢!这比WMI解决方案好得多。 (5认同)

mkl*_*nt0 8

AC#6适应Jesse C. Slicer的优秀答案:

  • 已完成并且应该按原样运行,一旦添加对程序集的引用System.Management.dll(WMI System.Management.ManagementSearcher类需要).

  • 简化原始代码并修复一些问题

  • 处理正在检查的进程已经退出时可能发生的其他异常.

using System.Management;
using System.ComponentModel;

// Note: The class must be static in order to be able to define an extension method.
static class Progam
{   
    private static void Main()
    {
        foreach (var process in Process.GetProcesses())
        {
            try
            {
                Console.WriteLine($"PID: {process.Id}; cmd: {process.GetCommandLine()}");
            }
            // Catch and ignore "access denied" exceptions.
            catch (Win32Exception ex) when (ex.HResult == -2147467259) {}
            // Catch and ignore "Cannot process request because the process (<pid>) has
            // exited." exceptions.
            // These can happen if a process was initially included in 
            // Process.GetProcesses(), but has terminated before it can be
            // examined below.
            catch (InvalidOperationException ex) when (ex.HResult == -2146233079) {}
        }
    }

    // Define an extension method for type System.Process that returns the command 
    // line via WMI.
    private static string GetCommandLine(this Process process)
    {
        string cmdLine = null;
        using (var searcher = new ManagementObjectSearcher(
          $"SELECT CommandLine FROM Win32_Process WHERE ProcessId = {process.Id}"))
        {
            // By definition, the query returns at most 1 match, because the process 
            // is looked up by ID (which is unique by definition).
            using (var matchEnum = searcher.Get().GetEnumerator())
            {
                if (matchEnum.MoveNext()) // Move to the 1st item.
                {
                    cmdLine = matchEnum.Current["CommandLine"]?.ToString();
                }
            }
        }
        if (cmdLine == null)
        {
            // Not having found a command line implies 1 of 2 exceptions, which the
            // WMI query masked:
            // An "Access denied" exception due to lack of privileges.
            // A "Cannot process request because the process (<pid>) has exited."
            // exception due to the process having terminated.
            // We provoke the same exception again simply by accessing process.MainModule.
            var dummy = process.MainModule; // Provoke exception.
        }
        return cmdLine;
    }
}
Run Code Online (Sandbox Code Playgroud)