原文:http://www.codeproject.com/useritems/wmi.asp
第一次翻譯,只想帶個頭,翻譯的不好,希望各位不要笑話我
相信大家對WMI一定也都有聽說過吧,國內的很多網站也多有介紹過
這里是codeproject上的一篇,我覺得很全面在這里翻譯一下希望大
家評價一下,討論一下自己編寫代碼的心得,OK不多說了,翻譯了......
先介紹一下相關知識:
什么是WMI呢Windows 管理規范 (Windows Management Instrumentation ),它的
主要功能包括:訪問本地主機的一些信息和服務,可以遠程管理計算機(當然你必
須擁有足夠的權限)也就是說可以象重起,關機,關閉進程,創建進程等等!
有了初步了解下面我門開始一些初步的工作吧:
在這個WMI程序中,我將實現四個基本功能:
1.Explorer 類似與windows里的資源管理器
2.SystemInfo 查看你的硬件信息和OS信息
3.Services 當前正在工作的信息
4.Processes 當前執行的進程
(這里是可以管理遠程和本地OS的)
好了,我們要開始實現訪問我們的OS了,不過在這之前我們必須要引入System.Management
這個命名空間
下面讓我們了解一下控件的狀態事件
我們必須保證是實時的所以必須在這里包涵UpdateStatus(string e)該事件(這是一個自定義的)
這里主要是希望在點擊每個控件時刷新狀態欄,可以讓用戶知道程序在做什么!
代碼事例:
//控件代碼
//狀態事件的代理
public delegate void Status(string e);
public event Status UpdateStatus;
//這里更新狀態欄
UpdateStatus("Hello world.");
//這里是在主程序里的代碼
//寫具體的事件代碼
private void refreshStatusBar(string stringStatus)
{
//update status bar
statusBarStatus.Text = stringStatus;
}
下面是具體代碼:
Explorer Control
這里首先介紹一下WMI的 Win32_LogicalDisk類(參考Platform SDK: Windows Management Instrumentation),通過它我們可以查看到本地驅動器
的一些詳細情況,我們還需要用到System.Management中的兩個類ManagementObjectSearcher
和ManagementOjbectCollection它們的作用主要是ManagementObjectSearcher將查詢到了
ManagementOjbectCollection該對象的集合中去(這里可以獲取的驅動器信息包括 驅動器的名稱
,類型,描述信息等)當然你也可以只查看驅動器的部分信息可以在ManagementObjectSearcher類
的構造函數中這樣寫ManagementObjectSearcher query = new ManagementObjectSearcher("SELECT * From Win32_LogicalDisk "); (參考Platform SDK: Windows Management Instrumentation)
代碼如下:
//get drive collection
ManagementObjectSearcher query = new ManagementObjectSearcher("SELECT * From Win32_LogicalDisk ");
ManagementObjectCollection queryCollection = query.Get();
//loop throught each object to get drive information
foreach ( ManagementObject mo in queryCollection)
{
switch (int.Parse( mo["DriveType"].ToString()))
{
case Removable: //removable drives
imageIndex = 5;
selectIndex = 5;
break;
case LocalDisk: //Local drives
imageIndex = 6;
selectIndex = 6;
break;
case CD: //CD rom drives
imageIndex = 7;
selectIndex = 7;
break;
case Network: //Network drives
imageIndex = 8;
selectIndex = 8;
break;
default: //defalut to folder
imageIndex = 2;
selectIndex = 3;
break;
}
//get drive name
Console.WriteLine("Drive: " + mo["Name"].ToString());
}
SystemInfo Control
該控件主要用來查看本地或遠程主機的OS和硬件信息,這里需要用到另外兩個
對象ConnectionOptions和ManagementScope,ConnectionOptions主要是設置
WMI連接信息的,如用戶名和密碼,這里我們主要用到它的兩個屬性UserName和
Password; ManagementScope對象表示WMI的規范,通過該規范可以訪問服務器
和命名空間的路徑已及使用ConnectionOptions中的設置
請看如下代碼:
//Connect to the remote computer
ConnectionOptions co = new ConnectionOptions();
co.Username = textUserID.Text;
co.Password = textPassword.Text;
//Point to machine
System.Management.ManagementScope ms = new System.Management.ManagementScope("" +
stringHostName + "", co);
現在我們結合剛才的知識來得到我們要的信息,但我們要得到那些我們想要信息呢?
那樣的話我們就必須要用到ObjectQuery對象,通過它我們可以得到我們想要的查詢
信息.把ObjectQuery對象和ManagementScope對象放入ManagementObjectSearcher對象
中這樣就可以通過我們設置好的規范和我們設置好的查詢得到我們想要的結果,當然
還必須要掉用ManagementObjiectSearcher的Get()方法,它會返回一個ManagementObject
對象的集合,然后可以通過結合操作來訪問到每一個我們要的信息.
代碼如下:
//Query system for Operating System information
oq = new System.Management.ObjectQuery("SELECT * FROM Win32_OperatingSystem");
query = new ManagementObjectSearcher(ms,oq);
queryCollection = query.Get();
foreach ( ManagementObject mo in queryCollection)
{
//create child node for operating system
createChildNode(nodeCollection, "Operating System: " + mo["Caption"]);
createChildNode(nodeCollection, "Version: " + mo["Version"]);
createChildNode(nodeCollection, "Manufacturer : " + mo["Manufacturer"]);
createChildNode(nodeCollection, "Computer Name : " +mo["csname"]);
createChildNode(nodeCollection, "Windows Directory : " + mo["WindowsDirectory"]);
}
要是你只是希望查看到本地主機的信息,你就沒必要去創建 ConnectionOption, ManagementScope,ObjectQuery 對象,你僅僅只需要把ManagementObjectSearcher
對象的結果在ManagementObjectCollection集合里去調用Get()方法既可.
代碼如下:
ManagementObjectSearcher query = new ManagementObjectSearcher("SELECT * From Win32_OperatingSystem");
ManagementObjectCollection queryCollection = query.Get();
這里只是介紹了OS信息的方法,其它的如Bios,Memory.Network Connection等信息的查看
只需要把查詢字改改就可以了!(可參考Platform SDK: Windows Management Instrumentation)
Service Control控件介紹:
該控件要用到一個新的查詢字"SELECT * FROM Win32_Service",通過它我們就可以
得到系統中有那些服務存在.為了方便啟動和終止一項服務我們可以在ListView中
動態的創建一個彈出式菜單,當用鼠標左擊ListView中的Item的時候,可以用來啟動
或終止一項服務.可以這樣來指定你要的服務"SELECT * FROM Win32_Service WHERE
Name = ´ServiceName´",這個時候我們要調用ManagementObject.InvokeMethod()
來指定是終止還是啟動一個服務.InvokeMethod()的第一個參數是一個ManagementBaseObject
的對象.它用作更具體的管理對象類的基類.我通過一個ManagementOperationObserver對象
管理異步操作和處理異步收到的管理信息和事件??梢杂蒫ompletionHandlerObj.ReturnObject
(為自定義類的屬性)
屬性返回值來判斷是否成功.
代碼如下:
/// <summary>
/// List view mouse down event to built context menu dynamically
/// </summary>
///
///
private void listViewServices_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
System.Windows.Forms.ListView listViewObject = (System.Windows.Forms.ListView) sender;
ContextMenu mnuContextMenu = new ContextMenu();
MenuItem menuItem = new MenuItem();
ManagementObjectCollection queryCollection;
//check if right button
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
//get service name
ServiceName = listViewObject.GetItemAt(e.X, e.Y).Text;
//set list view item
ServiceItem = listViewObject.GetItemAt(e.X,e.Y);
//create popup menu
listViewObject.ContextMenu = mnuContextMenu;
try
{
//get specific service object
queryCollection = getServiceCollection("SELECT * FROM Win32_Service Where Name = ´" +
ServiceName + "´");
foreach ( ManagementObject mo in queryCollection)
{
//create menu depending on service state
if (mo["Started"].Equals(true))
{
menuItem.Text = "Stop";
//set action property
ServiceAction = "StopService";
}
else
{
menuItem.Text = "Start";
ServiceAction = "StartService";
}
mnuContextMenu.MenuItems.Add(menuItem);
// Add functionality to the menu items using the Click event.
menuItem.Click += new System.EventHandler(this.menuItem_Click);
}
}
catch (Exception e1)
{
MessageBox.Show("Error: " + e1);
}
}
}
/// <summary>
/// List view context menu click event to invoke start/stop service
/// </summary>
///
///
private void menuItem_Click(object sender, System.EventArgs e)
{
ManagementObjectCollection queryCollection;
ListViewItem lvItem;
//Set up a handler for the asynchronous callback
ManagementOperationObserver observer = new ManagementOperationObserver();
completionHandler.MyHandler completionHandlerObj = new completionHandler.MyHandler();
observer.ObjectReady += new ObjectReadyEventHandler(completionHandlerObj.Done);
//get specific service object
queryCollection = getServiceCollection("Select * from Win32_Service Where Name =´" +
ServiceName + "´");
//Status
updateStatus("Starting/Stopping service...");
foreach ( ManagementObject mo in queryCollection)
{
//start or stop service
mo.InvokeMethod(observer, ServiceAction, null);
}
//wait until invoke method is complete or 5 sec timeout
int intCount = 0;
while
(!completionHandlerObj.IsComplete)
{
if
(intCount > 10)
{
MessageBox.Show("Terminate process timed out.", "Terminate Process Status");
break;
}
//wait 1/2 sec.
System.Threading.Thread.Sleep(500);
//increment counter
intCount++;
}
//see if call was suclearcase/" target="_blank" >ccessful.
if (completionHandlerObj.ReturnObject.Properties["returnValue"].Value.ToString() == "0")
{
//succeeded
lvItem = ServiceItem;
if (ServiceAction == "StartService")
lvItem.SubItems[2].Text = "Started";
else
lvItem.SubItems[2].Text = "Stop";
}
else
{
//error message
string stringAction;
if (ServiceAction == "StartService")
stringAction = "start";
else
stringAction = "stop";
MessageBox.Show("Failed to " + stringAction + " service " + ServiceName + ".",
"Start/Stop Service Failure");
}
//clean-up objects
ServiceName = "";
ServiceAction = "";
ServiceItem = null;
//Status
updateStatus("Ready");
this.Update();
}
//----------------------------------
// Completion Handler
//----------------------------------
using System;
using System.Management;
namespace completionHandler
{
/// <summary>
/// MyHandler class handle notification when InvokeMethod call is complete
/// </summary>
public class MyHandler
{
private bool isComplete = false;
private ManagementBaseObject returnObject;
/// <summary>
/// Trigger Done event when InvokeMethod is complete
/// </summary>
public void Done(object sender, ObjectReadyEventArgs e)
{
isComplete = true;
returnObject = e.NewObject;
}
/// <summary>
/// Get property IsComplete
/// </summary>
public bool IsComplete
{
get
{
return isComplete;
}
}
/// <summary>
/// Property allows accessing the result object in the main function
/// </summary>
public ManagementBaseObject ReturnObject
{
get
{
return returnObject;
}
}
}
}
ProcessesControl控件介紹:
該控件主要用來顯示系統中正在運行的進程,如:用戶進程.CPU利用率,
內存的使用狀況.我們可以通過GetOwner(User,Domain)方法來得知進程
的所有者是誰.User和Domain是入口參數,可是問題是我們如何從InvokeMethod
中得到這入口參數呢?這里我們需要實現InvokeMethod.一下討論兩種情況
1.我們不需要異步操作,我們僅僅只需要一個string[]數組就可以完成
2.當我們需要異步操作的時候也只需要一個completionHandlerObj.ReturnObject
屬性來收集對象.
代碼如下:
//-------------------------------------------------
//Get process owner info without the observer object
//--------------------------------------------------
//Createan array containing all arguments for the method
string[] methodArgs = {"", ""};
//Get process owner info
mo.InvokeMethod("GetOwner", methodArgs);
//methodArgs[0] - contain process user
//methodArgs[1] = contain process domain
//-----------------------------------------------
//Getprocess owner info with the observer object
//-----------------------------------------------
mo.InvokeMethod(observer,"GetOwner", null);
while (!completionHandlerObj.IsComplete)
{
System.Threading.Thread.Sleep(500);
}
if (completionHandlerObj.ReturnObject["returnValue"].ToString() == "0")
structProcess.stringUserName = completionHandlerObj.ReturnObject.Properties["User"].Value.ToString();
else
structProcess.stringUserName = "";
下面討論如何終結進程:
終結一個指定的進程很類似與上面提到的啟動或終止一項服務.
首先當然是用ManagementObject對象來指定你要的進程,然后調用
InvokeMethod(observer,"Terminate",null)來終止一個進程.
代碼如下:
//Set up a handler for the asynchronous callback
ManagementOperationObserver observer = new ManagementOperationObserver();
completionHandler.MyHandler completionHandlerObj = new completionHandler.MyHandler();
observer.ObjectReady += new ObjectReadyEventHandler(completionHandlerObj.Done);
//Get ManagementObject for process
queryCollection = getProcessCollection("Select * from Win32_Process Where ProcessID = ´" + ProcessID + "´");
//Status
updateStatus("Invoking terminate process");
foreach ( ManagementObject mo in queryCollection)
{
//start or stop service
mo.InvokeMethod(observer, "Terminate", null);
}
//wait until invoke method is complete or 5 sec timeout
int intCount = 0;
while (!completionHandlerObj.IsComplete)
{
if (intCount == 10)
{
MessageBox.Show("Terminate process timed out.", "Terminate Process Status");
break;
}
//wait 1/2 sec.
System.Threading.Thread.Sleep(500);
//increment counter
intCount++;
}
if (intCount != 10)
{
//InvokeMethod did not time out
if (completionHandlerObj.ReturnObject.Properties["returnValue"].Value.ToString() == "0")
{
lvItem = ProcessItem;
lvItem.Remove();
}
else
{
MessageBox.Show("Error terminating process.", "Terminate Process");
}
}
創建進程:
創建一個新的進程我們需要調用ManagementClass類的InvokeMethod方法來完成
我們可以通過ManagementClass processClass = New ManagementClass(ms,path,null);
這條語句來實現一個ManagementClass對象.ms是一個ManagementScope類的實例;
,path是一個ManagementPath的實例.ManagementScope來設置Management的范圍.
ManagementPath用來提供一個包裝,用于分析和生成 WMI 對象的路徑.("Win32_Process")
在這之前我們還需要調用ManagementClass.InvokeMethod(observer, methodName, inParameters).
我們可以通過一個對象數組來一次傳遞四個參數.inParameters實際上就是一個
Create Method in Class Win32_Process(參考Platform SDK: Windows Management Instrumentation)
uint32 Create(string CommandLine,
string CurrentDirectory,
Win32_ProcessStartup ProcessStartupInformation,
uint32* ProcessId);
Parameters
CommandLine - [in] Command line to execute. The system adds a null character to the command line, trimming the string if necessary, to indicate which file was actually used.
CurrentDirectory - [in] Current drive and directory for the child process. The string requires that the current directory resolves to a known path. A user can specify an absolute path or a path relative to the current working directory. If this parameter is NULL, the new process will have the same path as the calling process. This option is provided primarily for shells that must start an application and specify the application´s initial drive and working directory.
ProcessStartupInformation - [in] The startup configuration of a Windows process. For more information see Win32_ProcessStartup.
ProcessId - [out] Global process identifier that can be used to identify a process. The value is valid from the time the process is created until the time the process is terminated
例如代碼:
//Create an array containing all arguments for the method
object[] methodArgs = {stringCommandLine, null, null, 0};
//Execute the method
processClass.InvokeMethod (observer, "Create", methodArgs);
下面的代碼是用來創建并插入一個新的進程.我們可以寫一個CreateProcess
函數通過參數stringCommandLine來傳遞一個你希望創建的進程.如你可以
這樣寫 CreateProcess("Calc.exe"), 這時候你就可以創建一個計算器
進程了,下面是個例子.
代碼如下;
/// <summary>
/// Invoke method ´Create´ on local or remote machine
/// </summary>
///
private void CreateProcess(string stringCommandLine)
{
//Set up a handler for the asynchronous callback
ManagementOperationObserver observer = new ManagementOperationObserver();
completionHandler.MyHandler completionHandlerObj = new completionHandler.MyHandler();
observer.ObjectReady += new ObjectReadyEventHandler(completionHandlerObj.Done);
string stringMachineName = "";
//Connect to the remote computer
ConnectionOptions co = new ConnectionOptions();
if (radioMachine.Checked == true)
{
stringMachineName = "localhost";
}
else
{
stringMachineName = textIP.Text;
}
if (stringMachineName.Trim().Length == 0)
{
MessageBox.Show("Must enter machine IP address or name.");
return;
}
//get user and password
if (textUserID.Text.Trim().Length > 0)
{
co.Username = textUserID.Text;
co.Password = textPassword.Text;
}
//Point to machine
System.Management.ManagementScope ms = new System.Management.ManagementScope("" +
stringMachineName + "", co);
//get process path
ManagementPath path = new ManagementPath( "Win32_Process");
//Get the object on which the method will be invoked
ManagementClass processClass = new ManagementClass(ms,path,null);
//Status
updateStatus("Create process " + stringCommandLine + ".");
//Create an array containing all arguments for the method
object[] methodArgs = {stringCommandLine, null, null, 0};
//Execute the method
processClass.InvokeMethod (observer, "Create", methodArgs);
//wait until invoke method is complete or 5 sec timeout
int intCount = 0;
while (!completionHandlerObj.IsComplete)
{
if (intCount > 10)
{
MessageBox.Show("Create process timed out.", "Terminate Process Status");
break;
}
//wait 1/2 sec.
System.Threading.Thread.Sleep(500);
//increment counter
intCount++;
}
if (intCount != 10)
{
//InvokeMethod did not time out
//check for error
if (completionHandlerObj.ReturnObject.Properties["returnValue"].Value.ToString() == "0")
{
//refresh process list
this.Refresh();
}
else
{
MessageBox.Show("Error creating new process.", "Create New Process");
}
}
//Status
updateStatus("Ready");
this.Update();
}
總結:
這里只是做了一個使用WMI的例子.我們大體可以通過這個簡單的例子
了解一下WMI究竟可以做那些事情.我想,我在代碼中的注釋可以很方便
讓大家了解WMI.
下面這個列表可以讓你明白WMI能處理那些問題:
*控制你的軟硬件
*監管事件
*執行一個基于事件的描述
*通過事件來發送E-mail
參考資料:
[url]http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/wmi_start_page.asp[/url]
[url]http://www.microsoft.com/taiwan/technet/scriptcenter/sampscr.htm[/url]
原文轉自:http://www.anti-gravitydesign.com