我有一个项目,我有一个运行的应用程序的多个实例,每个实例都使用不同的命令行参数启动.我希望有一种方法可以从其中一个实例中单击一个按钮,然后关闭所有实例并使用相同的命令行参数重新启动它们.
我可以很容易地通过自己获得进程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)
Soo*_*nts 15
如果您想在没有 WMI 和 ProcCmdLine32.dll 的 Linux 上执行相同的操作,代码如下:
\n\nstring cmdline = File.ReadAllText( $"/proc/{ process.Id }/cmdline" );\n
Run Code Online (Sandbox Code Playgroud)\n
如果您不想使用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在此处可用。
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)