C++ Builder,利用命令或API函数卸载COM口,在设备管理器中卸载COM 通信端口(或指定设备)

初学C++ Builder遇到的问题,问题描述如下:
个人发帖:

https://bbs.csdn.net/topics/391999974


1. 本人机器以前用过许多COM设备,使得再接入COM设备时,COM号不从最小的顺序开始,而是从之前使用过的开始。比如之前我使用了COM3/4/5/6,然后使用过以后,取下设备,再接其他COM设备时便从COM7/8/9 开始,COM7之前的COM号显示在使用中(而实际没有使用)。
2. 为解决以上问题,我尝试再注册表里清空注册表值,然后再试。结果COM7 之前的COM都被释放了(再没有显示折正在使用),但是COM设备的COM号依旧为 COM7/8/9。于是我在 设备管理器中 通过找到COM7/8/9并且手动卸载了COM设备,然后再选择  扫描检测硬件改动,发现COM设备 COM号正常的从 COM3/4/5/6 开始。
3.  综上,需要手动去点击卸载。因此在此请教 是否有WINDOWS 命令或者 可以用 API 函数来代替 卸载 COM设备。

----完整工程后续上传~

解决代码:

... ...

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#pragma comment(lib, "newdev.lib")
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "cfgmgr32.lib")
//#include <Newdev.h>
#include <setupapi.h>
#include "cfgmgr32.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------


bool __fastcall TForm1::EnumDevices(HDEVINFO hDevInfo)
{
  //TODO: Add your source code here

  SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)};
 // LPOLESTR guid;
  char devName[128];
  char instanceId[128];
  char DeviceName[128];
  char LocationDers[1024];
  int Dev_i = 0;

  for (int i=0;SetupDiEnumDeviceInfo(hDevInfo,i,&DeviceInfoData);i++)
  {
    SetupDiGetDeviceInstanceId(hDevInfo,&DeviceInfoData,instanceId,128,NULL);
M1:    Memo1->Lines->Add("M1: "+AnsiString(instanceId));
    SetupDiClassNameFromGuid(&DeviceInfoData.ClassGuid,devName,128,NULL);
    AnsiString TarGetDeviceGUID = GUIDToString(DeviceInfoData.ClassGuid);
M2:    Memo1->Lines->Add("M2: "+GUIDToString(DeviceInfoData.ClassGuid));
    AnsiString TarGetDeviceType = AnsiString(devName);
M3:    Memo1->Lines->Add("M3: "+AnsiString(devName));
    SetupDiGetDeviceRegistryProperty(hDevInfo,&DeviceInfoData,SPDRP_DEVICEDESC,NULL,DeviceName,128,NULL);
    AnsiString TarGetDeviceName = AnsiString(DeviceName);
M4:    Memo1->Lines->Add("M4: "+AnsiString(DeviceName));
    SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_LOCATION_INFORMATION, NULL, LocationDers, 1024, NULL);
