Registry
Registering a COM server is complicated, but the essential parts are
- ProgID, a human-readable name
HKEY_CLASSES_ROOT\<name>
is the ProgIDHKEY_CLASSES_ROOT\<name>\CLSID
points to the corresponding CLSID
- CLSID, a GUID
HKEY_CLASSES_ROOT\CLSID\<GUID>
is the CLSIDHKEY_CLASSES_ROOT\CLSID\<GUID>\InprocServer32
points to the server’s filename (InProc)HKEY_CLASSES_ROOT\CLSID\<GUID>\LocalServer32
points to the server’s filename (OutProc)HKEY_CLASSES_ROOT\CLSID\<GUID>\ProgID
points back to the ProgIDHKEY_CLASSES_ROOT\CLSID\<GUID>\Implemented Categories
lists the implemented CATIDsHKEY_CLASSES_ROOT\CLSID\<GUID>\Required Categories
lists the required CATIDsHKEY_CLASSES_ROOT\CLSID\<GUID>\TreatAs
maps a CLSID to newer, compatible CLSID
- IIDs, one or more GUIDs
HKEY_CLASSES_ROOT\Interface\<GUID>
is an IIDHKEY_CLASSES_ROOT\Interface\<GUID>\TypeLib
points to the type libraryHKEY_CLASSES_ROOT\Interface\<GUID>\ProxyStubClsid32
points to marshaler (oleaut32.dll)
- LIBID, a type library
HKEY_CLASSES_ROOT\TypeLib\<GUID>
is a LIBIDHKEY_CLASSES_ROOT\TypeLib\<GUID>\<version>\0\win32
points to the .tlb file
- CATID, category ID
HKEY_CLASSES_ROOT\Component Categories\<GUID>
is a CATIDHKEY_CLASSES_ROOT\CLSID\<GUID>\TreatAs
maps a CATID to a default CLSID (not a typo)
The IIDs are associated with the class through QueryInterface()
and other API calls.
CoCreateInstance() can take a CATID instead of a CLSID, if there is a TreatAs entry specifying a default.
If a COM DLL implements DllRegisterServer()
and DllUnregisterServer()
, it can be registered/unregistered with regsvr32.exe
.
using System;
using Microsoft.Win32;
class Program
{
static void Main()
{
try
{
Console.WriteLine("List of COM interfaces on the system:");
using (RegistryKey interfaceKey = Registry.ClassesRoot.OpenSubKey("Interface"))
{
if (interfaceKey != null)
{
foreach (string subKeyName in interfaceKey.GetSubKeyNames())
{
using (RegistryKey subKey = interfaceKey.OpenSubKey(subKeyName))
{
if (subKey != null)
{
string interfaceName = (string)subKey.GetValue(null);
if (!string.IsNullOrEmpty(interfaceName))
{
// Get the IID (Interface Identifier) from the subkey name
Guid iid = Guid.ParseExact(subKeyName, "B");
Console.WriteLine("IID: " + iid.ToString());
Console.WriteLine("Interface Name: " + interfaceName);
Console.WriteLine();
}
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
#include <Windows.h>
#include <Objbase.h>
#include <string>
#include <iostream>
#pragma comment(lib, "Ole32.lib")
int main() {
HRESULT hr = CoInitialize(nullptr);
if (FAILED(hr)) {
std::cout << "Failed to initialize COM. Error code: " << hr << std::endl;
return 1;
}
HKEY hKey;
LONG result = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"Interface", 0, KEY_READ, &hKey);
if (result != ERROR_SUCCESS) {
std::cout << "Failed to open the Interface key in the registry. Error code: " << result << std::endl;
CoUninitialize();
return 1;
}
std::cout << "List of COM interfaces on the system:" << std::endl;
WCHAR subKeyName[256];
DWORD subKeyNameSize = 256;
DWORD index = 0;
while (RegEnumKeyEx(hKey, index++, subKeyName, &subKeyNameSize, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS) {
HKEY interfaceKey;
std::wstring interfacePath = L"Interface\\";
interfacePath += subKeyName;
result = RegOpenKeyEx(HKEY_CLASSES_ROOT, interfacePath.c_str(), 0, KEY_READ, &interfaceKey);
if (result == ERROR_SUCCESS) {
DWORD bufferSize = 1024;
WCHAR interfaceName[1024];
DWORD valueType;
// Read the Interface Name
result = RegQueryValueEx(interfaceKey, nullptr, nullptr, &valueType, (LPBYTE)interfaceName, &bufferSize);
if (result == ERROR_SUCCESS && valueType == REG_SZ) {
// Get the IID (Interface Identifier) from the subkey name
std::wstring iidString = subKeyName;
std::wcout << "IID: " << iidString << std::endl;
std::wcout << "Interface Name: " << interfaceName << std::endl;
std::wcout << std::endl;
}
RegCloseKey(interfaceKey);
}
subKeyNameSize = 256;
}
RegCloseKey(hKey);
CoUninitialize();
return 0;
}