新客网WWW.XKER.COM:致力做中国最专业的网络学院!
学院: 操作系统 - 网络应用 - 服务器 - 网络安全 - 工具软件 - 办公软件 - Web开发 - 数据库 - 网页设计 - 图形图像 - 媒体动画 - 硬件学堂 - 存储频道 - QQ专区
您的位置:首页 > 软件开发 > Web开发 > Asp教程 > 正文:编程实现重起网卡等设备

编程实现重起网卡等设备

新客网 XKER.COM 2006-04-27 来源: 收藏本文
今天水木上有位朋友问我如何卸载WinPCap的驱动。因为此类驱动跟网卡绑定很紧密,卸载的时候最好是要把网卡重起一下(SnifferPro就是如此)。而重起网卡的程序实现又很少有资料介绍,前段时间好容易看到一篇文章,居然是用字符串查找到控制面板下面调用applet,呵呵,够狠 -_-b。刚好前几个月有同事有类似需求,我写过一个命令行下重起网卡的小工具,就把它翻出来大概介绍一下实现思路。
     
     首先是要找到需要操作的网卡的ID,这个功能实现的方法很多:最常见的是Winpcap的packet32.c里面提供的直接从注册表中枚举的方法;另外一种方法则是使用DDK中提供的Device Installation系列函数完成。
     枚举注册表的方法需要打开HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}注册表键,{4D36E972-E325-11CE-BFC1-08002bE10318}是Net类型设备的ID,下面每个子键定义一个网络设备,但只有一部分设备是网卡。具体处理方法请参见Winpcap的PacketGetAdapterNames函数。
     使用Device Installation API则首先用SetupDiGetClassDevs函数获取所有类型的设备,或者在此指定只获取特定类型设备。因为我那个程序原意是控制所有类型设备,就没有指定类型。
 
以下为引用:

 HDEVINFO m_hDevInfo = ::SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
 

    
     然后使用SetupDiEnumDeviceInfo枚举类型中所有的设备
 
以下为引用:

 SP_DEVINFO_DATA did = { sizeof(SP_DEVINFO_DATA) };  

 

 for(int i=0; ::SetupDiEnumDeviceInfo(m_hDevInfo, i, &did); i++)
 {
    //... 
 }
 


   

 

     在找到要处理的设备后,应该用CM_Get_DevNode_Status函数和注册表获取其状态,忽略被隐藏的设备。
 

以下为引用:

 bool CDeviceManager::IsClassHidden(const GUID *ClsGuid) const
 {
   HKEY hKeyClass = ::SetupDiOpenClassRegKey(ClsGuid, KEY_READ);
   
   bool hidden = false;
   
   if(INVALID_HANDLE_VALUE != hKeyClass)
   {
     hidden = ERROR_SUCCESS == ::RegQueryValueEx(hKeyClass, REGSTR_VAL_NODISPLAYCLASS, NULL, NULL, NULL, NULL);
     
     ::RegCloseKey(hKeyClass);
   }
   
   return hidden;
 }

 

 DWORD dwStatus = 0, dwProblem = 0;

 if(CR_SUCCESS != ::CM_Get_DevNode_Status(&dwStatus, &dwProblem, did.DevInst,0))
 {
   DisplayError("CM_Get_DevNode_Status");
   continue;
 }

 if(dwStatus & DN_NO_SHOW_IN_DM || IsClassHidden(&did.ClassGuid))
 {
   continue;
 }    
 


    
     对剩下的设备则根据其Class进行过滤,只处理Net类型设备,如果前面指定只获取Net设备则此步骤可以忽略。
 
以下为引用:

 

 const std::string CDeviceManager::GetProperty(SP_DEVINFO_DATA& did, DWORD Property) const
 {   
   std::string buf;
   DWORD dwLength = 0;

   while(!::SetupDiGetDeviceRegistryProperty(m_hDevInfo, &did, Property, NULL, 
     (PBYTE)buf.c_str(), buf.size(), &dwLength))
   {
     if(::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
     {
       buf.resize(dwLength * sizeof(wchar_t));
       std::fill(buf.begin(), buf.end(), '\0');
     }
     else
     {
       break;
     }
   }
   buf.resize(strlen(buf.c_str()));

   return buf;
 }

 if(stricmp(GetProperty(did, SPDRP_CLASSGUID).c_str(), "{4d36e972-e325-11ce-bfc1-08002be10318}") == 0)
 {
   // ...
 }
 


    
     满足上述限制的设备,就是我们要处理的网卡。可以直接修改其状态:SetupDiSetClassInstallParams函数设置参数;SetupDiCallClassInstaller完成参数修改。
 
以下为引用:

 bool CDeviceManager::ChangeDeviceState(SP_DEVINFO_DATA& did, DWORD State) const
 {
   SP_PROPCHANGE_PARAMS pcp = {sizeof(SP_CLASSINSTALL_HEADER)};
   
   pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
   pcp.Scope = (State == DICS_START || State == DICS_STOP )? DICS_FLAG_CONFIGSPECIFIC : DICS_FLAG_GLOBAL;
   pcp.StateChange = State; 

 

   if(!::SetupDiSetClassInstallParams(m_hDevInfo, &did, 
     (SP_CLASSINSTALL_HEADER *)&pcp, sizeof(pcp)))
   {
     DisplayError("SetupDiSetClassInstallParams");    
     return false;
   }
   
   //
   // Call the ClassInstaller and perform the change.
   //
   if(!::SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, m_hDevInfo, &did))
   {
     DisplayError("SetupDiCallClassInstaller");
   }
   return true;
 }

 ChangeDeviceState(did, DICS_STOP);    // 停止
 ChangeDeviceState(did, DICS_START);   // 启动
 ChangeDeviceState(did, DICS_ENABLE);  // 启用
 ChangeDeviceState(did, DICS_DISABLE); // 禁用

收藏】 【评论】 【推荐】 【投稿】 【打印】 【关闭
发表评论
要记得去论坛讨论,点击注册新会员匿名评论
评论内容:不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
阅读排行
随机推荐
实用信息推荐