En faisant une recherche, il est assez facile de trouver une solution: utiliser le programme fourni par Windows regsvr32 pour enregistrer la DLL. Dans mon cas, le fichier se nomme vcf132.ocx.

regsvr32 vcf132.ocx

A noter qu'il faut mettre cette commande dans un fichier bat et l'exécuter en tant qu'administrateur, sinon le programme n'aura pas le droit de modifier le registre.

Comme il n'est pas toujours possible d'exécuter un script de la sorte, l'idée est d'enregistrer directement le composant via quelques lignes de C (source).

bool registerDll(const char* dll)
{
  HINSTANCE hDLL = LoadLibrary(dll);
 
  if(hDLL == NULL) return FALSE;
 
  typedef HRESULT (CALLBACK *HCRET)(void);
  HCRET lpfnDllRegisterServer;
 
  lpfnDllRegisterServer = (HCRET)GetProcAddress(hDLL, "DllRegisterServer");
  if(lpfnDllRegisterServer == NULL) return FALSE;
 
  if(FAILED((*lpfnDllRegisterServer)())) return FALSE;
 
  return TRUE;
}

Le problème restant est qu'il faut pouvoir indiquer à l'utilisateur de lancer (au moins une fois) le programme en tant qu'administrateur pour que les composants puissent être enregistrés. Le fait est que la fonction ci-dessus renverra FALSE si ce n'est pas le cas (l'appel à la fonction DllRegisterServer ne marchera pas).

La question est donc de savoir si ledit composant a déjà été enregistré. Et pour ce faire, il faut aller lire le registre de windows (doc), plus précisément les valeurs contenues dans la clé HKEY_LOCAL_MACHINE/SOFTWARE/Classes/CLSID.

bool isDllRegistered(const char* dllName)
{
  bool found = FALSE;
  HKEY clsidKey;
 
  const char* clsidPath = "SOFTWARE\\Classes\\CLSID";
  const char* clsidInsideKeyPath = "\\InprocServer32";
  const int clsidPathSize = strlen(clsidPath);
  const int clsidInsideKeyPathSize = strlen(clsidInsideKeyPath);
 
  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, clsidPath, 0, KEY_READ, &clsidKey) == ERROR_SUCCESS)
  {
    int keyNameSize = 255;
    char keyName[255];
    int keyIndex = 0;
    while(RegEnumKey(clsidKey, keyIndex, keyName, keyNameSize) == ERROR_SUCCESS && !found)
    {
      //build the full path => SOFTWARE\Classes\CLSID\{1234-5678-1234-5678}\InprocServer32
      const int keySize = strlen(keyName);
      const int fullPathSize = clsidPathSize+clsidInsideKeyPathSize+keySize+1/* the slash */;
      char* fullPath = (char*)malloc(sizeof(char)*(fullPathSize+1));
      strncpy(fullPath, clsidPath, clsidPathSize);
      strncpy(fullPath+clsidPathSize+1, keyName, keySize);
      strncpy(fullPath+clsidPathSize+1+keySize, clsidInsideKeyPath, clsidInsideKeyPathSize);
      fullPath[clsidPathSize] = '\\';
      fullPath[fullPathSize] = '\0';
 
      //open the path and get the value
      HKEY fullPathKey;
      if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, fullPath, 0, KEY_READ, &fullPathKey) == ERROR_SUCCESS)
      {
        unsigned long size = 255;
        char keyValue[255];
        if(RegQueryValueEx(fullPathKey, 0, 0, 0, (BYTE*)keyValue, &size)  == ERROR_SUCCESS)
        {
          char* vcfCheck = strstr(keyValue, dllName);
          if (vcfCheck != NULL) found = TRUE;
        }
        RegCloseKey(fullPathKey);
      }
 
      free(fullPath);
      ++keyIndex;
    }
    RegCloseKey(clsidKey);
  }
 
  return found;
}

Finalement, il ne reste plus qu'a afficher un message d'erreur à l'utilisateur pour lui indiquer quoi faire:

if (!registerDll("vcf132.ocx") && !isDllRegistered("vcf132.ocx"))
{
  //erreur: veuillez lancer l'application en tant qu'administrateur la première fois
}

J'ai fait un petit programme attaché à ce billet permettant de checker si un composant est enregistré ou pas (compilé avec Dev-cpp).