Page 1 of 2

Enumerate COM-Ports

Posted: Sat Apr 10, 2004 6:00 pm
by ABBKlaus
Code updated for 5.20+

here is a code-snippet to enumerate the COM-Ports :

Code: Select all

#DIGCF_DEFAULT                     =   1
#DIGCF_PRESENT                     =   2
#DIGCF_ALLCLASSES                  =   4
#DIGCF_PROFILE                     =   8
#DIGCF_DEVICEINTERFACE             =  16
#SPDRP_DEVICEDESC                  =   0
#MAX_CLASS_NAME_LEN                = 128
#DIREG_DEV                         =   1
#DIREG_DRV                         =   2
#DICS_FLAG_GLOBAL                  =   1
#DICS_FLAG_CONFIGSPECIFIC          =   2
#SPDRP_DEVICEDESC                  =   0 ; ECP-Druckeranschluss
#SPDRP_HARDWAREID                  =   1 ; ACPI\PNP0401
#SPDRP_COMPATIBLEIDS               =   2 ; (err13)
#SPDRP_SERVICE                     =   4 ; Parport
#SPDRP_CLASS                       =   7 ; Ports
#SPDRP_CLASSGUID                   =   8 ; {4D36E978-E325-11CE-BFC1-08002BE10318}
#SPDRP_DRIVER                      =   9 ; {4D36E978-E325-11CE-BFC1-08002BE10318}\0000
#SPDRP_CONFIGFLAGS                 =  10 ; 127 (Zahl=Long)
#SPDRP_MFG                         =  11 ; (Standardanschlusstypen)
#SPDRP_FRIENDLYNAME                =  12 ; ECP-Druckeranschluss (LPT1)
#SPDRP_LOCATION_INFORMATION        =  13 ; (err13)
#SPDRP_PHYSICAL_DEVICE_OBJECT_NAME =  14 ; \Device\0000005c
#SPDRP_CAPABILITIES                =  15 ; 48 (Zahl=Long)
#SPDRP_UI_NUMBER                   =  16 ; (err13)
#SPDRP_UPPERFILTERS                =  17 ; (err13)
#SPDRP_LOWERFILTERS                =  18
#SPDRP_BUSTYPEGUID                 =  19
#SPDRP_LEGACYBUSTYPE               =  20
#SPDRP_BUSNUMBER                   =  21
#SPDRP_ENUMERATOR_NAME             =  22 ; ACPI
#SPDRP_SECURITY                    =  23
#SPDRP_SECURITY_SDS                =  24
#SPDRP_DEVTYPE                     =  25
#SPDRP_EXCLUSIVE                   =  26
#SPDRP_CHARACTERISTICS             =  27
#SPDRP_ADDRESS                     =  28
#SPDRP_UI_NUMBER_DESC_FORMAT       =  30

; Structure SP_DEVICE_INTERFACE_DATA
;   cbSize.l
;   InterfaceClassGuid.GUID
;   Flags.l
;   Reserved.l
; EndStructure

Structure SP_DEVINFO_DATA
  cbSize.l
  ClassGuid.GUID
  DevInst.l
  Reserved.l
EndStructure

Structure ComArrayStructure
  ComPort.s
EndStructure

