フレンドリ名の取得にはSetup APIを使用しますが、残念ながらDelphiにはSetup API関係の定義が含まれていない(C++Builderならsetupapi.hがあるのですが)ため、まずは必要なWin32APIと構造体を定義します。
{ Setup APIs }
type
{ HDEVINFO }
HDEVINFO = THandle;
{$EXTERNALSYM HDEVINFO}
{ SP_DEVINFO_DATA }
SP_DEVINFO_DATA = packed record
cbSize: DWORD;
ClassGuid: TGUID;
DevInst: DWORD;
Reserved: ULONG_PTR;
end;
{$EXTERNALSYM SP_DEVINFO_DATA}
const
{ Flags for SetupDiGetClassDevs }
DIGCF_PRESENT = $00000002;
{$EXTERNALSYM DIGCF_PRESENT}
{ Property for SetupDiGetDeviceRegistryProperty }
SPDRP_DEVICEDESC = $00000000;
{$EXTERNALSYM SPDRP_DEVICEDESC}
SPDRP_FRIENDLYNAME = $0000000C;
{$EXTERNALSYM SPDRP_FRIENDLYNAME}
{ Scope for SetupDiOpenDevRegKey }
DICS_FLAG_GLOBAL = $00000001;
{$EXTERNALSYM DICS_FLAG_GLOBAL}
{ KeyType for SetupDiOpenDevRegKey }
DIREG_DEV = $00000001;
{$EXTERNALSYM DIREG_DEV}
{ SetupDiClassGuidsFromName }
function SetupDiClassGuidsFromName(const ClassName: PChar;
ClassGuidList: PGUID;
ClassGuidListSize: DWORD;
var RequiredSize: DWORD): BOOL; stdcall;
external 'SetupApi.dll' name
{$IFDEF UNICODE}
'SetupDiClassGuidsFromNameW';
{$ELSE}
'SetupDiClassGuidsFromNameA';
{$ENDIF}
{$EXTERNALSYM SetupDiClassGuidsFromName}
{ SetupDiGetClassDevs }
function SetupDiGetClassDevs(ClassGuid: PGUID;
const Enumerator: PChar;
hwndParent: HWND;
Flags: DWORD): HDEVINFO; stdcall;
external 'SetupApi.dll' name
{$IFDEF UNICODE}
'SetupDiGetClassDevsW';
{$ELSE}
'SetupDiGetClassDevsA';
{$ENDIF}
{$EXTERNALSYM SetupDiGetClassDevs}
{ SetupDiDestroyDeviceInfoList }
function SetupDiDestroyDeviceInfoList(DeviceInfoSet: HDEVINFO): BOOL; stdcall;
external 'SetupApi.dll' name 'SetupDiDestroyDeviceInfoList';
{$EXTERNALSYM SetupDiDestroyDeviceInfoList}
{ SetupDiEnumDeviceInfo }
function SetupDiEnumDeviceInfo(DeviceInfoSet: HDEVINFO;
MemberIndex: DWORD;
var DeviceInfoData: SP_DEVINFO_DATA): BOOL; stdcall;
external 'SetupApi.dll' name 'SetupDiEnumDeviceInfo';
{$EXTERNALSYM SetupDiEnumDeviceInfo}
{ SetupDiGetDeviceRegistryProperty }
function SetupDiGetDeviceRegistryProperty(DeviceInfoSet: HDEVINFO;
const DeviceInfoData: SP_DEVINFO_DATA;
Prop: DWORD;
PropertyRegDataType: PDWORD;
PropertyBuffer: Pointer;
PropertyBufferSize: DWORD;
var RequiredSize: DWORD): BOOL; stdcall;
external 'SetupApi.dll' name
{$IFDEF UNICODE}
'SetupDiGetDeviceRegistryPropertyW';
{$ELSE}
'SetupDiGetDeviceRegistryPropertyA';
{$ENDIF}
{$EXTERNALSYM SetupDiGetDeviceRegistryProperty}
{ SetupDiOpenDevRegKey }
function SetupDiOpenDevRegKey(DeviceInfoSet: HDEVINFO;
var DeviceInfoData: SP_DEVINFO_DATA;
Scope: DWORD;
HwProfile: DWORD;
KeyType: DWORD;
samDesired: REGSAM): HKEY; stdcall;
external 'SetupApi.dll' name 'SetupDiOpenDevRegKey';
{$EXTERNALSYM SetupDiOpenDevRegKey}
これらを使用してシリアルポートをそのフレンドリ名とともに取得します。function EnumSerialCommWithFriendlyName(const S: TStrings): Integer;
var
Guid: TGUID;
Size: DWORD;
hDevInf: HDEVINFO;
Index: DWORD;
DevInfoData: SP_DEVINFO_DATA;
S1: String;
hRegKey: HKEY;
S2: String;
RegType: DWORD;
PortNo: Integer;
begin
Result := 0;
Size := 0;
if SetupDiClassGuidsFromName('Ports',@Guid,1,Size) = False then
begin
RaiseLastOSError;
end;
hDevInf := SetupDiGetClassDevs(@Guid,nil,0,DIGCF_PRESENT);
if hDevInf = INVALID_HANDLE_VALUE then
begin
RaiseLastOSError;
end;
try
Index := 0;
while True do
begin
FillChar(DevInfoData,SizeOf(DevInfoData),0);
DevInfoData.cbSize := SizeOf(DevInfoData);
if SetupDiEnumDeviceInfo(hDevInf,Index,DevInfoData) = False then
begin
Break;
end;
SetupDiGetDeviceRegistryProperty(hDevInf,DevInfoData,SPDRP_FRIENDLYNAME,
nil,nil,0,Size);
SetLength(S1,(Size + SizeOf(Char)) div SizeOf(Char));
if SetupDiGetDeviceRegistryProperty(hDevInf,DevInfoData,SPDRP_FRIENDLYNAME,
nil,PChar(S1),Size,Size) = True then
begin
SetLength(S1,StrLen(PChar(S1)));
hRegKey := SetupDiOpenDevRegKey(hDevInf,DevInfoData,DICS_FLAG_GLOBAL,0,DIREG_DEV,KEY_READ);
if hRegKey <> INVALID_HANDLE_VALUE then
begin
try
if RegQueryInfoKey(hRegKey,nil,nil,nil,nil,nil,nil,nil,nil,
@Size,nil,nil) = ERROR_SUCCESS then
begin
SetLength(S2,(Size + SizeOf(Char)) div SizeOf(Char));
if (RegQueryValueEx(hRegKey,'PortName',nil,@RegType,Pointer(PChar(S2)),
@Size) = ERROR_SUCCESS) and
(RegType = REG_SZ) then
begin
SetLength(S2,StrLen(PChar(S2)));
if CompareText(Copy(S2,1,3),'COM') = 0 then
begin
if TryStrToInt(Copy(S2,4,Length(S2)),PortNo) = True then
begin
S.AddObject(S1,Pointer(PortNo));
if Result < PortNo then
begin
Result := PortNo;
end;
end;
end;
end;
end;
finally
RegCloseKey(hRegKey);
end;
end;
end;
Index := Index + 1;
end;
finally
SetupDiDestroyDeviceInfoList(hDevInf);
end;
end;
手順ですが、まずSetupDiClassGuidsFromNameでデバイスインタフェースクラスが'Ports'のGUIDを取得し、そのGUIDを使用してSetupDiGetClassDevsで現在システムに認識されているDevice Information Setsを取得し、SetupDiEnumDeviceInfoでDevice Information Set一つずつの情報をSP_DEVINFO_DATAに取り出して、SetupDiGetDeviceRegistryPropertyでフレンドリ名を取得します。さらにSetupDiOpenDevRegKeyでデバイス固有情報の含まれるレジストリキー('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum'の下のデバイスごとのキーに含まれる'Device Parameters'キー)を開き、RegQueryValueExで'PortName'という名前でREG_SZの値のデータを文字列として取得し、'COM'で始まっていたらシリアルポートとしてフレンドリ名とともにパラメータ(S: TStrings)に格納します。全てのDevice Information Setをチェックし終わったらSetupDiDestroyDeviceInfoListでDevice Information Sets全体を解放します。
以前のものと同様に必ずしもポート番号順にはなっていないため、必要に応じて結果をソートしてください。→シリアルポートをフレンドリ名で列挙 (Gist)
0 件のコメント:
コメントを投稿