admin 管理员组文章数量: 887053
2024年2月20日发(作者:java怎样定义结构体)
如何使用WMI获取进程信息(异步处理)
文章分类:操作系统
以下示例演示如何使用WMI 获得本地机器的进程列表(当然,WMI 也能获得远程机器的进程列表,远不只例子中的功能),示例代码是我简化codeproject 的例子而来:
// 用于表示进程信息的结构
public struct structProcessInfo
{
// 进程名
public string stringName;
// 进程ID
public string stringProcessID;
// 父进程ID
public string stringParentProcessID;
// 用户名
public string stringUserName;
}
public class ProcessesInfo
{
private structProcessInfo _value;
public structProcessInfo Value
{
get {return _value;}
set {_value = value ;}
}
}
// 用于保存进程信息的字典类,继承于NameObjectCollectionBase
public class ProcessesDictionary : NameObjectCollectionBase
{
public void Clear()
{
BaseClear();
}
public void Add(string name, ProcessesInfo processObj)
{
BaseAdd(name, processObj);
}
public void Remove(string name)
{
BaseRemove(name);
}
public void RemoveAt(int index)
{
BaseRemoveAt(index);
}
public ProcessesInfo this [int index]
{
get { return (ProcessesInfo )BaseGet(index); }
set { BaseSet(index, value ); }
}
public ProcessesInfo this [string name]
{
get { return (ProcessesInfo )BaseGet(name); }
set { BaseSet(name, value ); }
}
}
= = = = = = = = = = = = = = = = = = = = = = =
= = = = = = =
// 用于表示进程CPU 及内存使用情况的结构
public struct structPerformance
{
public string stringPercentProcessorTime;
public string stringVirtualBytes;
}
public class ProcessPerf
{
private structPerformance _value;
public structPerformance Value
{
get { return _value; }
set { _value = value ; }
}
}
// 用于保存进程CPU 及内存使用情况的字典类
public class ProcessesPerformanceDictionary : NameObjectCollectionBase
{
public void Clear()
{
BaseClear();
}
public void Add(string name, ProcessPerf processPerformance)
{
BaseAdd(name, processPerformance);
}
public void Remove(string name)
{
BaseRemove(name);
}
public void RemoveAt(int index)
{
BaseRemoveAt(index);
}
public ProcessPerf this [int index]
{
get { return (ProcessPerf )BaseGet(index); }
set { BaseSet(index, value ); }
}
public ProcessPerf this [string name]
{
get { return (ProcessPerf )BaseGet(name); }
set { BaseSet(name, value ); }
}
}
= = = = = = = = = = = = = = = = = = = = = = =
= = = = = = =
// 表示ManagementObject 对象的异步调用方法是否完成
public class MyHandler
{
private bool isComplete = false ;
private ManagementBaseObject returnObject;
public void Done(object sender, ObjectReadyEventArgs e)
{
isComplete = true ;
returnObject = ect;
}
public bool IsComplete
{
get
{
return isComplete;
}
}
public ManagementBaseObject ReturnObject
{
get
{
return returnObject;
}
}
}
= = = = = = = = = = = = = = = = = = = = = = =
= = = = = = =
一个窗体,添加一个ListView :lvProcess ,一个Button :btList 用于显示进程列表,一个Button :btClose 用于关闭窗体:
private void btList_Click(object sender, EventArgs e)
{
this .();
ManagementOperationObserver observer = new
ManagementOperationObserver ();
MyHandler invokeHandler = new MyHandler ();
Ready += new ObjectReadyEventHandler ();
ProcessesDictionary pDict = new ProcessesDictionary ();
ProcessesPerformanceDictionary perDict = new
ProcessesPerformanceDictionary ();
ProcessesInfo pInfo;
structProcessInfo pStruct;
ProcessPerf perInfo;
structPerformance perStruct;
string [] lvData = new string [5];
#region 获取进程名称、ID 、父进程ID 、进程所属用户名
ManagementObjectCollection moc = this .ExecSearch("SELECT * FROM
Win32_Process" );
if (moc == null )
{
MessageBox .Show("Error:null" );
return ;
}
foreach (ManagementObject mo in moc)
{
pInfo = new ProcessesInfo ();
pStruct = new structProcessInfo ();
Name = mo["Name" ].ToString();
ProcessID = mo["ProcessID" ].ToString();
ParentProcessID =
mo["ParentProcessID" ].ToString();
Method(observer, "GetOwner" , null );
while (!lete)
{
.Sleep(500);
}
// 判断获取用户名的操作是否成功
if (Object["returnValue" ].ToString() ==
"0" )
{
UserName =
ties["User" ].ng();
}
else
{
UserName = "" ;
}
// 保存该进程信息到字典类中
= pStruct;
(mo["ProcessID" ].ToString(), pInfo);
}
#endregion
#region 获得进程的CPU 及内存使用情况
ManagementObjectCollection moc1 = this .ExecSearch("SELECT * FROM
Win32_PerfFormattedData_PerfProc_Process" );
if (moc1 == null )
{
MessageBox .Show("Error:null" );
return ;
}
foreach (ManagementObject mo1 in moc1)
{
perInfo = new ProcessPerf ();
perStruct = new structPerformance ();
PercentProcessorTime =
ties["PercentProcessorTime" ].ng();
VirtualBytes =
mo1["VirtualBytes" ].ToString();
// 添加CPU 及内存使用情况到字典类中
= perStruct;
(mo1["IDProcess" ].ToString(), perInfo);
perInfo = null ;
}
#endregion
#region 显示列表
foreach (string stringProcessID in pDict)
{
pStruct = pDict[stringProcessID].Value;
lvData[0] = ng();
lvData[4] = ng();
lvData[1] = ng();
try
{
lvData[2] =
perDict[ng()].ng();
lvData[3] =
perDict[ng()].ng();
}
catch (NullReferenceException )
{
// 无法获取CPU 及内存情况
lvData[2] = "0" ;
lvData[3] = "0" ;
}
ListViewItem lvItem = new ListViewItem (lvData, 0);
(lvItem);
}
#endregion
();
pDict = null ;
();
perDict = null ;
}
///
/// 执行查询
///
/// 查询语句
///
private ManagementObjectCollection ExecSearch(string command)
{
ManagementObjectCollection moc = null ;
ObjectQuery objQuery = new ObjectQuery (command);
string stringMachineName = "localhost" ;
ManagementScope scope = new ManagementScope ("" +
stringMachineName + "rootcimv2" );
ManagementObjectSearcher searcher = new ManagementObjectSearcher
(scope, objQuery);
try
{
moc = ();
}
catch (Exception x)
{
MessageBox .Show("Error:" + e);
}
return moc;
}
private void btClose_Click(object sender, EventArgs e)
{
this .Close();
}
WMI 的一个实现
原文出处:Code Project:Windows Management Instrumentation (WMI)
Implementation
源代码下载:(45KB)
介绍
这是我在继上一篇文章"My Explorer"之后关于Windows Management
Instrumentation(Windows管理规范)的又一新作。我将向你展示一些技巧,让你可以在远程地访问网络中其他计算机的操作系统、服务、当前运行着的进程等等信息,当然前提是你必须得拥有这些计算机的管理员权限。同时我也将向你展示如何利用WMI来启动或者停止服务、终止进程、创建进程。这是程序的主界面:
开始
在这个WMI应用程序里,我创建了一个包含了四个用户控制的库WMIControlLibrary。这四个用户控制分别是Explorer,SystemInfo,Services与Processes。每个控制都有其特定的功用。以下是对每个控制作用的一个简单描述:
Explorer控制 我把我那个"My Explorer"转换成了一个用户控制,它还是用来显示你系统上的驱动器、目录、文件等信息。
SystemInfo 控制* 这个控制用来显示操作系统与硬件数据及清单等信息。
Services 控制* 这个控制用来显示系统当前运行着的服务。
Process 控制* 这个控制用来显示系统当前运行着的进程。
(*注意:这个控制可以用来监控本地或者网络上的远程系统。)
上述的每个控制都引用了ment命名空间,以保证它们能访问各自特定的系统信息。
控制的状态事件
这其中的一些控制需要点时间才能从系统获取相关的信息,因此我在每个控制中都实现了一个事件UpdateStatus(string e)。这样每个控制就可以更新主应用程序窗体的状态条,用户也能很清楚地知道控制正在干什么了。
//控制内部的代码
//声明一个Status的事件委托类型
public delegate void Status(string e);
//声明了一个更新状态的事件
public event Status UpdateStatus;
//更新状态条
UpdateStatus("Hello world.");
//主程序代码
//用参数中的字符串刷新状态条的显示文本
private void refreshStatusBar(string stringStatus)
{
//更新状态条
= stringStatus;
}
Explorer 控制
在Explorer控制内部,我使用了WMI的Win32_LogicalDisk类来访问所有本地的及网络映射的驱动器。要访问驱动器的相关信息,我得先使用一个ManagementObjectSearcher对象来获取一个包含了我所需驱动器信息的ManagementOjbectCollection对象(译注:原文用的是class,我认为不准确,因此改译为对象)。之后,我们就可以自由支配所有这些驱动器的信息。(比如驱动器名、类型、卷标、标识等等)。你也可以只查询剩余空间低于1MByte的驱动器的信息,对此只需要改变ManagementObjectSearcher参数而已:
//译注:这句就是查询剩余空间低于1MByte的SQL语句,用在ManagementObjectSearcher的构造时。
//是不是很象一般数据库编程里用的SQL语句啊?
Select * From Win32_LogicalDisk Where FreeSpace < 1000000
//取得驱动器集
ManagementObjectSearcher query =
new ManagementObjectSearcher
("SELECT * From Win32_LogicalDisk ");
ManagementObjectCollection queryCollection = ();
//遍历每个对象,以获取每个驱动器的信息
foreach ( ManagementObject mo in queryCollection)
{
switch (( mo["DriveType"].ToString()))
{
case Removable: //可移动驱动器
imageIndex = 5;
selectIndex = 5;
break;
case LocalDisk: //本地驱动器
imageIndex = 6;
selectIndex = 6;
break;
case CD: //CD-ROM驱动器
imageIndex = 7;
selectIndex = 7;
break;
case Network: //网络驱动器
imageIndex = 8;
selectIndex = 8;
break;
default: //缺省:文件夹
imageIndex = 2;
selectIndex = 3;
break;
}
//获取驱动器名
ine("Drive: " + mo["Name"].ToString());
}
SystemInfo 控制
SystemInfo控制用于显示你的本地计算机或者远程计算机上一些不同类型的信息。它首先定义一个ConnectionOptions对象,并设置好该对象的UserName与Password属性,准备用此来建立一个WMI的连接。之后再以该ConnectionOptions对象为参数,使用本地或远程计算机的主机名创建一个ManagementScope对象。
//建立远程计算机连接
ConnectionOptions co = new ConnectionOptions();
me = ;
rd = ;
//将管理范围确定为该远程计算机
mentScope ms = new
mentScope
("" + stringHostName +
"rootcimv2", co);
现在我们就要准备通过创建一个ObjectQuery 成员对象来访问这个系统上的信息了。我们需要利用这个ObjectQuery对象和之前的那个ManagementScope对象来创建一个ManagementObjectSearcher对象。然后再
调用该ManagementObjectSearcher对象的Get()方法来执行ObjectQuery对象定义的那个查询命令,并将查询结果返回到一个ManagementObject对象集中。
//查询操作系统信息
oq = new Query("SELECT * FROM
Win32_OperatingSystem");
query = new ManagementObjectSearcher(ms,oq);
queryCollection = ();
foreach ( ManagementObject mo in queryCollection)
{
//在树中创建一个操作系统的子结点
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这些对象。你只需要用SQL查询语句串创建一个ManagementObjectSearcher对象,然后直接调用该对象的Get()方法,就能以一个ManagementObjectCollection对象的形式返回本地主机的信息了。
ManagementObjectSearcher query = new
ManagementObjectSearcher("SELECT * From
Win32_OperatingSystem");
ManagementObjectCollection queryCollection = ();
SystemInfo控制也用于显示计算机相关的其他信息:系统制造商,处理器,BIOS,时区,内存、网络连接、显卡等等。用于查询这些信息的代码只是在SQL
查询语句和返回属性上不同而已,所以为了减少篇幅我就不把代码写出来了。具体的代码你可以看下载包里的内容。
Service 控制
Service控制使用了这样的一个查询来返回系统中所有服务的信息:
SELECT * FROM Win32_Service
为了能启动或者停止一个服务,我为ListView动态地创建了一个弹出式菜单(上下文菜单)。你在列表的某个项上单击鼠标右键时,一个启动或停止服务(依赖于服务的当前运行状态)的菜单就会弹出。当菜单项被点击后,我需要利用这样的查询语句获得该服务的ManagementObject对象:
SELECT * FROM Win32_Service WHERE Name = ''ServiceName''
接着我就可以通过调用Method()方法来启动或者停止该服务了。InvokeMethod()方法的第一个参数是一个Observer。我传递一个ManagementOperationObserver对象给这个方法,来管理这些异步操作,以及相应的异步事件与信息。通过检查返回的Object的returnValue属性,我们就可以确定操作是否成功了。
///
/// List view的鼠标右击事件导致动态上下文菜单的生成
///
private void listViewServices_MouseDown(object sender,
ventArgs e)
{
ew listViewObject =
(ew) sender;
ContextMenu mnuContextMenu = new ContextMenu();
MenuItem menuItem = new MenuItem();
ManagementObjectCollection queryCollection;
//是否是鼠标右键单击
if ( == )
{
//取得服务的名称
ServiceName = mAt(e.X, e.Y).Text;
//取得列表项
ServiceItem = mAt(e.X,e.Y);
//创建弹出式菜单
tMenu = mnuContextMenu;
try
{
//取得特定的服务对象
queryCollection = getServiceCollection("SELECT *
FROM Win32_Service Where Name =
''" + ServiceName + "''");
foreach ( ManagementObject mo in queryCollection)
{
//据服务的当前状态创建相应的菜单
if (mo["Started"].Equals(true))
{
= "Stop";
//设置动作Action属性
ServiceAction = "StopService";
}
else
{
= "Start";
ServiceAction = "StartService";
}
(menuItem);
// 给菜单项挂上事件处理函数
+= new
andler(em_Click);
}
}
catch (Exception e1)
{
("Error: " + e1);
}
}
}
///
/// List view上下文菜单的事件响应函数
///
///
///
private void menuItem_Click(object sender, rgs e)
{
ManagementObjectCollection queryCollection;
ListViewItem lvItem;
//设置一个异步回调函数的句柄
ManagementOperationObserver observer = new
ManagementOperationObserver();
ler completionHandlerObj = new
ler();
Ready += new
ObjectReadyEventHandler();
//获得特定的服务对象
queryCollection = getServiceCollection("Select * from
Win32_Service Where Name =''" +
ServiceName + "''");
//更新状态条
updateStatus("Starting/");
foreach ( ManagementObject mo in queryCollection)
{
//启动或者停止服务
Method(observer, ServiceAction, null);
}
//等待,直到invoke调用完成或者超时5秒后
int intCount = 0;
while(!lete)
{
if
(intCount > 10)
{
("Terminate process timed out.",
"Terminate Process Status");
break;
}
//等待0.5秒
(500);
//增加计数器
intCount++;
}
//检查是否成功执行了
if
(ties["returnValue"].ng() == "0")
{
//成功
lvItem = ServiceItem;
if (ServiceAction == "StartService")
ms[2].Text = "Started";
else
ms[2].Text = "Stop";
}
else
{
//错误信息
string stringAction;
if (ServiceAction == "StartService")
stringAction = "start";
else
stringAction = "stop";
("Failed to " + stringAction + " service
" + ServiceName + ".",
"Start/Stop
Service Failure");
}
//清除对象
ServiceName = "";
ServiceAction = "";
ServiceItem = null;
//更新状态条
updateStatus("Ready");
();
}
//----------------------------------
// 完整的处理器
//----------------------------------
using System;
using ment;
namespace completionHandler
{
///
/// MyHandler类在InvokeMethod()调用完成后处理通知
///
public class MyHandler
{
private bool isComplete = false;
private ManagementBaseObject returnObject;
///
/// 当InvokeMethod完成后触发Done事件
///
public void Done(object sender, ObjectReadyEventArgs e)
{
isComplete = true;
returnObject = ect;
}
///
/// 取IsComplete属性
///
public bool IsComplete
{
get
{
return isComplete;
}
}
///
/// 属性允许访问主函数里的返回结果
///
public ManagementBaseObject ReturnObject
{
get
{
return returnObject;
}
}
}
}
Process 控制
Process控制显示系统中运行着的进程,启动进程的用户,CPU使用率,内存的使用情况。要获得进程的用户信息,需要调用GetOwner(User, Domain)方法,其中的User 与Domain是传出参数。我们如何才能从InvokeMethod()调用中取回这些传出型参数呢?这实际取决于我们是如何实现这个InvokeMethod()方法的。如果我们不需要管理异步操作,那么我们只需要传递一个string数组给InvokeMethod()以获取传出的参数值。否则,我们就无需给InvokeMethod()传
递任何的参数了,而是从Object属性中取回传出的参数值。
//-------------------------------------------------
//在不使用observer对象的情况下获取进程用户信息
//--------------------------------------------------
//为InvokeMethod()方法准备参数表
string[] methodArgs = {"", ""};
//获取进程用户信息
Method("GetOwner", methodArgs);
//methodArgs[0] 进程用户
//methodArgs[1] 进程的域
//-----------------------------------------------
//在使用observer对象的情况下获取进程用户信息
//-----------------------------------------------
Method(observer,"GetOwner", null);
while (!lete)
{
(500);
}
if (Object["returnValue"].
ToString() == "0")
UserName = completionHandlerObj.
ties["User"].ng();
else
UserName = "";
终止进程
终止一个特定的进程与启动或停止一个服务类似。首先还是要取得选中进程对应的 ManagementObject 对象,然后通过调用InvokeMethod(observer,
"Terminate", null) 来杀死一个进程。
//设置一个异步回调的句柄
ManagementOperationObserver observer = new
ManagementOperationObserver();
ler completionHandlerObj = new
ler();
Ready += new
ObjectReadyEventHandler();
//获取进程的ManagementObject
queryCollection = getProcessCollection("Select * from
Win32_Process Where ProcessID =
''" + ProcessID + "''");
//更新状态条
updateStatus("Invoking terminate process");
foreach ( ManagementObject mo in queryCollection)
{
//启动或者停止服务(译注:作者真懒?)
Method(observer, "Terminate", null);
}
//等待,直到invoke调用完成或者超时5秒后
int intCount = 0;
while (!lete)
{
if (intCount == 10)
{
("Terminate process timed out.",
"Terminate Process Status");
break;
}
//等待0.5秒
(500);
//增加计数器
intCount++;
}
if (intCount != 10)
{
//InvokeMethod尚未超时
if
(ties["returnValue"].ng() == "0")
{
lvItem = ProcessItem;
();
}
else
{
("Error terminating process.",
"Terminate Process");
}
}
创建进程
要创建一个进程,我们需要调用ManagementClass 的InvokeMethod ()方法。我们可以这么创建一个ManagementClass对象:
ManagementClass processClass = New
ManagementClass(ms,path,null);
其中的ms是一个ManagementScope对象,path是一个ManagementPath对象。ManagementScope对应了一个管理操作对应的范围。ManagementPath则提供了一个对Win32_Process进行解析与创建的封装。在调用Method(observer, methodName, inParameters)之前,我们还需要做点其他的准备。我们得把四个传入参数封装到一个object数组里。
uint32 Create(string CommandLine,
string CurrentDirectory,
Win32_ProcessStartup
ProcessStartupInformation,
uint32* ProcessId);
参数说明
CommandLine - [传入] 要执行的命令行。如果有必要,系统会自动在末尾追加一个null字符来截断该串,表示真正要执行的文件。
CurrentDirectory - [传入] 子进程的当前驱动器与当前目录。这个串必须保证当前目录能解析到一个已知的路径。用户可以定义一个绝对的或相对的路径作为当前的工作目录。如果该参数为null,新创建的进程就会使用父进程的同一路径。这样做是主要是为了保证操作系统外壳能确定应用程序启动的初始驱动器和工作目录。
ProcessStartupInformation - [传入] 这是一个Windows进程的启动配置,请参见Win32_ProcessStartup.
ProcessId - [传出] 一个全局的用于标识进程的标识符。这个值的生存期自进程创建时起,至进程终结时止。
//为InvokeMethod()准备参数
object[] methodArgs = {stringCommandLine, null, null, 0};
//执行这个方法
Method (observer, "Create", methodArgs);
下面是创建进程的实现代码。我编写了一个CreateProcess()函数接受一个传入的命令行字符串stringCommandLine作为参数。当你调用CreateProcess("")时,就意味着创建了一个新的计算器的进程。就这么简单。
///
/// 在一个本地或者远程机器上调用Create方法
///
///
private void CreateProcess(string stringCommandLine)
{
//设置一个异步回调的句柄
ManagementOperationObserver observer = new
ManagementOperationObserver();
ler completionHandlerObj = new
ler();
Ready += new
ObjectReadyEventHandler();
string stringMachineName = "";
//连接到远程计算机
ConnectionOptions co = new ConnectionOptions();
if (d == true)
{
stringMachineName = "localhost";
}
else
{
stringMachineName = ;
}
if (().Length == 0)
{
("Must enter machine IP address or
name.");
return;
}
//获取用户名与密码
if (().Length > 0)
{
me = ;
rd = ;
}
//获取指向机器的接入点
mentScope ms = new
mentScope("" +
stringMachineName + "rootcimv2", co);
//获取进程的路径
ManagementPath path = new ManagementPath( "Win32_Process");
//获取将要被调用的进程的对象
ManagementClass processClass = new
ManagementClass(ms,path,null);
//更新状态条
updateStatus("Create process " + stringCommandLine + ".");
//为方法准备参数
object[] methodArgs = {stringCommandLine, null, null, 0};
//执行方法
Method (observer, "Create",
methodArgs);
//等待,直到invoke调用完成或者超时5秒后
int intCount = 0;
while (!lete)
{
if (intCount > 10)
{
("Create process timed out.",
"Terminate Process Status");
break;
}
//等待0.5秒
(500);
//增加计数器
intCount++;
}
if (intCount != 10)
{
//InvokeMethod尚未超时
//检查是否出现错误
if
(ties["returnValue"].ng() == "0")
{
//刷新进程列表
h();
}
else
{
("Error creating new process.",
"Create New Process");
}
}
//更新状态条
updateStatus("Ready");
();
}
总结
编写这个演示用的WMI应用程序,增加了我不少的经验。这只展示了WMI很小一部分的功能。我想有了我给出的注释,代码还容易理解吧。
你可以使用WMI完成下列工作:
控制硬件与软件
监控事件
就某个事件运行一个脚本
就某个事件发出一封Email
MSDN 中关于WMI的内容:Windows Management Instrumentation
WMI基本知识(进程管制)
发布时间: 2009-8-15 00:00 | 发布作者: 东莞祥哥 | | 查看: 20次
一:WMI基本学识
====================================================================================
WMI 最初于1998年作为唯一附加组件与 Windows NT 4.0 Service Pack 4 一起发行,是内置在Windows 2000、 Windows XP和Windows Server 2003 集锦操作系统中核心的管制支持技能。基于由 Distributed Management Task Force (DMTF) 所监督的业界达标,WMI是一种规范和基本框架,经过它能够来访、配置、管制和监视几乎所有的Windows资源。大多用户习惯于应用众多的图形化管制道具来管制Windows资源,在WMI之前这一部份道具都是经过 Win32实际运用程式编程接口(Application ProgrammingInterfaces,API)来来访和管制Windows资源的。只要你熟悉操作系统编程你就明白API有多么重要。但是大多数脚本语句语言都别直接调用Win32 API,WMI的呈现使得操作系统管制员能够经过一种简便的窍门即利用日常学识的脚本语句语言呈现日常的操作系统管制任务。
利用WMI需求和脚本如WSH和VBScript结合起来,能够呈现的功能大部份人能够看微软集团公司的MSDN文档。
在编写咱们自个的脚本之前,咱们需求对WMI的体系框架有个基本的了解。如图一:()
在WMI 体系框架中咱们最需求关心的就WMI帮助程式,WMI帮助程式在WMI和托管资源之间扮演着中间方的角色。帮助程式代表应用者实际运用程式和脚本从WMI托管资源请求消息,并发送命令到WMI托管资源。下面是咱们利用WMI编程经常要用到的WMI内置帮助程式清单,以供编程参考。
Directory帮助程式
链接库文档:
命名空间:rootdirectoryldap
功能:将Active Directory 对象映射到 WMI。
2.事件日志帮助程式
链接库文档:
命名空间:rootcimv2
功能:管制 Windows 事件日志,例如,读取、备份、清除、复制、删除、监视、重命名、压缩、解压缩和更改事件日志设置。
3.注册表帮助程式
链接库文档:
命名空间:rootdefault
功能:读取、写入、枚举、监视、创建、删除注册表项和值。
32 帮助程式
链接库文档:
命名空间:rootcimv2
功能:帮助涉及电脑、磁盘、外围设备、文档、文档夹、文档操作系统、互联网组件、操作系统、打印机、进程、安全safe性、效劳、共享、SAM 用户及组,以及更多资源的消息。
s 安装程式帮助程式
链接库文档:
命名空间:rootcimv2
功能:帮助对已安装热门软件消息的来访。
从上面能够看出在WMI中类(即内置帮助程式)被分组到命名空间中,命名空间能够看成是唯一组。比如,命名空间 rootcimv2 包括大部份表明通常与电脑和操作系统有联系联的资源的类。在应用类的时候要说明类所在的命名空间。类由属性和窍门构成。这是可视化编程中的两个重要的概念。属性描述的是对象的状态,窍门是对象能够执行的操作。
理论学识学起来很枯燥,下面让咱们边考虑水平很高的人的脚本源代码边停止理论学识的巩固吧。
二:解析主要代码Code
=====================================================================================
有时候泛读更多有联系人的源代码未尝否则唯一好而且快捷的办法,下面就让咱们来认真研究zzzEVAzzz编写的唯一能够远程开启telnet效劳的脚本。
该脚本能够直接来访目的的WMI,不依赖于目的的ipc$,呈现远程开启/关闭目的telnet效劳,为了方便大部份人研究我抽出了最主要的代码Code,具体考虑如下:
set objlocator=createobject("ocator")
//创建ocator对象(脚本接口)。
//能够看出WMI其实就把Com组件ocator封装起来罢了。
set
objswbemservices=tserver(ipaddress,"root/default",username,password)
//经过ConnectServer参数请求连接到WMI控件效劳上,root/default为命名空间。
set objinstance=("stdregprov")
//建立来访注册表的举例。
set objmethod=s_("SetDWORDvalue")
//建立能够更改注册表键值的窍门。
set objinparam=nstance_()
//meters用于获取或设置窍门的输入参数parameter。那里用spawninstance窍门为它建立唯一子举例,下面就能够将参数parameter值赋予那个对象的属性。
y=&h80000002
//hdefkey表明根键,根键的十六制值如下:
//HKEY_CLASSES_ROOT (&H80000000)
//HKEY_CURRENT_USER (&H80000001)
//HKEY_LOCAL_MACHINE (&H80000002)
//HKEY_USERS (&H80000003)
//HKEY_CURRENT_CONFIG (&H80000005)
yname="SOFTWAREMicrosoftTelnetServer1.0"
//ssubkeyname表明子键。
name="NTLM"
//svaluename表明属性名。
=ntlm
//uvalue表明键值。
set objoutparam=thod_("SetDWORDvalue",objinparam)
//利用execmethod执行窍门,那里才真正改写了注册表。
//下面是改正telnet效劳的TelnetPort值,思想同上。
name="TelnetPort"
=port
set objoutparam=thod_("SetDWORDvalue",objinparam)
改正telnet的注册表部份就完成了,将NTLM和TelnetPort停止了改正,要是对方的telnet效劳没有开启呢?下面就需求根据telnet的具体情况,来启动telnet效劳,继续看代码Code。
//首先查询远程主机上tlntsvr的启动方法。
set
objswbemservices=tserver(ipaddress,"rootcimv2",username,password)
//win32_service类在rootcimv2命名空间中,功能没忘记吧?快看基本学识呵。
set colinstances=ery("select * from win32_service where
name='tlntsvr'")
//留意:查询都是经过枚举来呈现的。
for each objinstance in colinstances
if ode="Disabled" then
set objmethod=s_("changestartmode")
//创建changestartmode窍门来改变tlntsvr的启动方法。
set objinparam=nstance_()
ode="Manual"
//将启动方法改为手动方法。
set objoutparam=thod_("changestartmode",objinparam)
end if
//下面启动咱们的telnet效劳。那里zzzEVAzzz的思维好象有点不对,也不明白是否则他的疏忽,我个体以为当telnet效劳已经启动时不因该用stopservice窍门停止效劳。
if d=true then
intstatus=rvice()
//stopservice是WMI中用于停止效劳举例的效劳的窍门。
else
intstatus=ervice()
end if
next
三:手把手教你编写WMI版本的来开启3389
=====================================================================================
zzzVEAzzz 的脚本就考虑到那里吧,怎样样?很EASY吧?!我相信大部份人目前一定蠢蠢欲动了?:)好,一起来写唯一什么程式呢?我想大部份人一定都用过吧?什么东东啊?我……砸!大部份人因该明白那个ROTS是有它的应用要求的,不仅要有管制员帐号,还要允许停止ipc连接,在那个到处都是墙的年代,ipc 早就不实战了,而且早就被查杀了,那该怎样办?当然是自个动手了。能别呈现ROTS的相同的远程开启3389的功能而不受ipc的控制呢?答案自从我写了这篇文字作品后成了肯定的,哈哈,吹吹了。
当然咱们也是要求操作系统至少是2000server及以上的,最近看到有个热门软件能够给
2000pro开3389,由于较量忙,也没怎样去理它,那里咱们暂且不说它,明白了思想相同好办。
开启3389有个注册表导入的窍门,其它一部份热门软件的开法,我想也大多是经过改正注册表呈现的。那个窍门需求导入如下的注册表:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionnetcache]
"Enabled"="0"
[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionWinlogon]
"ShutdownWithoutLogon"="0"
[HKEY_LOCAL_MACHINESOFTWAREPoliciesMicrosoftWindowsInstaller]
"EnableAdminTSRemote"=dword:00000001
[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlTerminal Server]
"TSEnabled"=dword:00000001
[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesTermDD]
"Start"=dword:00000002
[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesTermService]
"Start"=dword:00000002
[HKEY_TKeyboard LayoutToggle]
"Hotkey"="1"
思想明白了就没什么难的了,先理清咱们的思维,咱们的主要任务是更改注册表里的键值。首先是创建WMI对象,然后是连接到远程WMI效劳器,最后改正注册表键值。
部份主要代码Code如下(完整的代码Code和详细的注释请看附带的热门软件包)
on error resume next
//防止呈现意外。
set outstreem=
if (lcase(right(me,11))="") then
set objShell=Object("")
(" /k cscript //nologo "&chr(34)&fullname&chr(34))
//cmd后带/K参数parameter表明执行字符串指定的命令。
end if
//停止简单的检查。
if <3 then
usage()
"Not enough parameters."
end if
//取出参数parameter,分别赋予几个变量。
ipaddress=nts(0)
username=nts(1)
password=nts(2)
option=nts(3)
usage()
下面是核心代码Code,也是呈现远程改正注册表的功能,我那里给出另外一种呈现的方法,对比前面的代码Code很简易理解,我就只作简单的解释了。详细情况能够参阅MSDN文档中涉及StdRegProv类的说明。
(/library/?url=/library/en-us/wmisdk/wmi/)
const HKEY_LOCAL_MACHINE = &H80000002
const HKEY_USERS=&H80000003
strComputer = ipaddress
//获取wmi对象
Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!" &_
strComputer & "rootdefault:StdRegProv")
strKeyPath = "SOFTWAREMicrosoftWindowsCurrentVersionnetcache"
strValueName = "Enabled"
strValue=0
RDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
strKeyPath = "SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon"
strValueName = "ShutdownWithoutLogon"
strValue=0
RDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
strKeyPath = "SOFTWAREPoliciesMicrosoftWindowsInstaller"
strValueName = "EnableAdminTSRemote"
strValue=1
RDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
strKeyPath = "SYSTEMCurrentControlSetControlTerminal Server"
strValueName = "TSEnabled"
strValue=1
RDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
strKeyPath = "SYSTEMCurrentControlSetServicesTermDD"
strValueName = "Start"
strValue=2
RDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
strKeyPath = "SYSTEMCurrentControlSetServicesTermService"
strValueName = "Start"
strValue=2
RDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
strKeyPath = ".DEFAULTKeyboard LayoutToggle"
strValueName = "Hotkey"
strValue=1
RDValue HKEY_USERS,strKeyPath,strValueName,strValue
//下面呈现重启远程机器
if option="/r" then
"Now, "
strwmiquery="select * from win32_operatingsystem where primary='true'"
set colinstances=ery(strwmiquery)
for each objinstance in colinstances
32shutdown(2)
end if
"Ok, rebooted the target."
//简单的应用办法说明的参数。
function usage()
string(60,"=")
"Wmi3389 v1.0.0"
"No ipc Open 3389, code written by pye."
"******************************************************.cn"
"Usage:"
"cscript "&fullname&" targetIP username password [/r]"
"/r reboot the target this is optional"
"It use WMI to Open 3389 of target server."
string(60,"=")&vbcrlf
end function
将上面的代码Code复制带记事本里,保存为。然后在CMD里执行:
cscript ipaddress administrator password [/r]
看看是否则和有相同的效果啊?大部份人赶快实践实践吧。
四:最后的唠叨
=====================================================================================
大部份人能够看出WMI的功能是很强大的,那里要感谢MicroSoft了,它是永远都不会让咱们失望的。WMI对象允许经过VB,VBA,WSH, VBScript, JScript,asp,或是支持自动对象的其它环境,对WMI停止完全来访。在参考查询体系中加入 WMI Scripting V1.1
Library ,则Visual Basic或是VBA方案就能够来访这一部份对象了。支持ActiveX程式的操作平台能够经过对象类的代号,或是类的名字创建这一部份对象,这一部份对象的前缀是WbemScripting,如 ocator。所以大部份人有兴趣的完全能够利用VB,WSH,VBScript, JScript,asp等编写更多的利用WMI的黑客程式。
WMI For C++/COM 调用方法
Win32 Provider不仅仅提供类和实例的信息,而且有些Provider会提供了一些方法,供用户调用。调用方法的流程如下:
1)取得Provider实例对象
调用IWbemServices::GetObject方法可以取得我们想要调用的Provider类型实例,他以一个IWbemClassObject类型指针返回。
BSTR MethodName = SysAllocString(L"Create");
BSTR ClassName = SysAllocString(L"Win32_Process");
IWbemClassObject* pClass = NULL;
hres = pSvc->GetObject(ClassName, 0, NULL, &pClass, NULL);2)取得Provider提供方法参数
调用IWbemClassObject::GetMethod方法可以取得我们想要调用方法的参数,他以一个IWbemClassObject类型指针返回。
IWbemClassObject* pInParamsDefinition = NULL;
hres = pClass->GetMethod(MethodName, 0,
&pInParamsDefinition, NULL);3)生成Provider提供方法的参数的对象
调用IWbemClassObject::SpawnInstance方法生成调用方法的参数实例。需要将第二步得到的参数类型指针调用这个SpawnInstance方法,并且传递给该方法一个IWbemClassObject指针作为生成的参数对象的指针。
IWbemClassObject* pClassInstance = NULL;
hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);4)设置参数对象的属性
调用IWbemClassObject::Put方法就可以设置参数对象的类型。
VARIANT varCommand;
= VT_BSTR;
l = L"";
hres = pClassInstance->Put(L"CommandLine", 0,
&varCommand, 0);
wprintf(L"The command is: %s ", V_BSTR(&varCommand));5)调用方法
与查询信息相同,调用方法也可以分为同步方式和异步方式,同步方式等待执行进程结束,才继续往下执行;异步方式则利用实现IWbemObjectSink接口的类型,创建一个新的线程后继续运行当前线程,而由新创建的线程完成调用方法,然后回调IWbemObjectSink::
Indicate函数,处理函数返回值。
以下是以同步方式调用IWbemServices::ExecMethod方法即调用Provider提供的方法,将之前生成的关于参数的实例传给该方法即可。
IWbemClassObject* pOutParams = NULL;
hres = pSvc->ExecMethod(ClassName, MethodName, 0,
NULL, pClassInstance, &pOutParams, NULL); 以下是以异步方式调用同样的Provider的函数,不同于同步方式,异步方式调用IWbemServices::ExecMethodAsync方法,第三个参数IFlag可以设置为WBEM_FLAG_SEND_STATUS以接受调用时中间状态信息,没有输出参数(本例中是pOutParams),最后一个参数是实现IWbemObjectSink接口的类型。
QuerySink *pSink = r: rgb(0, 0, 255);">new QuerySink();
hres = pSvc->ExecMethodAsync(ClassName, MethodName,
WBEM_FLAG_SEND_STATUS,
NULL, pClassInstance, pSink); 但是调用方法比查询信息多出一种半同步方式,由于同步方法使得调用者线程等待方法执行完,而异步方法则需要编程人员继承IWbemObjectSink接口并进行多线程编程,所以半同步方式则是以一种折中的方法进行IWbemServices实例中方法的调用,创建一个线程去查询,然后写入一个IWbemCallResult接口的实例中,由主线程去查询。
IWbemCallResult *pCallRes = 0;
IWbemClassObject *pObj = 0;
hres = pSvc->ExecMethod(ClassName,
WBEM_FLAG_RETURN_IMMEDIATELY,
NULL, pClassInstance,NULL, &pCallRes);
while (true)
...{
LONG lStatus = 0;
HRESULT hRes = pCallRes->GetCallStatus(5000, &lStatus);
if ((hRes == WBEM_S_NO_ERROR))
break;
if ((hRes == WBEM_S_TIMEDOUT))
continue;
}
hres = pCallRes->GetResultObject(5000, &pObj);
if (hres)
_429_467_Open_Text').y='inline';" style="display:
src="/syntaxhighlighting/OutliningIndicators/"
id="_429_467_Closed_Image" alt="" /> ...{
pCallRes->Release();
return 1;
}
VARIANT varReturnValue;
hres = pObj->Get(_bstr_t(L"ReturnValue"), 0,
&varReturnValue, NULL, 0);
cout << << endl;
pCallRes->Release();
pObj->Release();
以上就是通过WMI调用方法的基本形式,在XP下,调用方法的功能比较少,但是在Vista下,Windows在rootwmi命名空间中提供了一些Provider和方法,代替了一些none;"
MethodName,
本来由驱动做的事情。
但是比较遗憾的是,MSDN上一些文档与MS提供的WMI Tool所实际体现的数据不一致,像WmiSetBrightnessMethods类的SetBrightness方法的两个参数就有这样的情况,uint8和uint64好像也是为dotNet平台所准备的一样,在Put进去这两个参数后,hres 返回S_OK,但是在execMethod时,就会出现类型不匹配的错误,让人比较挠头~希望如果有朋友路过且恰巧知道如何用C++COM调用这个方法可以给我留言,或者加我QQ,十分感谢!
从WMI看VC++到.Net的变迁
WMI(Windows Management Instrumentation)是Windows下可以与系统信息(包括软硬件等)的一个管理框架,通过WMI可以很方便地对机器进行管理。现在以通过WMI来打开(或创建)一个记事本()进程为例,看看VC++到.Net的变迁,一览.Net是如何让程序员从繁琐晦涩的程序中解放出来。
1、预工作:
VC++中需要在源代码中加入:
#include
#pragma comment(lib, "")
VC#中需要:
在工程中添加引用:ment
在代码中加入using ment;
2、流程:
VC++的代码,需要6步和查询返回值、最后释放资源:
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
hres = CoInitializeSecurity(
NULL,
-1, // COM negotiates service
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLoc);
// Step 4: ---------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the local rootcimv2 namespace
// and obtain pointer pSvc to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOTCIMV2"),
NULL,
NULL,
0,
NULL,
0,
0,
&pSvc
);
// Step 5: --------------------------------------------------
// Set security levels for the proxy ------------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE // proxy capabilities
);
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// set up to call the Win32_Process::Create method
BSTR MethodName = SysAllocString(L"Create");
BSTR ClassName = SysAllocString(L"Win32_Process");
IWbemClassObject* pClass = NULL;
hres = pSvc->GetObject(ClassName, 0, NULL, &pClass, NULL);
IWbemClassObject* pInParamsDefinition = NULL;
hres = pClass->GetMethod(MethodName, 0,
&pInParamsDefinition, NULL);
IWbemClassObject* pClassInstance = NULL;
hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);
// Create the values for the in parameters
VARIANT varCommand;
= VT_BSTR;
l = L"";
// Store the value for the in parameters
hres = pClassInstance->Put(L"CommandLine", 0,
&varCommand, 0);
wprintf(L"The command is: %sn", V_BSTR(&varCommand));
// Execute Method
IWbemClassObject* pOutParams = NULL;
hres = pSvc->ExecMethod(ClassName, MethodName, 0, NULL, pClassInstance, &pOutParams, NULL);
// Get return value
VARIANT varReturnValue;
hres = pOutParams->Get(_bstr_t(L"ReturnValue"), 0, &varReturnValue, NULL, 0);
// Last: clean up
VariantClear(&varCommand);
VariantClear(&varReturnValue);
SysFreeString(ClassName);
SysFreeString(MethodName);
pClass->Release();
pInParamsDefinition->Release();
pOutParams->Release();
pLoc->Release();
pSvc->Release();
CoUninitialize();
VC#只需寥寥数行就可以实现(暂不考虑错误处理):
跳过VC++中的Step1~5,直接从Step6开始。而且非常直观:
ManagementClass mc = new ManagementClass("Win32_Process");
ManagementBaseObject obj = hodParameters("Create");
obj["CommandLine"]="";
Method("Create", obj, null);
e();
.Net对WMI良好的封装,还有对字符串的更强支持、方便的垃圾回收机制,使程序既一目了然,又易于维护。其实类似的区别在VC vs VB年代已经出现了(特别是在COM组件编写和调用方面可以看出),从这点也可以看出.Net完全继承了VB易学易用的特性,又不失强大的功能。
版权声明:本文标题:如何使用WMI获取进程信息 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1708361340h521411.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论