.NET / C #에서 다른 프로세스의 명령 줄 인수를 가져올 수 있습니까?
각기 다른 명령 줄 인수로 시작된 여러 앱 인스턴스가 실행중인 프로젝트가 있습니다. 해당 인스턴스 중 하나에서 버튼을 클릭 한 다음 모든 인스턴스를 종료하고 동일한 명령 줄 인수로 다시 시작하는 방법을 갖고 싶습니다.
을 통해 프로세스 자체를 쉽게 얻을 수 Process.GetProcessesByName()
있지만, 할 때마다 StartInfo.Arguments
속성은 항상 빈 문자열입니다. 해당 속성은 프로세스를 시작하기 전에 만 유효한 것 같습니다.
이 질문 에는 몇 가지 제안이 있었지만 모두 네이티브 코드로되어 있으며 .NET에서 직접 수행하고 싶습니다. 어떤 제안?
이것은 모든 관리되는 개체를 사용하지만 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();
}
}
WMI를 사용하지 않고이 작업을 수행하는 기본 방법이 있다면 기본적으로 NtQueryInformationProcess()
반환 된 정보에서 명령 줄을 호출 하고 파생 하는 DLL을 작성했습니다 .
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);
그런 다음 다음과 같이 호출하십시오.
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();
}
소스 코드 / DLL은 여기에서 사용할 수 있습니다 .
Jesse C. Slicer의 탁월한 답변에 대한 AC # v6 + 적용 :
어셈블리에 대한 참조를 추가하면
System.Management.dll
(WMISystem.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;
}
}
첫 번째 : 훌륭한 솔루션에 대해 Jesse에게 감사합니다. 내 변형은 다음과 같습니다. 참고 : C #에 대해 내가 좋아하는 것 중 하나는 강력한 형식의 언어라는 것입니다. 따라서 나는 var 유형의 사용을 피합니다. 약간의 명료 함이 캐스트 몇 번의 가치가 있다고 생각합니다.
class Program
{
static void Main(string[] args)
{
Process[] processes = Process.GetProcessesByName("job Test");
for (int p = 0; p < processes.Length; p++)
{
String[] arguments = CommandLineUtilities.getCommandLinesParsed(processes[p]);
}
System.Threading.Thread.Sleep(10000);
}
}
public abstract class CommandLineUtilities
{
public static String getCommandLines(Process processs)
{
ManagementObjectSearcher commandLineSearcher = new ManagementObjectSearcher(
"SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + processs.Id);
String commandLine = "";
foreach (ManagementObject commandLineObject in commandLineSearcher.Get())
{
commandLine+= (String)commandLineObject["CommandLine"];
}
return commandLine;
}
public static String[] getCommandLinesParsed(Process process)
{
return (parseCommandLine(getCommandLines(process)));
}
/// <summary>
/// This routine parses a command line to an array of strings
/// Element zero is the program name
/// Command line arguments fill the remainder of the array
/// In all cases the values are stripped of the enclosing quotation marks
/// </summary>
/// <param name="commandLine"></param>
/// <returns>String array</returns>
public static String[] parseCommandLine(String commandLine)
{
List<String> arguments = new List<String>();
Boolean stringIsQuoted = false;
String argString = "";
for (int c = 0; c < commandLine.Length; c++) //process string one character at a tie
{
if (commandLine.Substring(c, 1) == "\"")
{
if (stringIsQuoted) //end quote so populate next element of list with constructed argument
{
arguments.Add(argString);
argString = "";
}
else
{
stringIsQuoted = true; //beginning quote so flag and scip
}
}
else if (commandLine.Substring(c, 1) == "".PadRight(1))
{
if (stringIsQuoted)
{
argString += commandLine.Substring(c, 1); //blank is embedded in quotes, so preserve it
}
else if (argString.Length > 0)
{
arguments.Add(argString); //non-quoted blank so add to list if the first consecutive blank
}
}
else
{
argString += commandLine.Substring(c, 1); //non-blan character: add it to the element being constructed
}
}
return arguments.ToArray();
}
}
StartInfo.Arguments는 앱을 시작할 때만 사용되며 명령 줄 인수의 레코드가 아닙니다. 명령 줄 인수를 사용하여 응용 프로그램을 시작하는 경우 응용 프로그램에 인수가 들어올 때 저장하십시오. 가장 간단한 경우에는 텍스트 파일에 저장 한 다음 버튼을 누를 때 버튼 누르기 이벤트가있는 프로세스를 제외한 모든 프로세스를 종료 할 수 있습니다. 새 애플리케이션을 실행하고 새 명령 줄 인수에 해당 파일을 제공합니다. 이전 앱이 종료되는 동안 새 앱은 모든 새 프로세스 (파일의 각 줄에 하나씩)를 실행하고 종료합니다. 아래 Psuedocode :
static void Main(string[] args)
{
if (args.Contains(StartProcessesSwitch))
StartProcesses(GetFileWithArgs(args))
else
WriteArgsToFile();
//Run Program normally
}
void button_click(object sender, ButtonClickEventArgs e)
{
ShutDownAllMyProcesses()
}
void ShutDownAllMyProcesses()
{
List<Process> processes = GetMyProcesses();
foreach (Process p in processes)
{
if (p != Process.GetCurrentProcess())
p.Kill(); //or whatever you need to do to close
}
ProcessStartInfo psi = new ProcessStartInfo();
psi.Arguments = CreateArgsWithFile();
psi.FileName = "<your application here>";
Process p = new Process();
p.StartInfo = psi;
p.Start();
CloseAppplication();
}
Hope this helps. Good luck!
'IT Share you' 카테고리의 다른 글
Phoenix Framework에서`def`와`defp`의 차이점은 무엇입니까? (0) | 2020.12.08 |
---|---|
현재 디렉토리를 bash 기록에 저장 (0) | 2020.12.08 |
저장 프로 시저 (.net)의 테이블 값 매개 변수에 빈 목록 또는 null 값 바인딩 (0) | 2020.12.08 |
HTML 책과 같은 페이지 매김 (0) | 2020.12.08 |
Java 응용 프로그램에서 사용자 설정을 저장하는 가장 좋은 방법은 무엇입니까? (0) | 2020.12.08 |