Belegte COM-Ports herausfinden



  • Hallo,
    weiß jemand, wie man mit C oder einer anderen Sprache, die belegten COM-Ports herausfinden kann?

    Danke im Voraus. 🙂

    L. G.
    Steffo





  • Super, danke! 🙂



  • In Python ist die Registry-Lösung (HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM) übrigens mit wenigen Zeilen Code gelöst. Man braucht dafür das Modul _winreg.
    Posten darf ich die Lösung leider nicht, da ich das bei meinem Arbeitgeber entwickelt habe.

    L. G.
    Steffo



  • Der Vorschlag vom martiniclan scheint ja wirklich viele Möglichkeiten zu enthalten:

    1. WinAPI
    2. WMI
    3. Registry

    Die einfachste Möglichkeit ist vermutlich:

    BOOL EnumerateCOM(CSimpleArray<UINT>& ports)
    {
      // clear elements which may already be in the array
      ports.RemoveAll();
    
      // try any possible port
      for (UINT i=1; i<256; i++)
      {
        //Form the Raw device name
        CString sPort;
        sPort.Format(_T("\\\\.\\COM%d"), i);
    
        //Try to open the port
        BOOL bSuccess = FALSE;
        HANDLE hPort = ::CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
        if (hPort != INVALID_HANDLE_VALUE) {
          CloseHandle(hPort); // close port, do nothing with it anyway
          bSuccess = TRUE; // port opened successfully
        }
        //else {
        //  DWORD dwError = GetLastError();
        //  Check to see if the error was because some other app had the port open
        //  or a general failure
        //  if (dwError == ERROR_ACCESS_DENIED || dwError == ERROR_GEN_FAILURE ||
        //  dwError == ERROR_SHARING_VIOLATION || dwError == ERROR_SEM_TIMEOUT)
        //    bSuccess = TRUE;
        //  }
    
        //Add the port number to the array which will be returned
        if (bSuccess) {
          ports.Add(i);
        }
      }
    
      //Return the success indicator
      return TRUE;
    }
    

    Wobei man nur die erfolgreichen Zugriffe zaehlt ...

    Wenn man weder STL noch ATL mag würde es wohl auch ohne gehen 😋



  • merano schrieb:

    Die einfachste Möglichkeit ist vermutlich:

    // ...
    
      // try any possible port
      for (UINT i=1; i<256; i++)
      {
        //...
      }
    

    Mit dieser Holzhammermethode sind wir vorher lange Zeit vorgegangen, aber mein Vorgesetzter fand die Lösung nicht gut und sprach auch von Peformance-Einbußen (ohne dass er vermutlich mal konkret gemessen hat).

    Die beste Lösung finde ich immernoch die mit der Registry.

    L. G.
    Steffo



  • createFile kann schonmal mehrere Minuten brauchen, wenn das angeschlossene Gerät nicht reagiert. Ist mir bei dem eigenen entwickelten Gerät passiert und bei einem Bluetooth-Gerät, dass irgendwie was mit COM-Ports zu tun hatte.

    Meine Lösung:

    int getNumberOfComs(){
    	int coms = 0;
    	HDEVINFO devinfo;
    	SP_DEVINFO_DATA devInfoData;
    	ZeroMemory(&devInfoData, sizeof(devInfoData));
    	devInfoData.cbSize = sizeof(devInfoData);
    
    	devinfo = SetupDiGetClassDevs(0, 0, 0, DIGCF_ALLCLASSES | DIGCF_PRESENT);
    	if (devinfo == INVALID_HANDLE_VALUE){
    		RAISEERROR(L"No dev info!");
    		return -1;
    	}
    	{
    		int i;
    		for (i = 0; SetupDiEnumDeviceInfo(devinfo, i, &devInfoData); i++){
    			DWORD regDataType;
    			char devicename[300];
    			if (SetupDiGetDeviceRegistryPropertyA(devinfo, &devInfoData, SPDRP_FRIENDLYNAME, &regDataType, (BYTE *)devicename, sizeof devicename, NULL)){
    				if (endswith(devicename, "(COM ?)")){
    					coms++;
    				}
    			}
    		}
    	}
    	SetupDiDestroyDeviceInfoList(devinfo);
    	return coms;
    }
    

    Effektiv geht das die Geräte durch, die im Gerätemanager gelistet sind, und kuckt ob hinten (COM Zahl) steht.
    Die Funktion endswith habe ich mir eben ausgedacht, aber das sollte man schon hinkriegen.



  • Steffo schrieb:

    Mit dieser Holzhammermethode sind wir vorher lange Zeit vorgegangen, aber mein Vorgesetzter fand die Lösung nicht gut und sprach auch von Peformance-Einbußen (ohne dass er vermutlich mal konkret gemessen hat).

    Um es mal etwas konkreter zu machen hab ich es ausprobiert.

    Es kommt bei mir mit GetSystemTime() immer 78 ms raus.

    Es wird nur ein freier Port gefunden.

    Vermutlich benötigt das Öffnen eines Ports die meiste Zeit. da dieser Wert
    offensichtlich unabhängig von der Anzahl der durchsuchten Ports rauskommt.
    (Habe 10 und 2560 ausprobiert).

    Der Vorteil bei dieser angeblichen Holzhammermethode ist, das man den Port wirklich öffnen kann - egal ob realer oder virtueller COM-Port.

    Da es sich bei der seriellen Schnittstelle aber ohnehin um eine eher langsame Schnittstelle handelt, ist "Performance" hier wohl eher nicht so wichtig.



  • @merano
    Und was ist mit Ports die gerade offen sind?

    Registry durchackern finde ich jetzt auch nicht so berauschend. Die Lösung mit QueryDosDevice() gefällt mir da schon viel besser.



  • hustbaer schrieb:

    @merano
    Und was ist mit Ports die gerade offen sind?

    Dann nimmt man den auskommentierten Teil dazu. Das hat der Fragesteller aber gerade nicht gewollt.

    EDIT:
    Nach nochmaligen Lesen: Oder wollte er nur die belegten ???



  • *StirnPatsch*

    Jopp, hätte ich selber sehen können 🙂


Anmelden zum Antworten