Title: Enumerate COM Servers
Question: I needed a Class to Enumerate all Registered COM Objects so that I could Retrieve the Prog ID`s.
Answer:
The only way to do this, it seems, it to search through the first level of the HKEY_CLASSES_ROOT and look for subkeys of CLSID.
If the Key has a CLSID subkey it is a COM object of sorts. Open the CLDID GUID in the CLSID Key and look for PROGID Key and INPROCServer* Key.
There are usually a couple of variants to the availabe keys - There might be an InprocServer32 Key and or an InprocServer Key or an InprocHandler Key.
In this example I habe only searched for InprocServer32 Keys, as the Sub Class Items will get quite complicated in I was to look for everything.
Below is a class that handles this process. One should make it into a component or Com Object, but I'll leave that up to you.
unit Class_ComEnum;
interface
Uses Registry,Classes,Sysutils;
Type
TComItem = Class
Private
fProgID : String;
fCLSID : String;
fInprocServer : String;
fTypeLib : String;
fVersion : String;
Public
Published
Property ProgID : String Read fProgId Write fProgId;
Property CLSID : String Read fCLSID Write fCLSID;
Property InprocServer : String Read fInprocServer Write fInprocServer;
Property TypeLib : String Read fTypeLib Write fTypeLib;
Property Version : String Read fVersion Write fVersion;
end;
TComEnumProgress = Procedure(Sender : TObject;total,position : Integer) of object;
TComEnum = Class
Private
Reg : TRegistry;
ComList : TList;
eProgress : TComEnumProgress;
function GetComCount: Integer;
Public
Procedure BuildList;
Function GetItem(Index : Integer) : TComItem;
Constructor Create;
Destructor Destroy;override;
Published
Property ComCount : Integer Read GetComCount;
property OnProgress :TComEnumProgress Read eProgress Write eProgress;
End;
Var
ComEnum : TComEnum;
implementation
Uses Windows,Dialogs;
{ TComEnum }
procedure TComEnum.BuildList;
Var
KeyList : TStringList;
Count : Integer;
fCLSID : String;
Temp : TComItem;
test : Boolean;
KeyToOpen : String;
begin
KeyList := TStringList.Create;
Reg := TRegistry.Create;
Reg.RootKey := HKEY_CLASSES_ROOT;
test := Reg.OpenKey('',false);
Reg.GetKeyNames(KeyList);
Reg.CloseKey;
For Count := 0 to KeyList.Count -1 do
begin
if Assigned(eProgress) then eProgress(self,keylist.count,count);
// open the first Key in the List
KeyToOpen := KeyList.Strings[count];
Test := Reg.OpenKey('\' + KeyToOpen,False);
// look to see if it has a CLSID
if Reg.KeyExists('CLSID') then
Begin
Reg.CloseKey;
If Reg.OpenKey( '\' + KeyToOpen + '\CLSID',false) then
begin
fCLSID := Reg.ReadString('');
Reg.CloseKey;
if Reg.OpenKey('\CLSID\' + fCLSID,False) then
begin
// Get The CLSID
Temp := TComItem.Create;
Temp.CLSID := fCLSID;
// Get all the Details
Reg.CloseKey;
Try
If Reg.OpenKey('\CLSID\' + fCLSID + '\' + 'InprocServer32',false) Then
Temp.InprocServer := Reg.ReadString('');
if Reg.OpenKey('\CLSID\' + fCLSID + '\' + 'ProgID',false) then
Temp.ProgID := Reg.ReadString('');
if Reg.OpenKey('\CLSID\' + fCLSID + '\' + 'Version',false) then
Temp.Version := Reg.ReadString('');
If Reg.OpenKey('\CLSID\' + fCLSID + '\' + 'TypeLib',false) then
Temp.TypeLib := Reg.ReadString('');
Reg.CloseKey;
if (Temp.TypeLib = '') or
(Temp.ProgID = '') then
begin
Temp.Free;
end
else
ComList.Add(Temp);
Except on E:Exception do
begin
Temp.fCLSID := 'ERROR';
ComList.Add(Temp);
Reg.CloseKey;
end;
end;
end;
end;
end;
end;
End;
constructor TComEnum.Create;
begin
ComList := TList.Create;
end;
destructor TComEnum.Destroy;
begin
inherited;
ComList.Free;
end;
function TComEnum.GetComCount: Integer;
begin
result := ComList.Count;
end;
Function TComEnum.GetItem(Index: Integer) : TComItem;
begin
if (Index = 0) AND (Index begin
Result := ComList.Items[index];
End
Else
Result := NIL;
end;
end.
USING THE CLASS
For a Test, create a new Application. Put a ListView, button and a progress bar on the screen.
Set the ListView Style to Report.
Add the following code to the Button
procedure TForm1.Button1Click(Sender: TObject);
Var
count : Integer;
Temp : TComItem;
Rec : TListItem;
begin
ComEnum := TComEnum.Create;
ComEnum.OnProgress := DoProgress;
ComEnum.BuildList;
for Count := 0 to ComEnum.ComCount-1 do
begin
Temp := ComEnum.GetItem(count);
Rec := ListView1.Items.add;
Rec.Caption := Temp.ProgID;
Rec.SubItems.Add(Temp.CLSID);
Rec.SubItems.Add(Temp.InprocServer);
Rec.SubItems.Add(Temp.Version);
Rec.SubItems.Add(Temp.TypeLib);
end;
end;
TEMP is a pointer to the COMITEM sub class. As you loop though the list, assign the pointer (TEMP) to ratuen Result of Get Item. Once you have done this you can add it to any viewable component;
REC is a pointer to the ListView Items.
The class has one method and one Event
OnProgress EVENT
Delare this in your Private section of the form class
Procedure DoProgress(Sender : TObject;Count,Position : Integer);
and insert the following code
procedure TForm1.DoProgress(Sender: TObject; Count, Position: Integer);
begin
progressBar1.Max := count;
progressBar1.Position := position;
end;
The Count Value is the total number of first level keys that the class will search though. The Position the indication of how far it is.
BUILDLIST
This method will build an Object List of all the registerd COM Objects and store than in the COMITEM sub class. As the method runs, the progress event will trigger if you have assigned it.