2 回答

TA貢獻1824條經(jīng)驗 獲得超8個贊
從技術(shù)上講,這并不能回答您的問題,因為它不使用 Win32_Process 查詢。但是,使用 Powershell,它確實會在很短的時間內(nèi)(~1.5 秒對~25 秒)產(chǎn)生相同的結(jié)果。
您需要在 X64 模式下運行它以詢問 64 位進程,并且需要提升權(quán)限才能讓 Powershell 返回用戶名。
請注意,這是我第一次從 C# 調(diào)用 Powershell 腳本,可能有更好的方法來做。它還需要一些錯誤捕獲以使其更健壯(不適合按原樣生產(chǎn))。
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條經(jīng)驗 獲得超3個贊
我個人一直想擺脫使用DataTable. 您可以使用List<>可以解決許多潛在問題的集合。
話雖如此,您可能想查看ORMi庫以獲取有關(guān)List<>. 您可以通過以下方式實現(xiàn)您正在嘗試的目標:
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();
}
即使對于這個任務(wù),第二種方式可能看起來有點太多的工作,你會得到更干凈和易于理解的代碼。
注意:我已經(jīng)用 ORMi 嘗試過你的代碼,我會在 1-2 秒內(nèi)得到結(jié)果。正如其他人所說,這可能取決于您的環(huán)境。
SELECT注意 2:始終只使用語句中需要的屬性。WMI a 非常昂貴SELECT *。始終指定屬性。在您的情況下,它將是:
Select ProcessID, Name, ExecutablePath, Priority From Win32_Process
(ORMi 也會為您解決這個問題,因為它總是會查詢模型上設(shè)置的屬性。)
- 2 回答
- 0 關(guān)注
- 182 瀏覽
添加回答
舉報