title: Uninstall software
body: <p>My product has a helper executable to uninstall all related sub-products. I uninstall based on upgrade codes of all sub-products. </p>
  
  <p>First, I fetch the product code from upgrade code using <a href="http://msdn.microsoft.com/en-us/library/aa370103%28v=vs.85%29.aspx">MsiEnumRelatedProducts</a> function. Then I try to uninstall the product using <a href="http://msdn.microsoft.com/en-us/library/aa370071%28v=vs.85%29.aspx">MsiConfigureProductEx</a> function.</p>
  
  <p>The problem is <code>MsiConfigureProductEx</code> is returning error.</p>
  
  <blockquote>
    <p>Invoked Function: MsiConfigureProductsEx<br>
        Return Code: 1605 (0x00000645)<br>
        Description: This action is only valid for products that are currently installed.</p>
  </blockquote>
  
  <p>Why is <code>MsiEnumRelatedProducts</code> returning a invalid product code ? I searched through the windows registry to see if such product code exists. There isn't any. How to debug the issue ?</p>
  
  <p>Edit: Added minimum code that reproduces issue.</p>
  
  <pre><code>// UpgradeCodes is an array having upgrade codes of all modules.
  
  TCHAR lpProductCode[GUID_STR_LENGTH];
  const TCHAR tszNoReboot[] = _T("REMOVE=ALL REBOOT=ReallySuppress DISABLE_REBOOT_PROMPT=1");
  
  for (size_t i = 0; i &lt; sizeof(UpgradeCodes) / sizeof(UpgradeCodes[0]); i++)
  {
     tstring tstrUpgradeCode = UpgradeCodes[i];
  
     DWORD dwIndex = 0;
     size_t status;
  
     // for each of the upgrade code, get all the products
     do
     {
         status = MsiEnumRelatedProducts(UpgradeCodes[i], 
                                         0, 
                                         dwIndex, 
                                         lpProductCode);
         if (ERROR_SUCCESS == status)
         {
            UINT uiReturn = MsiConfigureProductEx(lpProductCode, 
                                                  INSTALLLEVEL_DEFAULT, 
                                                  INSTALLSTATE_DEFAULT, 
                                                  tszNoReboot);
  
            if (ERROR_SUCCESS_REBOOT_REQUIRED == uiReturn)
            {
                 // prompt for reboot at the end of all modules uninstallation.
            }
  
            if (ERROR_SUCCESS != uiReturn)
            {
                // log message with return code.
  
                // Error Code: 1605 is coming from here.
            }
         }
     }while (ERROR_NO_MORE_ITEMS != status);
  }
  </code></pre>