为什么一些设备不能与SetupDiGetDeviceInterfaceDetail枚举()?
题
我维持使用SetupDiGetDeviceInterfaceDetail()来找出在计算机上已安装的串行端口的信息的应用。在测试这一点,有一些设备,比如我朗讯的WinModem,即不要在枚举显示我已经注意到了。事实证明,我有一组实现串行端口接口由我公司生产的设备的一个类似的问题。我的假设是,有一些东西是从该设备的INF文件丢失。有谁知道可能会导致这种不作为什么样的条件呢?
编辑:这是我使用枚举串行端口的代码的一个示例。我已经尝试标志的各种组合,但没有看到任何行为显著差异。
DEFINE_GUID(GUID_CLASS_COMPORT, 0x4d36e978, 0xe325, 0x11ce, 0xbf, 0xc1, \
0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18);
GUID *serial_port_guid = const_cast<GUID *>(&GUID_CLASS_COMPORT);
HDEVINFO device_info = INVALID_HANDLE_VALUE;
SP_DEVICE_INTERFACE_DETAIL_DATA *detail_data = 0;
device_info = SetupDiGetClassDevs(
serial_port_guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(device_info != INVALID_HANDLE_VALUE)
{
uint4 const detail_data_size = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + 256;
detail_data = reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA *>(new char[detail_data_size]);
SP_DEVICE_INTERFACE_DATA ifc_data;
bool more_interfaces = true;
int rcd;
memset(&ifc_data, 0, sizeof(ifc_data));
memset(detail_data, 0, detail_data_size);
ifc_data.cbSize = sizeof(ifc_data);
detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
for(uint4 index = 0; more_interfaces; ++index)
{
rcd = SetupDiEnumDeviceInterfaces(device_info, 0, serial_port_guid, index, &ifc_data);
if(rcd)
{
// we need to get the details of this device
SP_DEVINFO_DATA device_data = { sizeof(SP_DEVINFO_DATA) };
rcd = SetupDiGetDeviceInterfaceDetail(
device_info, &ifc_data, detail_data, detail_data_size, 0, &device_data);
if(rcd)
{
StrAsc device_path(detail_data->DevicePath);
byte friendly_name[256];
rcd = SetupDiGetDeviceRegistryProperty(
device_info, &device_data, SPDRP_FRIENDLYNAME, 0, friendly_name, sizeof(friendly_name), 0);
if(rcd)
{
std::for_each(
port_names.begin(),
port_names.end(),
update_friendly_name(
reinterpret_cast<char const *>(friendly_name)));
}
}
else
more_interfaces = false;
}
}
}
解决方案 4
我决定踢上这一点,并废除对的SetupDi()函数的依赖性。相反,我写了遍历HKEY_LOCAL_MACHINE \ SYSTEM子项\ CURRENTCONTROLSET \枚举发现,支持串口GUID任何驱动程序代码。我有一种感觉,这是设备管理器做什么。如果任何人的爱好,我的代码片段可在下面看到:
typedef std::string StrAsc;
typedef std::pair<StrAsc, StrAsc> port_name_type;
typedef std::list<port_name_type> friendly_names_type;
void SerialPortBase::list_ports_friendly(friendly_names_type &port_names)
{
// we will first get the list of names. This will ensure that, at the very least, we get
// the same list of names as we would have otherwise obtained.
port_names_type simple_list;
list_ports(simple_list);
port_names.clear();
for(port_names_type::iterator pi = simple_list.begin(); pi != simple_list.end(); ++pi)
port_names.push_back(friendly_name_type(*pi, *pi));
// we will now need to enumerate the subkeys of the Enum registry key. We will need to
// consider many levels of the registry key structure in doing this so we will use a list
// of key handles as a stack.
HKEY enum_key ;
char const enum_key_name[] = "SYSTEM\\CurrentControlSet\\Enum";
StrAsc const com_port_guid("{4d36e978-e325-11ce-bfc1-08002be10318}");
char const class_guid_name[] = "ClassGUID";
char const friendly_name_name[] = "FriendlyName";
char const device_parameters_name[] = "Device Parameters";
char const port_name_name[] = "PortName";
long rcd = ::RegOpenKeyEx(
HKEY_LOCAL_MACHINE, enum_key_name, 0, KEY_READ, &enum_key);
char value_buff[MAX_PATH];
StrAsc port_name, friendly_name;
if(!port_names.empty() && rcd == ERROR_SUCCESS)
{
std::list<HKEY> key_stack;
key_stack.push_back(enum_key);
while(!key_stack.empty())
{
// we need to determine whether this key has a "ClassGUID" value
HKEY current = key_stack.front();
uint4 value_buff_len = sizeof(value_buff);
key_stack.pop_front();
rcd = ::RegQueryValueEx(
current,
class_guid_name,
0,
0,
reinterpret_cast<byte *>(value_buff),
&value_buff_len);
if(rcd == ERROR_SUCCESS)
{
// we will only consider devices that match the com port GUID
if(com_port_guid == value_buff)
{
// this key appears to identify a com port. We will need to get the friendly name
// and try to get the 'PortName' from the 'Device Parameters' subkey. Once we
// have those things, we can update the friendly name in our original list
value_buff_len = sizeof(value_buff);
rcd = ::RegQueryValueEx(
current,
friendly_name_name,
0,
0,
reinterpret_cast<byte *>(value_buff),
&value_buff_len);
if(rcd == ERROR_SUCCESS)
{
HKEY device_parameters_key;
rcd = ::RegOpenKeyEx(
current,
device_parameters_name,
0,
KEY_READ,
&device_parameters_key);
if(rcd == ERROR_SUCCESS)
{
friendly_name = value_buff;
value_buff_len = sizeof(value_buff);
rcd = ::RegQueryValueEx(
device_parameters_key,
port_name_name,
0,
0,
reinterpret_cast<byte *>(value_buff),
&value_buff_len);
if(rcd == ERROR_SUCCESS)
{
friendly_names_type::iterator fi;
port_name = value_buff;
fi = std::find_if(
port_names.begin(), port_names.end(), port_has_name(port_name));
if(fi != port_names.end())
fi->second = friendly_name;
}
::RegCloseKey(device_parameters_key);
}
}
}
}
else
{
// since this key did not have what we expected, we will need to check its
// children
uint4 index = 0;
rcd = ERROR_SUCCESS;
while(rcd == ERROR_SUCCESS)
{
value_buff_len = sizeof(value_buff);
rcd = ::RegEnumKeyEx(
current, index, value_buff, &value_buff_len, 0, 0, 0, 0);
if(rcd == ERROR_SUCCESS)
{
HKEY child;
rcd = ::RegOpenKeyEx(current, value_buff, 0, KEY_READ, &child);
if(rcd == ERROR_SUCCESS)
key_stack.push_back(child);
}
++index;
}
}
::RegCloseKey(current);
}
}
} // list_ports_friendly
其他提示
这更是一个有关问题问题。当你调用该函数,你传递应该是DeviceInfoSet,你可能从的 SetupDiGetClassDevs 功能。当被叫SetupDiGetClassDevs功能是什么?你的标志指定(最后一个参数)引用微软的页面上的功能:
<强> DIGCF_ALLCLASSES 强> 返回已安装的设备列表中的所有设备安装程序类或全部 设备接口类。
<强> DIGCF_DEVICEINTERFACE 强> 返回支持指定的设备的设备接口的设备 接口类。此标志必须是 在Flags参数如果设置 枚举参数指定 设备实例ID。
<强> DIGCF_DEFAULT 强> 只返回与系统默认关联的设备 设备接口,如果一个被设定为 指定的设备接口 类。
<强> DIGCF_PRESENT 强> 仅返回当前存在于系统设备。
<强> DIGCF_PROFILE 强> 返回仅是当前硬件配置文件的一部分的装置。
根据您所选择的设备变化的列表。例如,本标志将只显示设备插在积极。
更新:谢谢你的示例代码
我现在的问题是,如果你想知道为什么不使用相同的电话,但指定调制解调器的Guid,而不是COM端口的调制解调器的友好名称?我有调制解调器GUID是4D36E96D-E325-11CE-BFC1-08002BE10318
在注册表我可以看到一个称为“AttachedTo”值,它指定一个COM端口。我必须研究其性质,多数民众赞成在API中被绑定到。该注册表项是在
HKLM \系统\ CurrentControlSet \控制\类{4D36E96D-E325-11CE-BFC1-08002BE10318} \
另一个更新:
在研究样本代码更近。在此基础上,如果你想获得设备接口类应该返回 SP_DEVICE_INTERFACE_DETAIL_DATA 结构。这将不提供取设备的友好名称的方式。我相信,而不是你想的设备实例。
这是我读过,设备接口是用来作为一种方式来获得可用于写入它的设备路径。
有一件事我没有对代码进行测试是再次尝试磁盘设备接口。我做了一些改动,以得到它我的系统上工作,它仍然没有完全完成。我想一个问题(可能更多)是,我需要调整的DevicePath变量其间的SetupDiGetDeviceInterfaceDetail电话。
void Test()
{
GUID *serial_port_guid = const_cast<GUID *>(&GUID_DEVINTERFACE_DISK);
HDEVINFO device_info = INVALID_HANDLE_VALUE;
SP_DEVICE_INTERFACE_DETAIL_DATA detail_data;
device_info = SetupDiGetClassDevs(
serial_port_guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(device_info != INVALID_HANDLE_VALUE)
{
//uint4 const detail_data_size = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);// + 256;
//detail_data = reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA *>(new char[detail_data_size]);
SP_DEVICE_INTERFACE_DATA ifc_data;
bool more_interfaces = true;
int rcd;
memset(&ifc_data, 0, sizeof(ifc_data));
//memset(detail_data, 0, detail_data_size);
ifc_data.cbSize = sizeof(ifc_data);
detail_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
for(uint4 index = 0; more_interfaces; ++index)
{
rcd = SetupDiEnumDeviceInterfaces(device_info, 0, serial_port_guid, index, &ifc_data);
if(rcd)
{
// we need to get the details of this device
SP_DEVINFO_DATA device_data;
device_data.cbSize = sizeof(SP_DEVINFO_DATA);
DWORD intReqSize;
rcd = SetupDiGetDeviceInterfaceDetail(device_info, &ifc_data, 0, 0, &intReqSize, &device_data);
rcd = SetupDiGetDeviceInterfaceDetail(device_info, &ifc_data, &detail_data,intReqSize,&intReqSize,&device_data);
if(rcd)
{
//StrAsc device_path(detail_data->DevicePath);
byte friendly_name[256];
rcd = SetupDiGetDeviceRegistryProperty(
device_info, &device_data, SPDRP_FRIENDLYNAME, 0, friendly_name, sizeof(friendly_name), reinterpret_cast<DWORD *>(sizeof(friendly_name)));
if(rcd)
{
cout<<reinterpret_cast<char const *>(friendly_name);
}
else
{ int num = GetLastError();
}
}
else
{
int num = GetLastError();
}
}
else
more_interfaces = false;
}
}
SetupDiDestroyDeviceInfoList(device_info);
}
另外,在INF,可能必须添加 AddInterface 一>指令到驱动程序与正确的接口进行关联。
我不知道是否因为中提到以下修补程序将解决您的问题。
http://support.microsoft.com/kb/327868
一个更野趣点:GUID_CLASS_COMPORT是过时从Win2000的起..
http://msdn.microsoft.com/en-us/library /bb663140.aspx
http://msdn.microsoft.com/en-us/library /bb663174.aspx
我发现具有9种不同的枚举的方式的另一种部位。好运。
您说您的设备存在且可访问,但你直接访问您的设备或者是你访问由姓名和电话号码COMN端口:
我具有连接到我的音频驱动器的WinModem。我没有串行端口,甚至没有模拟一个。