일부 장치가 SetupDigetDeviceInterFacedEtail ()로 열거되지 않는 이유는 무엇입니까?
문제
컴퓨터에 설치된 직렬 포트에 대한 정보를 찾기 위해 SetupDigetDeviceInterfacedEtail ()을 사용하는 응용 프로그램을 유지하고 있습니다. 나는 이것을 테스트하는 동안 내 Lucent 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 () 함수에 대한 의존성을 없애기로 결정했습니다. 대신, 나는 serial port guid를 지원하는 드라이버를 찾기 위해 hkey_local_machine system currentcontrolset enum에서 하위 키를 통과하는 코드를 작성했습니다. 나는 이것이 장치 관리자가하는 일이라는 느낌을 가지고 있습니다. 누구나 관심이있는 경우 내 코드 조각이 아래에서 볼 수 있습니다.
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
다른 팁
이것은 문제에 대한 질문입니다. 당신이 기능을 호출 할 때 당신이 통과하는 첫 번째 arg는 당신이 SETUPDIGETCLASSDEVS 기능. SetupDigetClassDevs 기능을 호출했을 때 기능에 대한 Microsoft 페이지를 인용하는 플래그 (마지막 인수)에 무엇을 지정 했습니까?
digcf_allclasses모든 장치 설정 클래스 또는 모든 장치 인터페이스 클래스에 설치된 장치 목록을 반환합니다.
digcf_deviceinterface지정된 장치 인터페이스 클래스의 장치 인터페이스를 지원하는 장치를 반환합니다. 열거기 매개 변수가 장치 인스턴스 ID를 지정하는 경우이 플래그는 플래그 매개 변수로 설정해야합니다.
digcf_default지정된 장치 인터페이스 클래스에 대해 설정된 경우 시스템 기본 장치 인터페이스와 관련된 장치 만 반환합니다.
digcf_present현재 시스템에있는 장치 만 반환합니다.
digcf_profile현재 하드웨어 프로파일의 일부인 장치 만 반환합니다.
선택에 따라 장치 목록이 변경됩니다. 예를 들어, 현재 플래그에는 적극적으로 연결된 장치 만 표시됩니다.
업데이트 : 샘플 코드에 감사드립니다.
내 질문은 이제 모뎀의 친숙한 이름을 알고 싶다면 동일한 호출을 사용하지 말고 COM 포트 대신 모뎀 안내서를 지정하는 이유는 무엇입니까? 모뎀 안내서는 4D36E96D-E325-11CE-BFC1-08002BE10318입니다
레지스트리에서는 COM 포트를 지정하는 'AttachedTo'라는 값을 볼 수 있습니다. API에 어떤 부동산이 묶여 있는지 조사해야합니다. 레지스트리 키가 있습니다
hklm system currentControlset Control class {4d36e96d-e325-11ce-bfc1-08002be10318}
다른 업데이트 :
샘플 코드를 자세히 살펴 봅니다. 이를 기준으로, 당신이 sp_device_interface_detail_data 구조. 그것은 장치의 친근한 이름을 얻는 방법을 제공하지 않을 것입니다. 대신 장치 인스턴스를 원한다고 생각합니다.
내가 읽은 내용에서 장치 인터페이스는 기기 경로를 얻는 데 사용될 수있는 방법으로 사용됩니다.
코드를 테스트하기 위해 한 한 가지는 디스크 장치 인터페이스를 다시 시도하는 것입니다. 내 시스템에서 작동하도록 몇 가지 변경을했지만 여전히 수행되지 않았습니다. 한 가지 문제는 (아마도 더) SetupDigetDeviceInterFacedEtail 호출 사이에서 DevicePath 변수를 크기를 조정해야한다는 것입니다.
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 드라이버를 올바른 인터페이스와 연결하는 지침.
Hotfix를 따르는대로 문제가 해결 될지 확실하지 않습니다.
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 가지 다른 열거 방식을 가지고 있습니다. 행운을 빌어 요.
장치가 존재하고 액세스 할 수 있다고 말하지만 장치에 직접 액세스하거나 이름과 번호로 포트에 액세스하고 있습니까?
오디오 드라이버에 연결된 WinModem이 있습니다. 나는 시뮬레이션 된 포트조차도 없다.