M5:    Memo1->Lines->Add("M5: "+AnsiString(LocationDers));
    Memo1->Lines->Add("");
    TarGetDeviceType = TarGetDeviceType.UpperCase();
    IniCfg.DeviceType = IniCfg.DeviceType.UpperCase();
    if(0 == TarGetDeviceType.AnsiCompare(IniCfg.DeviceType)&& 0 == TarGetDeviceName.AnsiCompare(IniCfg.DeviceName) )
    {
      AnsiString DeviceNum = "Device "+IntToStr(++Dev_i);
      Report->Lines->Add(DeviceNum+" GUID: "+TarGetDeviceGUID);
      Report->Lines->Add(DeviceNum+" Type: "+TarGetDeviceType);
      Report->Lines->Add(DeviceNum+" Name: "+TarGetDeviceName);
      if (0 != SetupDiRemoveDevice(hDevInfo, &DeviceInfoData)) //移除设备
      Report->Lines->Add("Remove "+DeviceNum+" Success");
    }
    Application->ProcessMessages();
  }
  if(0 == Dev_i)
  {
    Report->Lines->Add("##Don't Find The COM Device");
    AllFlag = false;
    return false;
  }
  else
    return true;
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  AllFlag = true;
  Panel1->Color = clBtnFace;
  Button1->Enabled = false;
  Button2->Enabled = false;

  HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  hDevInfo = SetupDiGetClassDevs(NULL,NULL,NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES);
  if(INVALID_HANDLE_VALUE == hDevInfo)
          ShowMessage("hDevInfo Fail!");
  if(false == EnumDevices(hDevInfo))    //查找设备
  {
    Report->Lines->Add("##Uninstall COM Device Fail");
    AllFlag = false;
  }
  SetupDiDestroyDeviceInfoList(hDevInfo);
  EditRegister();  // 清理注册表
  UpdateDevice();  //更新设别 扫描检测硬件改动


  if(true == AllFlag)
  {
    Report->Lines->Add("#All Operation PASS");
    PassFun(Report,Panel1);
  }
  else
  {
    Report->Lines->Add("###All Test FAIL");
    FailFun(Report,Panel1);
  }

  if(1 == IniCfg.MRestart && true == AllFlag)
  {
    int t = Application->MessageBox("需要重启设备才能正常使用设备,是允许系统立即重启?","请做以下确认",MB_YESNO) ;
    if(ID_YES == t)
    {
      Report->Lines->Add("!!!!The system will restart");
      Shutdown();
    }
    else
      Report->Lines->Add("!!!!To cancel the restart");
  }
  else if(1 == IniCfg.AutoShowDown && true == AllFlag )
  {
    Report->Lines->Add("!!!!The system will restart");
    TmrDown->Enabled =true;
  }

  Button1->Enabled = true;
  Button2->Enabled = true;
  Report->Lines->Add("");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
  this->Close();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button3Click(TObject *Sender)
{
  if(FileExists("DeviceList.txt"))
    DeleteFile("DeviceList.txt");
  Memo1->Lines->SaveToFile("DevList.txt");
  ShowMessage("Save reslut success");
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
  Report->Clear();
  Memo1->Clear();
  TmrDown->Enabled = false;
  Timer1->Enabled = false;
  Timer2->Enabled = false;
  Panel1->Caption ="";
  Panel1->Color = clBtnFace;

  AnsiString BasePath = GetCurrentDir();
  TIniFile *Ini = new TIniFile(BasePath + "\\Setup.ini");
  IniCfg.AutoRun = Ini->ReadInteger("CfgIni","AutoRun",0);
  IniCfg.AutoClose = Ini->ReadInteger("CfgIni","AutoClose",0);
  IniCfg.AutoShowDown =Ini->ReadInteger("CfgIni","AutoRestart",0);
  IniCfg.ShutDownTime = Ini->ReadInteger("CfgIni","RestartTime",2);
  IniCfg.MRestart = Ini->ReadInteger("CfgIni","ManuallyRestart",1);
  IniCfg.DeveloperMode = Ini->ReadInteger("CfgIni","DeveloperMode",0);

  IniCfg.DeviceType = Ini->ReadString("CfgDevice","DeviceType","Ports");
  IniCfg.DeviceName = Ini->ReadString("CfgDevice","DeviceName","通信端口");
  delete Ini;
  Report->Lines->Add("Cfgini: ");
  Report->Lines->Add("AutoRun = "+IntToStr(IniCfg.AutoRun) );
  Report->Lines->Add("AutoClose = "+IntToStr(IniCfg.AutoClose) );
  Report->Lines->Add("AutoShowDown = "+IntToStr(IniCfg.AutoShowDown) );
  Report->Lines->Add("ShutDownTime = "+IntToStr(IniCfg.ShutDownTime+3)+"s" );
  Report->Lines->Add("CfgDevice: ");
  Report->Lines->Add("DeviceType = "+IniCfg.DeviceType );
  Report->Lines->Add("DeviceName = "+IniCfg.DeviceName );
  Report->Lines->Add("");

  if( 0 != IniCfg.DeveloperMode)
  {
    Form1->AutoSize = true;
  }
  if(1 == IniCfg.AutoRun)
  {
    Timer1->Enabled = true;
  }
}
//---------------------------------------------------------------------------
bool __fastcall TForm1::EditRegister()
{
    HKEY key;
    DWORD dispos=0;
    SECURITY_ATTRIBUTES sa;
    AnsiString skey = "SYSTEM\\CurrentControlSet\\Control\\COM Name Arbiter";
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.bInheritHandle = TRUE;
    sa.lpSecurityDescriptor = NULL;
    long iret = RegCreateKeyEx(HKEY_LOCAL_MACHINE,  //主键 的值
                                skey.c_str(),       //子键 的值
                                NULL,  //保留,必须设置为0
                                NULL,  //一个指向包含键类型的字符串。如果该键已经存在,则忽略该参数。
                                REG_OPTION_NON_VOLATILE,   //为新创建的键设置一定的属性
                                KEY_ALL_ACCESS,            //用来设置对键访问的权限
                                &sa,             //为一个指向SECURITY_ATTRIBUTES结构的指针,确定返回的句柄是否被子处理过程继承。如果该参数为NULL,则句柄不可以被继承。
                                &key,            //为一个指向新创建或打开的键的句柄的指针,指向该键
                                &dispos);        //指明键是被创建还是被打开的
    if(ERROR_SUCCESS == iret)
    {
      RegDeleteValue(key,"ComDB"); //删除项值名为ComDB的项值
      RegCloseKey(key);
      Report->Lines->Add("#Delete Register Value Success");
      return true;
    }
    else
    {
      AllFlag = false;
      Report->Lines->Add("##Delete Register Value Fail");
      return false;
    }
}

