본문 바로가기

Developement/C/C++

Windows API 를 이용해 Serial Port 찾기.


 Windows 에서 개발 하는 과정에서 COM port 를 찾는 방법은 여러가지가 있긴 합니다만, 명확히 USB 나 Bluetooth 와 같은 기기들이 연결 되었을 때 이것을 다 찾아 내는 방법은 애매한 경우가 더러 있습니다.

 저의 경우는 기존에 SetupDiEnumDeviceInterfaces() 를 사용한 방법을 쓰다가, Windows 10 으로 올린 다음 부터 USB 장치로 인식한 COM port 가 검색이 되질 않아 좀 더 애를 먹었습니다만, 간단히 GUID 를 GUID_DEVINTERFACE_COMPORT 로 쓰던걸 GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR 로 변경하기만 해도 문제가 해결 되었습니다.


각 GUI 는 다음과 같은 값을 가집니다. (mingw-w64 의 경우 winioctl.h 에 이 내용이 있습니다)


GUID_DEVINTERFACE_COMPORT = 0x86e0d1e0,0x8089,0x11d0,0x9c,0xe4,0x08,0x00,0x3e,0x30,0x1f,0x73


GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR = 0x4D36E978,0xE325,0x11CE,0xBF,0xC1,0x08,0x00,0x2B,0xE1,0x03,0x18


그리고 이것을 아래와 같이 응용 할 수 있습니다.



    GUID*    guidDev  = (GUID*) &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR;
    HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;

    SP_DEVICE_INTERFACE_DETAIL_DATA* pDetData = NULL;

    hDevInfo = SetupDiGetClassDevs( guidDev,
                                    NULL,
                                    NULL,
                                    DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );

    if( hDevInfo == INVALID_HANDLE_VALUE )
    {
        errorstring = TEXT("SetupDiGetClassDevs return INVALID_HANDLE_VALUE");

        return;
    }

    BOOL                        bOk = TRUE;
    SP_DEVICE_INTERFACE_DATA    ifcData;
    DWORD                       dwDetDataSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + DEVICE_INFO_SZ;

    pDetData = (SP_DEVICE_INTERFACE_DETAIL_DATA*)new char[dwDetDataSize];

    if ( pDetData == NULL )
        return;

    ifcData.cbSize   = sizeof(SP_DEVICE_INTERFACE_DATA);
    pDetData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

    for( int cnt=0; cnt<256; cnt++ )
    {
        bOk = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guidDev, cnt, &ifcData);

        if ( bOk == TRUE )
        {
            ⁄⁄ Got a device. Get the details.
            SP_DEVINFO_DATA devdata = {sizeof(SP_DEVINFO_DATA)};

            bOk = SetupDiGetDeviceInterfaceDetail( hDevInfo,
                                                   &ifcData,
                                                   pDetData,
                                                   dwDetDataSize,
                                                   NULL,
                                                   &devdata );
            if ( bOk == TRUE )
            {
                TSTRING strDevPath = pDetData->DevicePath;

                wchar_t fname[256] = {0};
                wchar_t desc[256] = {0};

                BOOL bSuccess = SetupDiGetDeviceRegistryProperty( hDevInfo,
                                                                  &devdata,
                                                                  SPDRP_FRIENDLYNAME,
                                                                  NULL,
                                                                  (PBYTE)fname,
                                                                  256,
                                                                  NULL );
                bSuccess = bSuccess &&
                           SetupDiGetDeviceRegistryProperty( hDevInfo,
                                                             &devdata,
                                                             SPDRP_DEVICEDESC,
                                                             NULL,
                                                             (PBYTE)desc,
                                                             256,
                                                             NULL );
                bool bUsbDevice = false;

                if ( ( wcsstr( desc, L"USB" ) != NULL ) || ( wcsstr( fname, L"USB" ) != NULL ) )
                {
                    bUsbDevice = true;
                }

                if ( bSuccess == TRUE )
                {
#ifdef DEBUG
                    wprintf( L"%S[%03d] %S (%S)\n",
                             L"COM Port",
                             cnt,
                             (wchar_t*)fname,
                             (wchar_t*)desc );
#endif ⁄⁄ DEBUG
                    serialportinfo si;

                    si.isUSBdev = bUsbDevice;
                    si.devpath  = ConvertFromUnicode( strDevPath.c_str() );
                    si.friendlyname = ConvertFromUnicode( fname );
                    si.description = ConvertFromUnicode( desc );

                    string::size_type postkf = si.friendlyname.find("(");
                    string::size_type postke = si.friendlyname.find_last_of(")");
                    string::size_type lentk  = postke - postkf - 1;
                    string portn = si.friendlyname.substr( postkf + 1, lentk );

                    si.portname = portn;

                    serialports.push_back( si );
                }

            }
            else
            {
                errorstring = TEXT("SetupDiGetDeviceInterfaceDetail failed.");
                throw errorstring;
            }
        }
        else
        {
            DWORD err = GetLastError();

            if (err != ERROR_NO_MORE_ITEMS)
            {
                errorstring = TEXT("SetupDiEnumDeviceInterfaces failed.");
                throw errorstring;
            }
        }
    }

	if (pDetData != NULL)
		delete [] (char*)pDetData;

	if (hDevInfo != INVALID_HANDLE_VALUE)
		SetupDiDestroyDeviceInfoList(hDevInfo);

혹시 저와 같이 이 일로 하루를 버린 경우가 계시다면 조속히 해결 할 수 있는 방법으로 사용하시길 바랍니다.

이걸 몰라서 엄청 해매었습니다.. 망할 MSDN ...