Page 1 of 1
VB -> PB conversion
Posted: Wed Oct 17, 2007 5:40 pm
by dhouston
I have some VB code which I probably got originally from some online VB code archive. I've long used it to enumerate the COM ports. I want to convert it to PB but am still too new to PB to manage without lots of help. It has always proven reliable, unlike other methods which rely on registry entries. It returns hardware COM ports, USB->serial adapters and virtual ports used with ethernet serial device servers. Here's the VB code...
Code: Select all
Private Type PORT_INFO_2
pPortName As String
pMonitorName As String
pDescription As String
fPortType As Long
Reserved As Long
End Type
Private comPorts(0 To 100) As PORT_INFO_2
Private Function GetAvailablePorts(ServerName As String) As Long
Dim ret As Long
Dim PortsStruct(0 To 100) As API_PORT_INFO_2
Dim pcbNeeded As Long
Dim pcReturned As Long
Dim TempBuff As Long
Dim i As Integer
'Get the number of bytes needed to contain the data returned by the API call
ret = EnumPorts(ServerName, 2, TempBuff, 0, pcbNeeded, pcReturned)
'Allocate the Buffer
TempBuff = HeapAlloc(GetProcessHeap(), 0, pcbNeeded)
ret = EnumPorts(ServerName, 2, TempBuff, pcbNeeded, pcbNeeded, pcReturned)
If ret Then
'Convert the returned String Pointer Values to VB String Type
'CopyMem is aliased RtlMoveMemory
CopyMem PortsStruct(0), ByVal TempBuff, pcbNeeded
For i = 0 To pcReturned - 1
comPorts(i).pDescription = Ptr2Str(PortsStruct(i).pDescription)
comPorts(i).pPortName = Ptr2Str(PortsStruct(i).pPortName)
comPorts(i).pMonitorName = Ptr2Str(PortsStruct(i).pMonitorName)
comPorts(i).fPortType = PortsStruct(i).fPortType
Next
End If
GetAvailablePorts = pcReturned
'Free the Heap Space allocated for the Buffer
If TempBuff Then
HeapFree GetProcessHeap(), 0, TempBuff
End If
End Function
I really don't yet grasp the details of structures in PB. Also, the EnumPorts API function returns Unicode which needs to be converted to ASCII.
The data returned tend to contain duplicate entries which have to be filtered and also returns Infrared and other ports which also need filtering. In VB, I use the filtered results to add items to a Port menu.
Posted: Wed Oct 17, 2007 6:36 pm
by ABBKlaus
here is my approach :
Code: Select all
Structure API_PORT_INFO_2
PortName.s
MonitorName.s
Description.s
PortType.l
Reserved.l
EndStructure
Global NewList Portinfos.API_PORT_INFO_2()
Procedure.l GetAvailablePorts(ServerName.s="")
;http://www.purebasic.fr/english/viewtopic.php?p=215002#215002
Protected res.l
Protected pcbNeeded.l
Protected pcReturned .l
Protected *TempBuff
Protected i.l
Protected *pName
If ServerName=""
*pName=0
Else
*pName=@ServerName
EndIf
;Dim PortsStruct(0 To 100) As API_PORT_INFO_2
;Get the number of bytes needed To contain the Data returned by the API call
ret = EnumPorts_(*pName, 2, 0, 0, @pcbNeeded, @pcReturned)
If pcbNeeded
Debug "pcbNeeded = "+Str(pcbNeeded)+" Bytes"
*TempBuff = AllocateMemory(pcbNeeded) ; Allocate the Buffer
ret = EnumPorts_(*pName, 2, *TempBuff, pcbNeeded, @pcbNeeded, @pcReturned)
If ret
Debug "Ports received = "+Str(pcReturned)
;Conversion is not needed, PB makes it ;-)
For i = 0 To pcReturned - 1
;set structure over the memory area
*strPortinfos.PORT_INFO_2=*TempBuff+(i*SizeOf(PORT_INFO_2))
AddElement(Portinfos())
Portinfos()\PortName=PeekS(*strPortinfos\pPortName)
Portinfos()\MonitorName=PeekS(*strPortinfos\pMonitorName)
Portinfos()\Description=PeekS(*strPortinfos\pDescription)
Portinfos()\PortType=*strPortinfos\fPortType
Next
EndIf
;Free the Heap Space allocated for the Buffer
If *TempBuff
FreeMemory(*TempBuff)
EndIf
EndIf
ProcedureReturn pcReturned
EndProcedure
If GetAvailablePorts("\\Klaus-Core2")
ForEach Portinfos()
Debug Portinfos()\PortName
Debug Portinfos()\MonitorName
Debug Portinfos()\Description
Debug Portinfos()\PortType
Debug "-------------------------------------------------------------"
Next
EndIf
Posted: Wed Oct 17, 2007 7:22 pm
by dhouston
Thank you.
Now, I'll try to work through it and understand the how and why of your conversion. I think this is the last major thing I needed get a handle on in order to start converting several VB apps to PB.
Posted: Wed Oct 17, 2007 8:32 pm
by TerryHough
Take a look here in my PureBasic web are too
http://elfecc.no-ip.info/purebasic/#Info_SerialPorts
Something I did long ago to check out the COM ports. Might help you.
Posted: Wed Oct 17, 2007 10:02 pm
by dhouston
@TerryHough
I spent a few weeks reading the forums and cruising all the code archives I could find, bookmarking posts and web pages that looked helpful for the things I knew I would need to do. I bookmarked your page with the intention of returning to steal as much as I could carry but I haven't been able to connect to it since then until just now when the link worked fine. I have now downloaded your serial port, device enumeration, and atomic clock examples and will look them over. Thanks.
Posted: Thu Oct 18, 2007 6:46 pm
by dhouston
Here's the debug output from my VB app followed by my partially converted PB app. COM1, COM3 & COM5 are valid serial ports.
Code: Select all
COM5 Virtual Serial Port 5
COM3 USB to Serial Port 3
COM1 Communications Port 1
LPT1 EPSON Printer Port 1
COM4 Infrared Serial (COM) Port 4
LPT3 Infrared Printing (LPT) Port 3
D-Link LPT port Print Server 0
FILE Unknown Local Port 0
FILE Creates a file on disk 0
COM5 Virtual Serial Port 5
COM3 USB to Serial Port 3
COM1 Communications Port 1
LPT1 EPSON Printer Port 1
COM4 Infrared Serial (COM) Port 4
LPT3 Infrared Printing (LPT) Port
pcbNeeded = 889 Bytes
Ports received = 15
COM5: Local Port Virtual Serial Port 1
-------------------------------------------------------------
COM3: Local Port USB to Serial Port 1
-------------------------------------------------------------
COM1: Local Port Communications Port 1
-------------------------------------------------------------
LPT1: Local Port EPSON Printer Port 3
-------------------------------------------------------------
COM4: Local Port Infrared Serial (COM) Port 1
-------------------------------------------------------------
LPT3: Local Port Infrared Printing (LPT) Port 3
-------------------------------------------------------------
D-Link LPT port Local Port Print Server 1
-------------------------------------------------------------
FILE: Local Port Unknown Local Port 1
-------------------------------------------------------------
FILE: Local Port Creates a file on disk 1
-------------------------------------------------------------
COM5: Local Port Virtual Serial Port 3
-------------------------------------------------------------
COM3: Local Port USB to Serial Port 3
-------------------------------------------------------------
COM1: Local Port Communications Port 3
-------------------------------------------------------------
LPT1: Local Port EPSON Printer Port 3
-------------------------------------------------------------
COM4: Local Port Infrared Serial (COM) Port 3
-------------------------------------------------------------
LPT3: Local Port Infrared Printing (LPT) Port 3
-------------------------------------------------------------
Posted: Thu Feb 05, 2009 9:51 pm
by RichardL
@dhouston
I have been trying to put a solution together to find all the real and virtual comm ports on a machine into a list; and stumbled on your code. After a bit of work I managed to get a list of ports that are supposed to be on my machine, but there seems to be too many
Did you ever take your code through to the bitter end? The problem I have is that some of the machines I run code on have a ton of Bluetooth virtual com ports and when I try to probe them to look for expected hardware I might as well go out for a beer it takes so long.
Any tips to stop me becoming an alcoholic?
Cheers
RichardL
Posted: Fri Feb 06, 2009 2:23 am
by dhouston
RichardL wrote:Did you ever take your code through to the bitter end? The problem I have is that some of the machines I run code on have a ton of Bluetooth virtual com ports and when I try to probe them to look for expected hardware I might as well go out for a beer it takes so long.
This code works well for me (under Windows) but I don't have any Bluetooth ports so it may need modification for them.
Code: Select all
;========================================================
;
; SerialPorts.pbi
;
;========================================================
Structure API_PORT_INFO_2
PortName.s
MonitorName.s
Description.s
PortType.l
Reserved.l
EndStructure
#BufferIn = 1024
#BufferOut = 1024
Global ports.s,ComPort.s
Global NumPorts,ComID
Procedure.l GetAvailablePorts(ServerName.s="")
NewList Portinfos.API_PORT_INFO_2()
NewList ComPorts()
Protected item.s,SaveSetting.s
Protected res.l, pcbNeeded.l,pcReturned .l,i.l,ret.l
Protected *TempBuff,*pName,*strPortinfos.PORT_INFO_2
If ServerName=""
*pName=0
Else
*pName=@ServerName
EndIf
;Get the number of bytes needed To contain the Data returned by the API call
ret=EnumPorts_(*pName,2,0,0,@pcbNeeded,@pcReturned)
If pcbNeeded
;Debug "pcbNeeded = "+Str(pcbNeeded)+" Bytes"
*TempBuff=AllocateMemory(pcbNeeded) ; Allocate the Buffer
ret=EnumPorts_(*pName,2,*TempBuff,pcbNeeded,@pcbNeeded,@pcReturned)
If ret
;Debug "Ports received = "+Str(pcReturned)
For i = 0 To pcReturned - 1
;set structure over the memory area
*strPortinfos.PORT_INFO_2=*TempBuff+(i*SizeOf(PORT_INFO_2))
AddElement(Portinfos())
Portinfos()\PortName=PeekS(*strPortinfos\pPortName)
Portinfos()\MonitorName=PeekS(*strPortinfos\pMonitorName)
Portinfos()\Description=PeekS(*strPortinfos\pDescription)
Portinfos()\PortType=*strPortinfos\fPortType
;Debug Portinfos()\Description
;Debug Portinfos()\PortName
;Debug Portinfos()\PortType
;Debug Portinfos()\MonitorName
;Debug "-------------"
If Not FindString(LCase(Portinfos()\Description),"infrared",1)
If Not FindString(LCase(Portinfos()\Description),"modem",1)
If Not FindString(ports,Portinfos()\PortName,1)
If Left(Portinfos()\PortName,3)="COM" And FindString(Portinfos()\Description," Port",1)
ComPort=RemoveString(Portinfos()\PortName,":")
ComID=OpenSerialPort(#PB_Any,ComPort,19200,#PB_SerialPort_NoParity,8,1,#PB_SerialPort_NoHandshake,1024,1024)
If IsSerialPort(ComID)
AddElement(ComPorts())
ComPorts()=Val(Mid(Portinfos()\PortName,4,3)) ;COM1-COM256
CloseSerialPort(ComID):Delay(25)
EndIf
EndIf
EndIf
EndIf
EndIf
Next
EndIf
ComID=0:ports=""
SortList(ComPorts(),0)
ForEach ComPorts()
item="COM"+Str(ComPorts())+":"
If FindString(ports,item,1)=0 ;avoid duplicates
ports+item
numPorts+1
EndIf
Next
;Debug ports
;Free the Heap Space allocated For the Buffer
If *TempBuff
FreeMemory(*TempBuff)
EndIf
EndIf
OpenPreferences("roZetta.prf"):PreferenceGroup("Global")
ComPort=ReadPreferenceString("ComPort","COM1")
ClosePreferences()
ProcedureReturn pcReturned
EndProcedure
Any tips to stop me becoming an alcoholic?
You can send me the booze instead of drinking it yourself.

Posted: Fri Feb 06, 2009 2:14 pm
by RichardL
@dhouston
Hi, thanks for your assistance, I have delved into your code and modified it to make a simpler version for my purposes, which is to establish a list of available serial ports. I was quite surprised by the results when I tested it with various serial adaptors.
I have started a new thread with the title "Discovering ports with EnumPorts()", not in any way because your thread is a bad choice in which to continue, but to move under a more relevant title.
Again, thanks for your help.
RichardL