void __fastcall TForm1::UpdateDevice()
{
   DEVINST DevInst;
   if(CR_SUCCESS == CM_Locate_DevNodeA(&DevInst,NULL,CM_LOCATE_DEVNODE_NORMAL) )
   {
     if(CR_SUCCESS != CM_Reenumerate_DevNode(DevInst,CM_REENUMERATE_NORMAL) )
     {
        ShowMessage("扫描检测硬件改动失败,请手动尝试");
        Report->Lines->Add("##Restart COM Devcie Fail");
        AllFlag = false;
     }
     else
     {
       Report->Lines->Add("#Restart COM Devcie Success");
       Sleep(1000);
     }
   }
   else
   {
     ShowMessage("扫描检测硬件改动失败,请手动尝试");
     Report->Lines->Add("##Restart COM Devcie Fail");
   //  Sleep(1000);
     AllFlag = false;
   }
}
void __fastcall TForm1::Shutdown()
{
//  AnsiString sss = "cmd";  //
  AnsiString sss = "Shutdown -r -t "+IntToStr(IniCfg.ShutDownTime+3);
  system(sss.c_str() );     //发出一个DOS命令 ,头文件<stdlib.h>
}
void __fastcall TForm1::PassFun(TMemo *MemoRepot,TPanel *PanelReport)
{
  AnsiString CFGPath = GetCurrentDir() + "\\userdefineresult.log";
  TIniFile *ini = new TIniFile(CFGPath);
  ini->WriteString("Response","Result","PASS");
  delete ini;

  AnsiString SaveLog = GetCurrentDir() + "\\userdefinelog.log";
  if(FileExists(SaveLog))       //FileExists检查SaveLog路径下文件或目录是否存在
    DeleteFile(SaveLog);        //删除 SaveLog 路径文件
  MemoRepot->Lines->SaveToFile(SaveLog);    // 新建文件

  AnsiString CFGPath1 = GetCurrentDir() + "\\userdefinelog.log";
  TIniFile *ini1 = new TIniFile(CFGPath1);
  ini1->WriteString("Response","Result","PASS");        //写入相关信息
  delete ini1;

  PanelReport->Caption = "PASS";
  PanelReport->Color = clGreen;

  if(1 == IniCfg.AutoClose)
  {
    Sleep(1000);
    this->Close();
  }  
}

void __fastcall TForm1::FailFun(TMemo *MemoRepot,TPanel *PanelReport)
{
  AnsiString CFGPath = GetCurrentDir() + "\\userdefineresult.log";
  TIniFile *ini = new TIniFile(CFGPath);
  ini->WriteString("Response","Result","FAIL");
  delete ini;


  AnsiString SaveLog = GetCurrentDir() + "\\userdefinelog.log";
  if(FileExists(SaveLog))
    DeleteFile(SaveLog);
  MemoRepot->Lines->SaveToFile(SaveLog);

  AnsiString CFGPath1 = GetCurrentDir() + "\\userdefinelog.log";
  TIniFile *ini1 = new TIniFile(CFGPath1);
  ini1->WriteString("Response","Result","FAIL");
  delete ini1;
  PanelReport->Caption = "FAIL";
  PanelReport->Color = clRed;

}

void __fastcall TForm1::Button4Click(TObject *Sender)
{
  AnsiString sss = "Shutdown -a";
  char buffer[512];
  sprintf(buffer,"%s",sss);
//  system(sss.c_str() );
  system(buffer);     //发出一个DOS命令 ,头文件<stdlib.h>
}
//---------------------------------------------------------------------------

void __fastcall TForm1::TmrDownTimer(TObject *Sender)
{
  TmrDown->Enabled = false;
  Shutdown();   //关机操作
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
  Timer1->Enabled =false;
  Button1->Click();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Timer2Timer(TObject *Sender)
{
  Timer2->Enabled =false;
  Button2->Click();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button5Click(TObject *Sender)
{
    int t = Application->MessageBox("确定立即重启系统?","请做以下确认",MB_YESNO) ;
    if(ID_YES == t)
    {
      Report->Lines->Add("!!!!The system will restart");
      Shutdown();
    }
    else
      Report->Lines->Add("!!!!To cancel the restart");
}
//---------------------------------------------------------------------------

 

 

 

 

 

后续补充:

工程源码已上传,请转移此处下载

https://download.csdn.net/download/ailong91/12004315

完结!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值