As I have only USB ports on my development machine, is quite common at connecting a serial device that I have to go to the device manager to see in which COM port it was installed.
I am developing an application that needs to access a serial device, so I need to get aware of the COM ports installed, either to indicate which to use or to verify the existence of which was already configured.
Researching a bit to not reinvent the wheel, I found this page: http://www.lazarus.freepascal.org/index.php?topic=14313.0 which publishes three interesting functions.
function GetSerialPortNames: string;
var
reg: TRegistry;
l, v: TStringList;
n: integer;
begin
l := TStringList.Create;
v := TStringList.Create;
reg := TRegistry.Create;
try
{$IFNDEF VER100}
reg.Access := KEY_READ;
{$ENDIF}
reg.RootKey := HKEY_LOCAL_MACHINE;
reg.OpenKeyReadOnly('HARDWARE\DEVICEMAP\SERIALCOMM');//, false);
reg.GetValueNames(l);
for n := 0 to l.Count - 1 do
v.Add(reg.ReadString(l[n]));
Result := v.CommaText;
finally
reg.Free;
l.Free;
v.Free;
end;
end;
function GetSerialPortRegNames: string;
var
reg: TRegistry;
l : TStringList;
n: integer;
begin
l := TStringList.Create;
// v := TStringList.Create;
reg := TRegistry.Create;
try
{$IFNDEF VER100}
reg.Access := KEY_READ;
{$ENDIF}
reg.RootKey := HKEY_LOCAL_MACHINE;
reg.OpenKeyReadOnly('HARDWARE\DEVICEMAP\SERIALCOMM');//, false);
reg.GetValueNames(l);
// for n := 0 to l.Count - 1 do
// l[n]:= l[n]+'='+ reg.ReadString(l[n]);
Result := l.CommaText;
finally
reg.Free;
l.Free;
// v.Free;
end;
end;
The last function GetComPortList seeks information from another part of the registry and gets the common name (FriendlyName) of the device installed, which is what I'm wanting.
function GetComPortList(PortList: TStrings): integer;
var
i,idx: integer;
SerPortNum: integer;
Reg: TRegistry;
EnumList: TStrings;
begin
result := -1;
if not CheckMinOS(osWin2k) then
exit;
Reg := TRegistry.Create();
EnumList := TStringList.Create;
try
// Anzahl der Schnittstellen ermitteln
Reg.RootKey := HKEY_LOCAL_MACHINE;
if Reg.OpenKeyReadOnly('\System\CurrentControlSet\Services\SerEnum\Enum') then
begin
SerPortNum := Reg.ReadInteger('Count');
// Registry-Schlüssel der Schnittstellen zwischenspeichern
for i:=0 to SerPortNum-1 do
EnumList.Add(Reg.ReadString(inttostr(i)));
Reg.CloseKey;
// Daten der Schnittstellen ermitteln
for i:=0 to SerPortNum-1 do
begin
// Schnittstellenname ermitteln (z.B. 'COM2')
if Reg.OpenKeyReadOnly('\System\CurrentControlSet\Enum\'+EnumList.Strings[i]+'\Device Parameters') then
idx := PortList.Add(Reg.ReadString('PortName')+'=');
Reg.CloseKey;
// Bezeichnung wie im Gerätemanager ermitteln (z.B. 'USB Serial Port (COM2)' )
if Reg.OpenKeyReadOnly('\System\CurrentControlSet\Enum\'+EnumList.Strings[i]) then
PortList.ValueFromIndex[idx] := Reg.ReadString('FriendlyName');
Reg.CloseKey;
end;
end;
finally
EnumList.Free;
Reg.Free;
end;
result := PortList.Count;
end;
But there is a problem with this last feature, it's looking for the information only in HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\SerEnum. To test I plugged in two serial devices, a generic USB-to-RS232 adapter and a Blu Samba Q cellphone. One of them appears on the sheet SerEnum but the other appears under USBSER, which makes me assume that depending on how it is programmed the device driver, service name is arbitrary and therefore its location in the tree HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services too.
To solve my problem I took as example the first and the third function and made my own.
function GetSerialPortNamesExt: string;
var
reg : TRegistry;
l,v : TStringList;
n : integer;
pn,fn: string;
function findFriendlyName(key: string; port: string): string;
var
r : TRegistry;
k : TStringList;
i : Integer;
ck: string;
rs: string;
begin
r := TRegistry.Create;
k := TStringList.Create;
r.RootKey := HKEY_LOCAL_MACHINE;
r.OpenKeyReadOnly(key);
r.GetKeyNames(k);
r.CloseKey;
try
for i := 0 to k.Count - 1 do
begin
ck := key + k[i] + '\'; // current key
// looking for "PortName" stringvalue in "Device Parameters" subkey
if r.OpenKeyReadOnly(ck + 'Device Parameters') then
begin
if r.ReadString('PortName') = port then
begin
//Memo1.Lines.Add('--> ' + ck);
r.CloseKey;
r.OpenKeyReadOnly(ck);
rs := r.ReadString('FriendlyName');
Break;
end // if r.ReadString('PortName') = port ...
end // if r.OpenKeyReadOnly(ck + 'Device Parameters') ...
// keep looking on subkeys for "PortName"
else // if not r.OpenKeyReadOnly(ck + 'Device Parameters') ...
begin
if r.OpenKeyReadOnly(ck) and r.HasSubKeys then
begin
rs := findFriendlyName(ck, port);
if rs <> '' then Break;
end; // if not (r.OpenKeyReadOnly(ck) and r.HasSubKeys) ...
end; // if not r.OpenKeyReadOnly(ck + 'Device Parameters') ...
end; // for i := 0 to k.Count - 1 ...
result := rs;
finally
r.Free;
k.Free;
end; // try ...
end; // function findFriendlyName ...
begin
v := TStringList.Create;
l := TStringList.Create;
reg := TRegistry.Create;
Result := '';
try
reg.RootKey := HKEY_LOCAL_MACHINE;
if reg.OpenKeyReadOnly('HARDWARE\DEVICEMAP\SERIALCOMM') then
begin
reg.GetValueNames(l);
for n := 0 to l.Count - 1 do
begin
pn := reg.ReadString(l[n]);
fn := findFriendlyName('\System\CurrentControlSet\Enum\', pn);
v.Add(pn + ' = '+ fn);
end; // for n := 0 to l.Count - 1 ...
Result := v.CommaText;
end; // if reg.OpenKeyReadOnly('HARDWARE\DEVICEMAP\SERIALCOMM') ...
finally
reg.Free;
v.Free;
end; // try ...
end;
No hay comentarios.:
Publicar un comentario