Posted to tcl by patthoyts at Thu Mar 01 12:55:28 GMT 2007view pretty

/* lscomport.c - Copyright (C) 2004 Pat Thoyts <patthoyts@users.sourceforge.net>
 *
 * List all COM ports (esp. including USB devices)
 *
 */

#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tchar.h>
#include <setupapi.h>
#include <stdio.h>

#ifdef _MSC_VER
#pragma comment(lib, "advapi32")
#pragma comment(lib, "setupapi")
#pragma comment(lib, "user32")
#endif

typedef struct tagSERIALPORTINFO
{
    int    nPortNumber;
    LPTSTR pszPortName;
    LPTSTR pszFriendlyName;
    struct tagSERIALPORTINFO* next;
} SERIALPORTINFO, *LPSERIALPORTINFO;

BOOL  GetSerialPortInfo(LPSERIALPORTINFO *ppInfo);

/* ---------------------------------------------------------------------- */

int
_tmain(int argc, TCHAR *argv[])
{
    LPSERIALPORTINFO pPortInfo = 0;
    GetSerialPortInfo(&pPortInfo);
    while (pPortInfo) {
        LPSERIALPORTINFO p = pPortInfo;
        pPortInfo = pPortInfo->next;
        _tprintf(_T("Port %d '%s'\n"), p->nPortNumber, p->pszFriendlyName);
        HeapFree(GetProcessHeap(), 0, p->pszPortName);
        HeapFree(GetProcessHeap(), 0, p->pszFriendlyName);
        HeapFree(GetProcessHeap(), 0, p);
    }
    return 0;
}

/* ---------------------------------------------------------------------- */

static HANDLE
SetupEnumeratePorts()
{
    HDEVINFO hDevices = INVALID_HANDLE_VALUE;
    DWORD dwGuids = 0;    
    BOOL br = SetupDiClassGuidsFromName(_T("Ports"), 0, 0, &dwGuids);
    if (dwGuids) {
        LPGUID pguids = (LPGUID)HeapAlloc(GetProcessHeap(), 0, sizeof(GUID) * dwGuids);
        if (pguids) {
            br = SetupDiClassGuidsFromName(_T("Ports"), pguids, dwGuids, &dwGuids);
            if (br) {
                hDevices = SetupDiGetClassDevs(pguids, NULL, NULL, DIGCF_PRESENT);
            }
            HeapFree(GetProcessHeap(), 0, pguids);
        }
    }
    return hDevices;
}

static BOOL
EndEnumeratePorts(HANDLE hDevices)
{
    if (SetupDiDestroyDeviceInfoList(hDevices)) {
        return TRUE;
    }
    return FALSE;
}

BOOL
GetSerialPortInfo(LPSERIALPORTINFO *ppInfo)
{
    HANDLE hDevices = SetupEnumeratePorts();
    BOOL br = TRUE;
    LPSERIALPORTINFO pHead = 0, pTail = 0;
    DWORD nDevice = 0;

    for (nDevice = 0; br ; nDevice++)
    {
        DWORD cbData = 0;
        SP_DEVINFO_DATA deviceData;

        deviceData.cbSize = sizeof(SP_DEVINFO_DATA);
        br = SetupDiEnumDeviceInfo(hDevices, nDevice, &deviceData);
        if (br)
        {
            TCHAR sz[16] = {0};
            HKEY hkey = SetupDiOpenDevRegKey(hDevices, &deviceData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
            if (hkey)
            {
                DWORD cbSize = 16 * sizeof(TCHAR);
                RegQueryValueEx(hkey, _T("PortName"), NULL, NULL, (LPBYTE)sz, &cbSize);
                RegCloseKey(hkey);
            }
            CharUpper(sz);
            if (sz[0] == _T('C') && sz[1] == _T('O') && sz[2] == _T('M'))
            {
                LPSERIALPORTINFO pInfo = 
                    (LPSERIALPORTINFO)HeapAlloc(GetProcessHeap(), 0, sizeof(SERIALPORTINFO));
                pInfo->next = 0;
                pInfo->pszPortName = 
                    (LPTSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(TCHAR) * (lstrlen(sz) + 1));
                lstrcpy(pInfo->pszPortName, sz);
                pInfo->nPortNumber = _ttoi(&sz[3]);

                SetupDiGetDeviceRegistryProperty(hDevices, &deviceData, SPDRP_FRIENDLYNAME,
                                                 NULL, NULL, 0, &cbData);
                if (cbData)
                {
                    pInfo->pszFriendlyName =
                        (LPTSTR)HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(TCHAR));
                    br = SetupDiGetDeviceRegistryProperty(hDevices, &deviceData, SPDRP_FRIENDLYNAME,
                                                      NULL, (LPBYTE)pInfo->pszFriendlyName, cbData, NULL);
                    pInfo->pszFriendlyName[cbData] = 0;
                }

                if (pTail == 0)
                {
                    pHead = pTail = pInfo;
                }
                else
                {
                    pTail->next = pInfo;
                    pTail = pInfo;
                }
            }
        }
    }
    EndEnumeratePorts(hDevices);
    *ppInfo = pHead;
    return br;
}