我正在使用以下代码来查找已启动的任何新流程。该函数在线程中运行。
我需要登录已启动的进程名称。我使用两个arraylist。在一个arraylist 我在启动线程和其他arraylist之前存储所有进程名称,我填写 线程中的当前进程并比较两个arraylist以找到新进程。
现在的问题是,因为写入日志文件的字符串是针对每个循环的,我看到了 日志文件中重复的进程名称。我希望它只被记录一次。我该如何解决这个问题?
class ProcessMonitor
{
public static ArrayList ExistingProcess = new ArrayList();
public static void Monitor()
{
existingProcesses = GetExistingProcess();
while (true)
{
ArrayList currentProcesses = new ArrayList();
currentProcesses = GetCurrentProcess();
ArrayList NewApps = new ArrayList(GetCurrentProcess());
foreach (var p in ExistingProcess)
{
NewApps.Remove(p);
}
string str = "";
foreach (string NewApp in NewApps)
{
str += "Launched ProcessName/ID : " + NewApp + "/" + System.Diagnostics.Process.GetProcessesByName(NewApp)[0].Id.ToString() + Environment.NewLine;
}
if(str!="")
{
Log.Info(str);
}
}
}
public static ArrayList GetExistingProcess()
{
Process[] processlist = Process.GetProcesses();
foreach (Process Proc in processlist)
{
ExistingProcess.Add(Proc.ProcessName);
}
return ExistingProcess;
}
public static ArrayList GetCurrentProcess()
{
ArrayList CurrentProcesses = new ArrayList();
Process[] processlist = Process.GetProcesses();
foreach (Process Proc in processlist)
{
CurrentProcesses.Add(Proc.ProcessName);
}
return CurrentProcesses;
}
}
答案 0 :(得分:4)
在Windows上迭代进程非常昂贵。使用WMI,Win32_ProcessStartTrace类有更好的方法。它还会自动解决您的问题,因为它只会告诉您有关新进程的入门信息。并且不需要线程。
您可以在this answer中找到所需的代码。
答案 1 :(得分:1)
我不确定你在这里做了什么,但是下面摘录的前两行和最后一行基本上做同样的事情,只有最后一行更昂贵(因为你创建了第二个数组列表来自由GetCurrentProcess
返回的那个:
ArrayList currentProcesses = new ArrayList();
currentProcesses = GetCurrentProcess();
ArrayList NewApps = new ArrayList(GetCurrentProcess());
其次,就我所知,你似乎永远不会使用currentProcess
变量......所以它100%浪费。第三,如果有重复的流程名称,为什么会出现问题?同一个进程可以多次启动,进程的多个实例可以同时运行,进程可以运行,停止,然后再运行等。进程名称不一定“不正确”上市两次。
(更新:您可能在日志中获得“重复”的一个原因是您只获得existingProcesses
一次。每次循环(顺便说一下,将以最大速度连续发生),您将再次获取进程列表,并将它们与原始existingProcesses
进行比较,因此上一循环中列出的相同进程...如果它们仍在运行,将再次列出。我已更新了我的代码示例演示如何解决此问题。)
您似乎有一些基本的代码错误,并且可能存在缺陷。我将重新审视您的代码,消除无用的代码(如上面的前两行),并通常简化您的代码。 (提示:ArrayList
是真的错误的选择......我会使用IEnumerable<T>
,它不需要任何转换或来自原始数组的填充。如果我用更有效的代码复制上面的代码:
public static void Monitor()
{
var existingProcesses = Process.GetProcesses();
bool doProcessing = true;
while (doProcessing)
{
var currentProcesses = Process.GetProcesses();
var newProcesses = currentProcesses.Except(existingProcesses);
int capacity = newProcesses.Count() * 60;
var builder = new StringBuilder(capacity);
foreach (var newProcess in newProcesses)
{
builder.Append("Launched ProcessName/ID : ");
builder.Append(newProcess.ProcessName);
builder.Append("/");
builder.Append(newProcess.Id);
builder.AppendLine();
}
string newProcessLogEntry = builder.ToString();
if(!String.IsNullOrEmpty(newProcessLogEntry))
{
Log.Info(newProcessLogEntry);
}
existingProcesses = currentProcesses; // Update existing processes, so you don't reprocess previously processed running apps and get "duplicate log entries"
if (requestToStopMonitoring) // do something to kill this loop gracefully at some point
{
doProcessing = false;
continue;
}
Thread.Sleep(5000); // Wait about 5 seconds before iterating again
}
}