2 回答
TA贡献1824条经验 获得超8个赞
从技术上讲,这并不能回答您的问题,因为它不使用 Win32_Process 查询。但是,使用 Powershell,它确实会在很短的时间内(~1.5 秒对~25 秒)产生相同的结果。
您需要在 X64 模式下运行它以询问 64 位进程,并且需要提升权限才能让 Powershell 返回用户名。
请注意,这是我第一次从 C# 调用 Powershell 脚本,可能有更好的方法来做。它还需要一些错误捕获以使其更健壮(不适合按原样生产)。
using System.Management.Automation;
using System.Management.Automation.Runspaces;
private DataTable getProcesses()
{
// Create the datatable and columns
DataTable dt = new DataTable();
dt.Columns.Add("ID");
dt.Columns.Add("Name");
dt.Columns.Add("Path");
dt.Columns.Add("User");
dt.Columns.Add("Priority");
dt.Columns.Add("BasePriority");
string script = $"get-process -IncludeUserName | select id, processname, path, username, priorityclass";
List<string[]> psOutput = new List<string[]>();
// Invoke Powershell cmdlet and get output
using (PowerShell ps = PowerShell.Create())
{
ps.AddScript(script);
var output = ps.Invoke();
if(ps.Streams.Error.Count > 0)
{
throw new Exception($"Error running script:{Environment.NewLine}{string.Join(Environment.NewLine, ps.Streams.Error.Select(e => e.ToString()))}");
}
// clean and split the output
psOutput.AddRange(output.Select(i => i.ToString().Replace("; ", ";").TrimStart("@{".ToCharArray()).TrimEnd('}').Split(';')));
}
// populate the DataTable
psOutput
.AsParallel() // this does not really help when not calling Process.GetProcessById
.Select(p => p.Select(f => f.Split("=")).ToDictionary(k => k.FirstOrDefault(), v => v.LastOrDefault()))
.Select(kv => new object[] { // "flatten" the dictionaries into object[]'s that will become the datarows
kv["Id"]
, kv["ProcessName"]
, kv["Path"]
, kv["UserName"]
, kv["PriorityClass"]
, Process.GetProcessById(int.Parse(kv["Id"])).BasePriority // if you need the numerical base priority - takes quite a bit longer though (Not sure how to get this via Powershell)
}
)
.ToList()
.ForEach(r => dt.Rows.Add(r)); // add each object[] to the datatable
// return the datatable
return dt;
}
TA贡献1906条经验 获得超3个赞
我个人一直想摆脱使用DataTable. 您可以使用List<>可以解决许多潜在问题的集合。
话虽如此,您可能想查看ORMi库以获取有关List<>. 您可以通过以下方式实现您正在尝试的目标:
WMIHelper helper = new WMIHelper("root\\CimV2");
string pid = "-";
string name = "-";
string path = "-";
string priort = "-";
string user = "-";
var processes = helper.Query("Select * From Win32_Process").ToList();
foreach (var p in processes)
{
pid = p.ProcessID;
name = p.Name;
path = p.ExecutablePath ?? String.Empty;
priort = p.Priority ?? String.Empty;
}
上面的代码适用于dynamic对象,不需要您编写任何模型。就是那个小代码。如果您需要使用方法,那么您可以声明您的模型并使用强类型对象:
1)定义你的模型:
[WMIClass(Name = "Win32_Process", Namespace = "root\\CimV2")]
public class Process
{
public int Handle { get; set; }
public string Name { get; set; }
public int ProcessID { get; set; }
public string ExecutablePath { get; set; }
public int Priority { get; set; }
/// <summary>
/// Date the process begins executing.
/// </summary>
public DateTime CreationDate { get; set; }
public dynamic GetOwnerSid()
{
return WMIMethod.ExecuteMethod(this);
}
public ProcessOwner GetOwner()
{
return WMIMethod.ExecuteMethod<ProcessOwner>(this);
}
public int AttachDebugger()
{
return WMIMethod.ExecuteMethod<int>(this);
}
}
public class ProcessOwner
{
public string Domain { get; set; }
public int ReturnValue { get; set; }
public string User { get; set; }
}
2)查询WMI
List<Process> processes = helper.Query<Process>().ToList();
foreach (Process p in processes)
{
pid = p.ProcessID;
name = p.Name;
path = p.ExecutablePath ?? String.Empty;
priort = p.Priority ?? String.Empty;
dynamic d = p.GetOwnerSid();
ProcessOwner po = p.GetOwner();
}
即使对于这个任务,第二种方式可能看起来有点太多的工作,你会得到更干净和易于理解的代码。
注意:我已经用 ORMi 尝试过你的代码,我会在 1-2 秒内得到结果。正如其他人所说,这可能取决于您的环境。
SELECT注意 2:始终只使用语句中需要的属性。WMI a 非常昂贵SELECT *。始终指定属性。在您的情况下,它将是:
Select ProcessID, Name, ExecutablePath, Priority From Win32_Process
(ORMi 也会为您解决这个问题,因为它总是会查询模型上设置的属性。)
- 2 回答
- 0 关注
- 210 浏览
添加回答
举报
