if(*sgProduct.greCleanupOrphansMessage != '\0'); ShowMessage(sgProduct.greCleanupOrphansMessage, FALSE);
HRESULT CleanupOrphanedGREs(){  HKEY      greIDKeyHandle;  HKEY      greAppListKeyHandle;  DWORD     totalGreIDSubKeys;  DWORD     totalGREAppListSubKeys;  char      **greIDListToClean = NULL;  char      **greAppListToClean = NULL;  char      greKeyID[MAX_BUF_MEDIUM];  char      greRegKey[MAX_BUF];  char      greKeyAppList[MAX_BUF_MEDIUM];  char      greAppListKeyPath[MAX_BUF];  char      greUninstaller[MAX_BUF];  DWORD     idKeySize;  DWORD     appListKeySize;  DWORD     indexOfGREID;  DWORD     indexOfGREAppList;  int       rv = WIZ_OK;  int       regRv = WIZ_OK;  char      buf[MAX_BUF];  DecryptString(greUninstaller, GRE_UNINSTALLER_FILE);  _snprintf(buf, sizeof(buf), "    GRE Cleanup Orphans: %s\n", sgProduct.greCleanupOrphans ? "true" : "false");  buf[sizeof(buf) - 1] = '\0';  UpdateInstallStatusLog(buf);  _snprintf(buf, sizeof(buf), "    GRE Uninstaller Path: %s\n", greUninstaller);  buf[sizeof(buf) - 1] = '\0';  UpdateInstallStatusLog(buf);  _snprintf(buf, sizeof(buf), "    GRE Uninstaller found: %s\n", FileExists(greUninstaller) ? "true" : "false");  buf[sizeof(buf) - 1] = '\0';  UpdateInstallStatusLog(buf);  // If greCleanupOrphans is false (set either in config.ini or passed in  // thru the cmdline) or GRE's uninstaller file does not exist, then  // simply do nothing and return.  if(!sgProduct.greCleanupOrphans || !FileExists(greUninstaller))  {    _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return: %d\n", WIZ_OK);    buf[sizeof(buf) - 1] = '\0';    UpdateInstallStatusLog(buf);    return(WIZ_OK);  }  // If GRE is installed locally, then use the private GRE key, else  // use the default global GRE key in the windows registry.  if(sgProduct.greType == GRE_LOCAL)    DecryptString(greRegKey, sgProduct.grePrivateKey);  else    MozCopyStr(GRE_REG_KEY, greRegKey, sizeof(greRegKey));  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, greRegKey, 0, KEY_READ, &greIDKeyHandle) != ERROR_SUCCESS)  {    _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return (RegOpenKeyEx: %s): %d\n", greRegKey, WIZ_ERROR_UNDEFINED);    buf[sizeof(buf) - 1] = '\0';    UpdateInstallStatusLog(buf);    return(WIZ_ERROR_UNDEFINED);  }  // Build the list of GRE's given greRegKey.  For example, if greRegKey is:  //  //   HKLM\Software\mozilla.org\GRE  //  // then build a list of the GRE IDs inside this key.  totalGreIDSubKeys = 0;  regRv = RegQueryInfoKey(greIDKeyHandle, NULL, NULL, NULL, &totalGreIDSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);  if((regRv != ERROR_SUCCESS) || (totalGreIDSubKeys == 0))  {    rv = WIZ_ERROR_UNDEFINED;    _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return (RegQueryInfoKey: all keys): %d\n", rv);    buf[sizeof(buf) - 1] = '\0';    UpdateInstallStatusLog(buf);    return(rv);  }  if((rv == WIZ_OK) && (greIDListToClean = NS_GlobalAlloc(sizeof(char *) * totalGreIDSubKeys)) == NULL)  {    RegCloseKey(greIDKeyHandle);    _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return.  Failed to allocate memory for greIDListToClean: %d\n", WIZ_OUT_OF_MEMORY);    buf[sizeof(buf) - 1] = '\0';    UpdateInstallStatusLog(buf);    return(WIZ_OUT_OF_MEMORY);  }  // Show message that orphaned GREs are being cleaned up  if(*sgProduct.greCleanupOrphansMessage != '\0');    ShowMessage(sgProduct.greCleanupOrphansMessage, TRUE);  if(rv == WIZ_OK)  {    // Initialize the array of pointers (of GRE ID keys) to NULL    for(indexOfGREID = 0; indexOfGREID < totalGreIDSubKeys; indexOfGREID++)      greIDListToClean[indexOfGREID] = NULL;    // Enumerate the GRE ID list and save the GRE ID to each of its array element    for(indexOfGREID = 0; indexOfGREID < totalGreIDSubKeys; indexOfGREID++)    {      idKeySize = sizeof(greKeyID);      if(RegEnumKeyEx(greIDKeyHandle, indexOfGREID, greKeyID, &idKeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)      {        if((greIDListToClean[indexOfGREID] = NS_GlobalAlloc(sizeof(char) * (idKeySize + 1))) == NULL)        {          RegCloseKey(greIDKeyHandle);          rv = WIZ_OUT_OF_MEMORY;          _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return.  Failed to add %s to greIDListToClean[]: %d\n", greKeyID, rv);          buf[sizeof(buf) - 1] = '\0';          UpdateInstallStatusLog(buf);          break;        }        MozCopyStr(greKeyID, greIDListToClean[indexOfGREID], idKeySize + 1);      }    }    RegCloseKey(greIDKeyHandle);    if(rv == WIZ_OK)    {      // Enumerate the GRE ID list built from above to get to each of it's AppList key.      // The list that we need to build now is from the following key:      //      //   HKLM\Software\mozilla.org\GRE\[GRE ID]\AppList      for(indexOfGREID = 0; indexOfGREID < totalGreIDSubKeys; indexOfGREID++)      {        // If we find the same GRE version as what we're trying to install,        // then we don't want to process it because if we do, it will        // uninstall it.  Which means that it'll reinstall it again.  We don't        // want to have reinstall when we don't need to.        //        // szUserAgent is the GRE unique id if this instance of the installer is        // installing GRE.        if(strcmpi(sgProduct.szUserAgent, greIDListToClean[indexOfGREID]) == 0)          continue;        _snprintf(greAppListKeyPath, sizeof(greAppListKeyPath), "%s\\%s\\AppList",            GRE_REG_KEY, greIDListToClean[indexOfGREID]);        greAppListKeyPath[sizeof(greAppListKeyPath) - 1] = '\0';        if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, greAppListKeyPath, 0, KEY_READ, &greAppListKeyHandle) != ERROR_SUCCESS)        {          rv = WIZ_ERROR_UNDEFINED;          _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return.  Failed to open key %s: %d\n", greAppListKeyPath, rv);          buf[sizeof(buf) - 1] = '\0';          UpdateInstallStatusLog(buf);          break;        }        totalGREAppListSubKeys = 0;        if(RegQueryInfoKey(greAppListKeyHandle, NULL, NULL, NULL, &totalGREAppListSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)        {          RegCloseKey(greAppListKeyHandle);          rv = WIZ_ERROR_UNDEFINED;          _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return.  Failed to regquery for all keys in %s: %d\n", greAppListKeyPath, rv);          buf[sizeof(buf) - 1] = '\0';          UpdateInstallStatusLog(buf);          break;        }            if((rv == WIZ_OK) && (greAppListToClean = NS_GlobalAlloc(sizeof(char *) * totalGREAppListSubKeys)) == NULL)        {          RegCloseKey(greAppListKeyHandle);          rv = WIZ_OUT_OF_MEMORY;          _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return.  Failed to allocate memory for greAppListToClean: %d\n", rv);          buf[sizeof(buf) - 1] = '\0';          UpdateInstallStatusLog(buf);          break;        }        // Initialize the GREAppList elements to NULL.        for(indexOfGREAppList = 0; indexOfGREAppList < totalGREAppListSubKeys; indexOfGREAppList++)          greAppListToClean[indexOfGREAppList] = NULL;        // enumerate the GRE AppList key and build a list.        for(indexOfGREAppList = 0; indexOfGREAppList < totalGREAppListSubKeys; indexOfGREAppList++)        {          appListKeySize = sizeof(greKeyAppList);          if(RegEnumKeyEx(greAppListKeyHandle, indexOfGREAppList, greKeyAppList, &appListKeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)          {            if((greAppListToClean[indexOfGREAppList] = NS_GlobalAlloc(sizeof(char) * (appListKeySize + 1))) == NULL)            {              RegCloseKey(greAppListKeyHandle);              rv = WIZ_OUT_OF_MEMORY;              _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return.  Failed to add %s to greAppListToClean[]: %d\n", greKeyAppList, rv);              buf[sizeof(buf) - 1] = '\0';              UpdateInstallStatusLog(buf);              break;            }            MozCopyStr(greKeyAppList, greAppListToClean[indexOfGREAppList], appListKeySize + 1);          }        }        RegCloseKey(greAppListKeyHandle);        if(rv != WIZ_OK)          break;        UpdateInstallStatusLog("\n    Cleanup Orphaned GRE's uninstall commandline:\n");        // Enumerate the saved GREAppList and start calling GREUninstall.exe        // to remove them if appropriate.        // GREUninstall.exe will take care of determining if the particular        // GRE should be fully removed or not.        // We need to enumerate the list again instead of doing this in the        // save loop as above because deleting keys while at the same time        // enumerating thru its parent key is a Bad Thing(TM).        for(indexOfGREAppList = 0; indexOfGREAppList < totalGREAppListSubKeys; indexOfGREAppList++)        {          char programNamePath[MAX_BUF];          char greUninstallParam[MAX_BUF];          DecryptString(programNamePath, sgProduct.szAppPath);          _snprintf(greUninstallParam, sizeof(greUninstallParam), "-mmi -ms -ua \"%s\" -app \"%s\" -app_path \"%s\"",              greIDListToClean[indexOfGREID], greAppListToClean[indexOfGREAppList], programNamePath);          greUninstallParam[sizeof(greUninstallParam) - 1] = '\0';          UpdateInstallStatusLog("        ");          UpdateInstallStatusLog(greUninstallParam);          UpdateInstallStatusLog("\n");          WinSpawn(greUninstaller, greUninstallParam, szTempDir, SW_SHOWNORMAL, WS_WAIT);        }        // Cleanup allocated memory        for(indexOfGREAppList = 0; indexOfGREAppList < totalGREAppListSubKeys; indexOfGREAppList++)          FreeMemory(&greAppListToClean[indexOfGREAppList]);        if(greAppListToClean)          GlobalFree(greAppListToClean);      }    }  }  //  // Cleanup allocated memory  CleanupArrayList(greIDListToClean, totalGreIDSubKeys);  if(greIDListToClean)    GlobalFree(greIDListToClean);  // Hide message that orphaned GREs are being cleaned up  if(*sgProduct.greCleanupOrphansMessage != '\0');    ShowMessage(sgProduct.greCleanupOrphansMessage, FALSE);  return(rv);}