Procedure EnumComPorts()
  zClassName.s="Ports"
  PortName.s=""
  DeviceInterfaceData.SP_DEVICE_INTERFACE_DATA
  DeviceInfoData.SP_DEVINFO_DATA
  hDeviceInfoSet.l=0
  Size.l=0
  hKeyDevice.l=0
  DevCount.l=0
  value.l=0
  value=SetupDiClassGuidsFromName_(zClassName,0,0,@Size) ; only ask for size of array
  If value=0
    err=GetLastError_()
    If err=#ERROR_INSUFFICIENT_BUFFER ; we will get this error and know the arraysize now
      Debug "The data area passed to a system call is too small."
      Debug "RequiredSize : "+Str(Size)
    EndIf
    If Size>0
      Dim GuidArray.GUID(Size)
      value=SetupDiClassGuidsFromName_(zClassName,@GuidArray(1),SizeOf(GUID)*Size,@Size)
      If value>0
        hDeviceInfoSet=SetupDiGetClassDevs_(@GuidArray(1),0,0,#DIGCF_PRESENT)
        err=GetLastError_()
        If err=#ERROR_IO_PENDING Or err=0
          Debug "Overlapped I/O operation is in progress."
          If hDeviceInfoSet<>#INVALID_HANDLE_VALUE
            DeviceInfoData\cbSize=SizeOf(DeviceInfoData)
            DeviceInterfaceData\cbSize=SizeOf(DeviceInterfaceData)
            NewList ComArray.ComArrayStructure()
            Repeat
              value=SetupDiEnumDeviceInfo_(hDeviceInfoSet,DevCount,@DeviceInfoData)
              If value=0
                err=GetLastError_()
                If err=#ERROR_NO_MORE_ITEMS
                  Debug "No more data is available."
                EndIf
                Break
              EndIf
              hKeyDevice=SetupDiOpenDevRegKey_(hDeviceInfoSet,@DeviceInfoData,#DICS_FLAG_GLOBAL,@HwProfile,#DIREG_DEV,#KEY_QUERY_VALUE)
              PortName=Space(128)
              lpValueName.s="portname"
              lpcbData.l=Len(lpValueName)
              RegQueryValueEx_(hKeyDevice,@lpValueName,0,0,@PortName,@lpcbData)
              If Left(PortName,3)="COM"
                AddElement(ComArray())
                ComArray()\ComPort=PortName
                Debug PortName
              EndIf
              RegCloseKey_(hKeyDevice)
              DevCount+1
            ForEver
            If hDeviceInfoSet
              SetupDiDestroyDeviceInfoList_(hDeviceInfoSet)
              hDeviceInfoSet=0
            EndIf
            ForEach ComArray()
              Debug "Found : "+ComArray()\ComPort
            Next
          EndIf
        EndIf
      EndIf
    EndIf
  EndIf
EndProcedure

EnumComPorts()
Converted using Powerbasic Source from http://www.powerbasic.com/support/forum ... 02248.html
(Pierre Bellisle)
Edited 3 times (forgot the constants / Structures / bug in errorhandling thx droopy)

Thanks to Bingo for testing :wink:

Posted: Sat May 08, 2004 11:46 am
by bingo
:( "structure not found SP_DEVICE_INTERFACE_DATA " !?

(pb 3.90)

Posted: Sat May 08, 2004 12:16 pm
by ABBKlaus
Sorry for this Bingo.

Code is fixed now.

Posted: Sat May 08, 2004 2:25 pm
by bingo
:?:
any "SetupDiRemoveDevice" sample to remove any ports (com1 ...) .

thanks .

Great code !

Posted: Sat May 08, 2004 3:51 pm
by DominiqueB
Thank's for sharing,

i've tried some enumeration but with no succes.
I'm interested to enumerate local networked computers.
Do you know how to ?
Same question with printers, or other devices ?

Thank's.

Dominique

Posted: Sat May 08, 2004 5:35 pm
by ABBKlaus
this sample was only converted for enumerating the serial-ports of a system. I wanted to display the com-ports that where actually in our systems rather than to display com1 - com16.
You can change the variable zClassName to any of the following

1394/1394debug/61883/adapter/apmsupport/avc/battery/biometric/
bluetooth/cdrom/computer/decoder/diskdrive/display/ dot4print/enum1394/fdc/gps/hdc/hidclass/image/infrared/
keyboard/legacydriver/media/mediumchanger/mtd/modem/ monitor/mouse/multifunction/multiportserial/net/netclient/ netservice/nettrans/nodriver/pcmcia/ports/printer/
printer upgrade/processor/pnpprinters/sbp2/scsiadapter/ security accelerator/smartcardreader/sound/system/tapedrive/ unknown/usb/volume/volumesnapshot/wceusbs

DominiqueB what did you tried with no success ? let us discuss it here :D
and don´t forget to modify the above code to this :

Code: Select all

;             If Left(PortName,3)="COM" 
                AddElement(ComArray()) 
                ComArray()\ComPort=PortName 
                Debug PortName 
;             EndIf 
 

Posted: Sat May 08, 2004 5:50 pm
by fweil
...,

Maybe you could parse IP addresses of a given class if you are working on an IP based network ?

If this is the case, I can help you to solve this.

Rgrds

Thank's for helpping .

Posted: Sat May 08, 2004 6:51 pm
by DominiqueB
Ok, here what i've for now:

Code: Select all

; '==============================================================================
; '  Network Resource List.
; '  Enumerate all of the networks and network resources available to the
; '  current machine.
; '==============================================================================
Global ListPC.s

Procedure EnumAll(*nr.NETRESOURCE )
  Dim n.NETRESOURCE(256)
  Entries.l = 256
  nSize.l = SizeOf(NETRESOURCE) * Entries
  ec.l = WNetOpenEnum_(#RESOURCE_GLOBALNET, #RESOURCETYPE_ANY, #Null, *nr, *hEnum.l)
  ec = WNetEnumResource_(*hEnum, *Entries, n(1), *nSize)
  
  For x.l = 1 To Entries
    If (n(x)\dwUsage And #RESOURCEUSAGE_CONTAINER)
      If (n(x)\dwType And #RESOURCETYPE_DISK) And (PeekS(n(x)\lpRemoteName, 2) = "\\")
        ListPC = ListPC + Trim(PeekS(n(x)\lpRemoteName, 256)) + " "
      EndIf
      EnumAll(@n(x))
    EndIf
  Next
EndProcedure


ProcedureDLL LitNet()
  EnumAll(#Null)
  MessageRequester("Liste des postes: ", ListPC, 0)
  ProcedureReturn @ListPC
EndProcedure

My goal is to enumerate all PC connected to the local network area.

Actualy i use the "Net View" command from dos to produce a .txt that i decode after. It works well but my goal is to incorporate all that functions into a dll.

Actually this dll contains some usfull functions like:
GetDate: to let a user to select a date from the windows calendar
ConcatFic: to concatenate some fics given their extension
GetVolumeName: that return volume name given it's letter
PingPoste: do a quick ping to a computer given it's name on the lan

Thank's for your help on the code above, not completly from me but ported from powerbasic source

Posted: Sat May 08, 2004 8:47 pm
by ABBKlaus
Your code didn´t return anything on my PC :(

i tried it this way

Code: Select all

lpnr.NETRESOURCE
dwResult.l     = 0
dwResultEnum.l = 0
hEnum.l        = 0
cEntries.l     = -1
cbBuffer.l     = 32768
i.l            = 0
j.l            = 0
*Buffer = AllocateMemory(cbBuffer)
dwResult.l     = WNetOpenEnum_(#RESOURCE_GLOBALNET, #RESOURCETYPE_ANY, #Null, *lpnr, @hEnum) 
If dwResult = #NO_ERROR
  Debug "No Error"
  dwResultEnum = WNetEnumResource_(hEnum,@cEntries,*Buffer,@cbBuffer)
  Debug "Error : "+Str(dwResultEnum)
  Debug "Entries : "+Str(cEntries)
  If dwResultEnum=#ERROR_INVALID_ADDRESS
    Debug "ERROR_INVALID_ADDRESS"
  EndIf
  CreateFile(1,"test.bin")
    WriteData(*Buffer,cbBuffer)
  CloseFile(1)
  For i = 1 To cEntries
    j = (i-1)*SizeOf(NETRESOURCE)
    If PeekL(*Buffer+j+20)<>0
      Debug PeekS(PeekL(*Buffer+j+20))
    EndIf
    If PeekL(*Buffer+j+24)<>0
      Debug PeekS(PeekL(*Buffer+j+24))
    EndIf
  Next
EndIf

WNetCloseEnum_(hEnum)
but returned only this :
No Error
Error : 0
Entries : 3
Microsoft-Terminaldienste
Microsoft Windows-Netzwerk
Web Client Network
:!: don´t think this helps you perhaps you should give us a link to the POWERBASIC resource site you mentioned above :?:

Thank's for help

Posted: Sat May 08, 2004 9:27 pm
by DominiqueB
Here it is:

Code: Select all

'==============================================================================
'  Network Resource List.
'  Enumerate all of the networks and network resources available to the
'  current machine.
'==============================================================================
#Include "WIN32API.INC"
Global s As String

Sub EnumAll (nr As NETRESOURCE)
  Local hEnum   As Long
  Local Entries As Long
  Local nSize   As Long
  Local ec      As Long
  Local x       As Long
  'Static s As String
  Dim n(1 To 256) As NETRESOURCE

  Entries = 256
  nSize   = SizeOf(nr) * Entries
  's = s + "  "
  ec = WNetOpenEnum(%RESOURCE_GLOBALNET, %RESOURCETYPE_ANY, %NULL, nr, hEnum)
  ec = WNetEnumResource(hEnum, Entries, n(1), nSize)
  For x = 1 To Entries
    'MsgBox Left$(s & n(x).@lpRemoteName + Space$(40), 40) + n(x).@lpComment
    If (n(x).dwUsage And %RESOURCEUSAGE_CONTAINER) Then
        If (n(x).dwType And %RESOURCETYPE_DISK) And(Left$(n(x).@lpRemoteName, 2) = "\\") Then
            'msgbox "Nom trouvé: " & n(x).@lpRemoteName
            s = s & n(x).@lpRemoteName + " "
        End If
      EnumAll n(x)
    End If
  Next
  's = Left$(s, Len(s) - 2)
End Sub

Function PBMain() As Long
  'Local u As Asciiz * 256

  'GetUserName u, 256
  'MsgBox "Network Resource List for " & u

  EnumAll ByVal %NULL
  MsgBox "Chaine: " & s

End Function
That was my try to translate from Powerbasic to Pure, so you could be more succesful than me to do the task ?

Thank's.

Posted: Sat May 08, 2004 10:47 pm
by ABBKlaus
DominiqueB its done 8)

i had problems with the array and replaced it !

since i buyed a license of the Powerbasic Console Compiler i where able to test the code from POWERBASIC directly.

have fun with it :D

Code: Select all

; '============================================================================== 
; '  Network Resource List. 
; '  Enumerate all of the networks and network resources available to the 
; '  current machine. 
; ' converted using http://www.powerbasic.com/support/forums/Forum6/HTML/001494.html
; '============================================================================== 

Global s.s
Global hOutput.l

Procedure EnumAll(*nr.NETRESOURCE)
  tempnr.NETRESOURCE
  hEnum.l
  Entries.l
  nSize.l
  ec.l
  x.l
  j.l
  Entries = -1
  nSize = 16384
  s = s + "  "
  ec = WNetOpenEnum_(#RESOURCE_GLOBALNET, #RESOURCETYPE_ANY, #Null, *nr, @hEnum) 
  ;Debug "Error : "+Str(ec)
  ;Debug "Entries : "+Str(Entries)
  ;Debug "Size : "+Str(nSize)
  *Buffer=AllocateMemory(nSize)
  ec = WNetEnumResource_(hEnum,@Entries,*Buffer,@nSize)
  ;Debug "Error : "+Str(ec)
  ;Debug "Entries " + Str(Entries)
  For x = 1 To Entries
    j = (x-1)*SizeOf(NETRESOURCE)
    tempnr\dwScope        = PeekL(*Buffer+j+0)
    tempnr\dwType         = PeekL(*Buffer+j+4)
    tempnr\dwDisplayType  = PeekL(*Buffer+j+8)
    tempnr\dwUsage        = PeekL(*Buffer+j+12)
    tempnr\lpLocalName    = PeekL(*Buffer+j+16)
    tempnr\lpRemoteName   = PeekL(*Buffer+j+20)
    tempnr\lpComment      = PeekL(*Buffer+j+24)
    tempnr\lpProvider     = PeekL(*Buffer+j+28)
    RemoteName.s=""
    Comment.s=""
    If tempnr\lpRemoteName
      RemoteName = Left(s + PeekS(tempnr\lpRemoteName) +Space(40),40)
    EndIf
    If tempnr\lpComment
      Comment = PeekS(tempnr\lpComment)
    EndIf
    Debug RemoteName+Comment
    If (tempnr\dwUsage And #RESOURCEUSAGE_CONTAINER)
      EnumAll (tempnr)
    EndIf
  Next
  s = Left(s, Len(s) -2)
  WNetCloseEnum_(hEnum)
EndProcedure

EnumAll(#null)

Posted: Sat May 08, 2004 10:49 pm
by ABBKlaus
Above code returns this for example :

Code: Select all

  Microsoft-Terminaldienste             
  Microsoft Windows-Netzwerk            
    SUPERFAST                           
      \\KLAUSP4                         
        \\KLAUSP4\HP                    hp deskjet 990c series
        \\KLAUSP4\Big120                
        \\KLAUSP4\Data                  
        \\KLAUSP4\in                    
        \\KLAUSP4\Scan_Dat              
        \\KLAUSP4\Big100                
        \\KLAUSP4\_Tools                
        \\KLAUSP4\Kyocera               Kyocera FS-1750 KX
        \\KLAUSP4\$LOG                  
      \\MEDION                          
        \\MEDION\Backup                 
        \\MEDION\scan_dat               
        \\MEDION\Tools New              
        \\MEDION\$LOG                   
  Web Client Network

Posted: Sat May 08, 2004 11:41 pm
by fweil
ABBKlaus,

I just corrected the enum part doing structure calls more clear. It is just that you used a buffer for transfering bytes, which is not necessary.

I also embedded the rendering by using a window to list items.

I was doing it when you sent your response to the post. So I mixed both my and your code !

Code: Select all

; '============================================================================== 
; '  Network Resource List. 
; '  Enumerate all of the networks and network resources available to the 
; '  current machine. 
; ' converted using http://www.powerbasic.com/support/forums/Forum6/HTML/001494.html 
; '============================================================================== 
#Window_Main = 0
#Gadget_ListIcon = 0

Global s.s 

Procedure EnumAll(*nr.NETRESOURCE) 
  n.NETRESOURCE 
  Entries = -1 
  nSize = 16384 
  s = s + "  " 
  ec = WNetOpenEnum_(#RESOURCE_GLOBALNET, #RESOURCETYPE_ANY, #NULL, *nr, @hEnum)
  If hEnum
      ec = WNetEnumResource_(hEnum, @Entries, @n, @nSize)
      For x = 1 To Entries
        Response.s = ""
        Select n\dwScope
          Case #RESOURCE_CONNECTED
            Response = Response + "#RESOURCE_CONNECTED" + Chr(10)
          Case #RESOURCE_GLOBALNET
            Response = Response + "#RESOURCE_GLOBALNET" + Chr(10)
          Case #RESOURCE_REMEMBERED
            Response = Response + "#RESOURCE_REMEMBERED" + Chr(10)
          Default
            Response = Response + "dwScope unknown" + Chr(10)
        EndSelect
        Select n\dwType
          Case #RESOURCETYPE_ANY
            Response = Response + "#RESOURCETYPE_ANY" + Chr(10)
          Case #RESOURCETYPE_DISK
            Response = Response + "#RESOURCETYPE_DISK" + Chr(10)
          Case #RESOURCETYPE_PRINT
            Response = Response + "#RESOURCETYPE_PRINT" + Chr(10)
          Default
            Response = Response + "dwType unknown" + Chr(10)
        EndSelect
        Select n\dwDisplayType
          Case #RESOURCEDISPLAYTYPE_DOMAIN
            Response = Response + "#RESOURCEDISPLAYTYPE_DOMAIN" + Chr(10)
          Case #RESOURCEDISPLAYTYPE_GENERIC
            Response = Response + "#RESOURCEDISPLAYTYPE_GENERIC" + Chr(10)
          Case #RESOURCEDISPLAYTYPE_SERVER
            Response = Response + "#RESOURCEDISPLAYTYPE_SERVER" + Chr(10)
          Case #RESOURCEDISPLAYTYPE_SHARE
            Response = Response + "#RESOURCEDISPLAYTYPE_SHARE" + Chr(10)
          Default
            Response = Response + "dwDisplayType unknown" + Chr(10)
        EndSelect
        Select n\dwUsage
          Case #RESOURCEUSAGE_CONNECTABLE
            Response = Response + "#RESOURCEUSAGE_CONNECTABLE" + Chr(10)
          Case #RESOURCEUSAGE_CONTAINER
            Response = Response + "#RESOURCEUSAGE_CONTAINER" + Chr(10)
          Default
            Response = Response + "dwUsage unknown" + Chr(10)
        EndSelect
        LocalName.s = ""
        If n\lpLocalName
            LocalName = PeekS(n\lpLocalName)
          Else
            LocalName = ""
        EndIf
        RemoteName.s = ""
        If n\lpRemoteName
            RemoteName = PeekS(n\lpRemoteName)
          Else
            RemoteName = ""
        EndIf
        Response = LocalName + Chr(10) + RemoteName + Chr(10) + Response
        Comment.s = ""
        If n\lpComment
            Comment = PeekS(n\lpComment)
            Response = Response + Comment + Chr(10)
        EndIf
        Provider.s = ""
        If n\lpProvider
            Provider = PeekS(n\lpProvider)
            Response = Response + Provider + Chr(10)
        EndIf
        AddGadgetItem(#Gadget_ListIcon, -1, Response)
        While WindowEvent()
        Wend
        If (n\dwUsage And #RESOURCEUSAGE_CONTAINER) 
          EnumAll (@n) 
        EndIf 
      Next 
      s = Left(s, Len(s) -2) 
      WNetCloseEnum_(hEnum) 
  EndIf
EndProcedure 

;
; Main starts here
;
  Quit = #FALSE
  WindowXSize = 800
  WindowYSize = 320
  If OpenWindow(#Window_Main, 0, 0, WindowXSize, WindowYSize, #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget | #PB_Window_TitleBar | #PB_Window_ScreenCentered, "MyWindow")
      AddKeyboardShortcut(0, #PB_Shortcut_Escape, #PB_Shortcut_Escape)
      If CreateGadgetList(WindowID())
          SetGadgetFont(#PB_Default, LoadFont(0, "Verdana", 7))
          ListIconGadget(#Gadget_ListIcon, 10, 10, WindowXSize - 20, WindowYSize - 20, "Local name", 120, #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect)
          AddGadgetColumn(#Gadget_ListIcon, 1, "Remote name", 120)
          AddGadgetColumn(#Gadget_ListIcon, 2, "Scope", 120)
          AddGadgetColumn(#Gadget_ListIcon, 3, "Type", 120)
          AddGadgetColumn(#Gadget_ListIcon, 4, "Display type", 120)
          AddGadgetColumn(#Gadget_ListIcon, 5, "Usage", 120)
          AddGadgetColumn(#Gadget_ListIcon, 7, "Comment", 120)
          AddGadgetColumn(#Gadget_ListIcon, 8, "Provider", 120)
      EndIf
      EnumAll(#NULL)
      Repeat
        Select WaitWindowEvent()
          Case #PB_Event_CloseWindow
            Quit = #TRUE
          Case #PB_Event_Menu
            Select EventMenuID()
              Case #PB_Shortcut_Escape
                Quit = #TRUE
            EndSelect
          Case #PB_EventGadget
            Select EventGadgetID()
            EndSelect
          Case #WM_SIZE
            WindowXsize = WindowWidth()
            WindowYSize = WindowHeight()
            ResizeGadget(#Gadget_ListIcon, 10, 10, WindowXSize - 20, WindowYSize - 20)
          Default
        EndSelect
      Until Quit
  EndIf
End

Great !

Posted: Sun May 09, 2004 12:27 am
by DominiqueB
Thank's a lot, i'll try all that work on Monday.
ABBKlaus, i tested here on xp but the table stays empty ?
I have no lan here, is it the reason why ?

Thank's

Posted: Sun May 09, 2004 12:34 am
by fweil
I am running a W2K as a server but don"t have any other resource to test locally. So the list answers just that I am a Windows Resource at the top containing Workgroup. I cannot test further here.

Tell me what it renders in a true bigger Lan on monday.

Have a nice WE