初めに
Windows.hを使うことでレジストリにアクセスすることができる。
今回は、現在接続されているデバイスのCOMポート一覧の取得方法をまとめました。
windows限定です
プログラム
int serchDevice()関数は接続されているデバイスの数を返します。x64環境で作成しております。
勉強中なので、プログラムにはミスが含まれている可能性があります。
#include <iostream>
#include <string>
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include <setupapi.h>
#pragma comment(lib,"hid.lib")
#pragma comment(lib,"setupapi.lib")
int serchDevice(){
HDEVINFO hDevInfo;
int max = 0;
// デバイス一覧の情報を取得
hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE) { printf_s("ERROR:COMPORT NOT FOUND\n"); return -1; }
// デバイス情報セット
SP_DEVINFO_DATA Data = { sizeof(SP_DEVINFO_DATA) };
Data.cbSize = sizeof(Data);
// 個々のデバイスの情報を取得
while (SetupDiEnumDeviceInfo(hDevInfo, max, &Data)) {
char *port = nullptr;
char name[256] = { 0 };
// 個々のデバイスの構成情報のレジストリキーを開く
HKEY key = SetupDiOpenDevRegKey(hDevInfo, &Data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
if (key != INVALID_HANDLE_VALUE) {
DWORD type = 0;
DWORD size = 256;
//デバイス情報(レジストリキー)の情報群からCOMPortの名前を取り出す
RegQueryValueEx(key, "PortName", NULL, &type, (LPBYTE)name, &size);
port = name;
}else continue;
DWORD size = 0;
char *buf = nullptr;
// デバイスの詳細の取得
// デバイスの詳細に必要な文字数をsizeに収納
SetupDiGetDeviceRegistryProperty(hDevInfo, &Data, SPDRP_DEVICEDESC, NULL, NULL, 0, &size);
buf = new char [size * 2];
BOOL success = FALSE;
// デバイスの詳細の文字列をbufに収納
success = SetupDiGetDeviceRegistryProperty(hDevInfo, &Data, SPDRP_DEVICEDESC, NULL, (PBYTE)buf, size, &size);
if (success == FALSE) printf_s("ERROR:CANT GET THE DETAIL\n");
// ここで、COMポートの名前(port)と詳細(buf)が取得できる。ここを改良して出力してください
printf_s("%s, %s\n", port, buf);
delete[] buf;
max++;
}
SetupDiDestroyDeviceInfoList(hDevInfo); // デバイス情報セットの解放
return max;
}
実行例
ターミナルの出力
COM20, Bluetooth リンク経由の標準シリアル
COM1, 通信ポート
COM21, Bluetooth リンク経由の標準シリアル
解説
ほとんどMicrosoftのWINAPIリファレンスから引用です。
間違えている可能性が高いです。レジストリなどよくわかっていません…参考でお願いします。
SetupDiGetClassDevs(const GUID *ClassGuid, PCSTR Enumerator, HWND hwndParent, DWORD Flags)
SetupDiGetClassDevsA 関数 (setupapi.h)
/*デバイス一覧の情報を取得
HDEVINFO SetupDiGetClassDevs(
デバイスの種類(GUID_DEVINTERFACE_COMPORT=COMPORTのみ),
PnP(コンピュータに差し込む装置)を識別するID,USBやPCMCIA等(NULL可),
ユーザーインターフェースの最上ウィンドウのハンドル? (NULL可),
出力するデバイスのフィルター (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE = 現在存在するデバイス ∧ デバイスインターフェースのみ)
);
戻り値:引数に一致するデバイス一覧を返す
*/
hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
SP_DEVINFO_DATA
SP_DEVINFO_DATA構造体 (setupapi.h)
詳細不明です…Dataには最終的に取得した個々のデバイスの情報(GUIDなど)が入ります。
// デバイス情報セット
SP_DEVINFO_DATA Data = { sizeof(SP_DEVINFO_DATA) };
Data.cbSize = sizeof(Data);
SetupDiEnumDeviceInfo(HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData)
SetupDiEnumDeviceInfo 関数 (setupapi.h)
/*個々のデバイスの情報を取得
BOOL SetupDiEnumDeviceInfo(
デバイス一覧,
デバイスのインデックス,
デバイス一覧から、インデックスで指定された個々のデバイス情報を渡す
);
戻り値:成功したか否か(成功=TRUE)
*/
SetupDiEnumDeviceInfo(hDevInfo, max, &Data)
SetupDiOpenDevRegKey(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired);
SetupDiOpenDevRegKey 関数 (setupapi.h)
/*個々のデバイスの構成情報のレジストリキーを開く
HKEY SetupDiOpenDevRegKey(
デバイス一覧,
デバイス一覧から一つを指定するためのSP_DEVINFO_DATA構造体,
開くレジストリキーを選択(DICS_FLAG_GLOBAL=構成情報を取得),
ハードウェアの情報の選択(0=現在の状態のハードウェアプロファイル)
開くレジストリキーの種類(DIREG_DEV デバイスのハードウェアキー),
開くキーに使うレジストリセキュリティアクセス
);
返り値:レジストリキー
*/
HKEY key = SetupDiOpenDevRegKey(hDevInfo, &Data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
RegQueryValueExA function (winreg.h)
/*デバイス情報(レジストリキー)の情報群から一つを選ぶ
LSTATUS RegQueryValueEx(
レジストリキー,
取得したい情報,
NULL(予約済み),
値を収納する変数へのポインタ(値)(NULL可),
値を収納する変数へのポインタ(文字)(NULL可),
文字を収納する場合の文字列バッファサイズ(文字ポインタがNULLのときはNULLでよい)
);
返り値:エラーコード(ERROE_SUCCESS=成功)
*/
RegQueryValueEx(key, "PortName", NULL, &type, (LPBYTE)name, &size);
SetupDiGetDeviceRegistryProperty(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize);
SetupDiGetDeviceRegistryPropertyA 関数 (setupapi.h)
/*デバイスの説明文の取得
SetupDiGetDeviceRegistryProperty(
レジストリキー,
取得したい情報,
取得したい情報の選択(SPDRP_DEVICEDESC=デバイスの解説),
返り値のデータの型(NULL可),
返り値を入れるバッファのポインタ(NULL可),
返り値を入れるバッファのサイズ,
取得した文字列の長さ
);
返り値:成功したか否か(成功=TRUE)
※「返り値を入れるバッファのポインタ」と「返り値を入れるバッファのサイズの両方がNULL」のとき、「取得した文字列の長さ」には必要なバッファの大きさが返る
*/
SetupDiGetDeviceRegistryProperty(hDevInfo, &Data, SPDRP_DEVICEDESC, NULL, (PBYTE)buf, size, &size);
参考
COMポートの一覧を表示・プロパティの変更及びポートの選択をする(ダイアログボックス版)
変更履歴
- コメントより、
SetupDiGetClassDevs
とSetupDiOpenDevRegKey
が失敗したとき、INVALID_HANDLE_VALUE
を返すのに0でチェックを行っていたところを修正 - コメントより、例外処理を
SetupDiGetDeviceRegisterProperty
関数にも追加