- 책 또는 웹사이트의 내용을 복제하여 다른 곳에 게시하는 것을 금지합니다.
- 책 또는 웹사이트의 내용을 발췌, 요약하여 강의 자료, 발표 자료, 블로그 포스팅 등으로 만드는 것을 금지합니다.
void GetDeviceRegistryProperty()
{
HDEVINFO devInfo;
SP_DEVINFO_DATA devInfoData;
int devIndex = 0;
TCHAR buffer[MAX_PATH] = {0, };
devInfo = SetupDiGetClassDevs(NULL, _T("USB"), NULL, DIGCF_ALLCLASSES);
ZeroMemory(&devInfoData, sizeof(SP_DEVINFO_DATA));
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
while (SetupDiEnumDeviceInfo(devInfo, devIndex, &devInfoData))
{
SetupDiGetDeviceRegistryProperty(
devInfo,
&devInfoData,
SPDRP_HARDWAREID,
NULL,
(BYTE *)buffer,
sizeof(buffer),
NULL);
devIndex++;
}
}
SetupDiGetClassDevs()를 이용하여 디바이스 클래스의 핸들을 얻습니다. 두번째 매개변수에는 PnP 장치들의 구분자를 넣습니다. PCI, USB, PCMCIA, SCSI 등을 사용할 수 있고 NULL을 넣으면 모든 장치를 얻어올 수 있습니다.
마지막 매개변수는 플래그로써 다음과 같은 효과를 가집니다. OR 연산으로 여러개의 플래그를 지정할 수 있습니다.
- DIGCF_ALLCLASSES: 시스템에 설치된 모든 디바이스 인터페이스 클래스를 리턴합니다.(시스템에 장착되지 않은 장치들도 포함합니다.)
- DIGCF_DEVICEINTERFACE: 두번째 매개변수에 PnP 장치의 구분자를 넣었을 때 사용할 수 있습니다. 디바이스 인터페이스를 지원하는 클래스를 리턴합니다.
- DIGCF_DEFAULT: 시스템의 기본 디바이스 클래스만 리턴합니다.
- DIGCF_PRESENT: 시스템에 장착된 장치들만 리턴합니다.
- DIGCF_PROFILE: 현재 하드웨어 프로파일만 리턴합니다.
SetupDiEnumDeviceInfo()로 SP_DEVINFO_DATA 내용을 채웁니다. devIndex는 0부터 시작하여 1씩 증가하면 되고, devInfoData.cbSize에는 꼭 SP_DEVINFO_DATA의 크기를 구하여 넣어줘야 합니다.
SP_DEVINFO_DATA를 구했다면 SetupDiGetDeviceRegistryProperty()를 이용하여 해당 디바이스의 속성과 설정값을 구할 수 있습니다. 대략 많이 쓰는 속성들은 다음과 같습니다.
- SPDRP_DEVICEDESC: 디바이스 설명
- SPDRP_HARDWAREID: 하드웨어 ID
- SPDRP_COMPATIBLEIDS: Compatible ID, USB에서는 Class, SubClass, Protocol 등의 값 SPDRP_UPPERFILTERS, SPDRP_LOWERFILTERS : Upper, Lower Filter 값
필터 설정
void SetFilter()
{
HDEVINFO devInfo;
SP_DEVINFO_DATA devInfoData;
... 생략 ...
TCHAR filterString[MAX_PATH] = _T("hello\0world\0\0");
SetupDiSetDeviceRegistryProperty(
devInfo,
&devInfoData,
SPDRP_LOWERFILTERS,
(BYTE *)filterString,
sizeof(filterString));
}
특정 디바이스의 인스턴스에 필터를 설정하는 방법입니다. 앞서 SetupDiGetClassDevs()와 SetupDiEnumDeviceInfo()를 이용하여 HDEVINFO와 SP_DEVINFO_DATA을 구해옵니다.
SetupDiSetDeviceRegistryProperty()로 해당 장치의 레지스트리에 필터 값을 설정합니다. SPDRP_LOWERFILTERS를 설정하여 LowerFilters에 설정되도록 합니다. 각각의 필터 문자열 값은 널문자(\0)로 구분해주고 마지막에는 두개의 널문자(\0\0)를 넣어줍니다. REG_MULTI_SZ 타입이기 때문입니다. 마지막 버퍼 크기는 실제 문자열 값의 길이를 넣어줘도 되지만, 필터 문자열 값 중간에 널(\0)이 들어가 있어서 _tcslen() 함수로는 길이를 구해 올 수 없습니다. 따라서 버퍼의 크기만 넣어줘도 마지막 두개의 널문자(\0\0)을 체크하여 기록하기 때문에 큰 상관은 없습니다.
필터 드라이버 로드
void PropertyChange()
{
HDEVINFO devInfo;
SP_DEVINFO_DATA devInfoData;
... 생략 ...
SP_PROPCHANGE_PARAMS propChangeParams;
ZeroMemory(&propChangeParams, sizeof(SP_PROPCHANGE_PARAMS));
propChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
propChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
propChangeParams.StateChange = DICS_PROPCHANGE;
propChangeParams.Scope = DICS_FLAG_CONFIGSPECIFIC;
propChangeParams.HwProfile = 0;
SetupDiSetClassInstallParams(
devInfo,
devInfoData,
(PSP_CLASSINSTALL_HEADER)&propChangeParams,
sizeof(SP_PROPCHANGE_PARAMS));
SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, devInfo, devInfoData);
}
필터 드라이버는 StartService()와 같은 함수로 로드하는 것이 아니라, 해당 디바이스의 인스턴스 속성(Property)를 변경해주는 것으로 로드할 수 있습니다.
먼저 SP_PROPCHANGE_PARAMS 구조체에 내용을 설정해줍니다. ClassInstallHeader.cbSize에는 SP_CLASSINSTALL_HEADER의 크기를 넣어줍니다. ClassInstallHeader.InstallFunction에는 호출할 DIF 함수를 지정합니다. DIF_PROPERTYCHANGE를 지정하여 속성을 변경하는 함수를 호출 할 수 있도록 합니다.
StateChange에 DICS_PROPCHANGE를 지정하여 속성을 변경할 수 있도록 합니다. Scope에 DICS_FLAG_CONFIGSPECIFIC를 지정하여 현재 선택된 디바이스의 속성만 변경하도록 합니다. HwProfile에는 0(현재 하드웨어 프로파일)을 지정합니다.
실행 가능한 예제: USB 마우스 장치에 필터 설정, 드라이버 로드하기
#include <windows.h>
#include <setupapi.h>
int _tmain(int argc, _TCHAR* argv[])
{
HDEVINFO devInfo;
SP_DEVINFO_DATA devInfoData;
SP_PROPCHANGE_PARAMS propChangeParams;
int devIndex = 0;
TCHAR buffer[MAX_PATH];
devInfo = SetupDiGetClassDevs(
NULL,
_T("USB"),
NULL,
DIGCF_ALLCLASSES | DIGCF_PRESENT);
ZeroMemory(&devInfoData, sizeof(SP_DEVINFO_DATA));
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
ZeroMemory(&propChangeParams, sizeof(SP_PROPCHANGE_PARAMS));
while (SetupDiEnumDeviceInfo(devInfo, devIndex, &devInfoData))
{
SetupDiGetDeviceRegistryProperty(
devInfo,
&devInfoData,
SPDRP_COMPATIBLEIDS,
NULL,
(BYTE *)buffer,
sizeof(buffer),
NULL);
// Protocol 2 마우스
if (_tcsstr(buffer, _T("Prot_02")) != NULL)
{
TCHAR filterString[MAX_PATH] = _T("devlower\0\0");
SetupDiSetDeviceRegistryProperty(
devInfo,
&devInfoData,
SPDRP_LOWERFILTERS,
(BYTE *)filterString,
sizeof(filterString));
propChangeParams.ClassInstallHeader.cbSize =
sizeof(SP_CLASSINSTALL_HEADER);
propChangeParams.ClassInstallHeader.InstallFunction =
DIF_PROPERTYCHANGE;
propChangeParams.StateChange = DICS_PROPCHANGE;
propChangeParams.Scope = DICS_FLAG_CONFIGSPECIFIC;
propChangeParams.HwProfile = 0;
SetupDiSetClassInstallParams(
devInfo,
&devInfoData,
(PSP_CLASSINSTALL_HEADER)&propChangeParams,
sizeof(SP_PROPCHANGE_PARAMS));
SetupDiCallClassInstaller(
DIF_PROPERTYCHANGE,
devInfo,
&devInfoData);
}
devIndex++;
}
}
저작권 안내
이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.- 블로그, 게시판 등에 퍼가는 것을 금지합니다.
- 비공개 포스트에 퍼가는 것을 금지합니다.
- 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
- 링크 및 SNS 공유는 허용합니다.