title: Error 2769 when Upgrading the Installer
body: <p>I have created an installer that will call two Custom actions. First custom action is <code>WRITEFILETODISK</code> that will create a config file based on the parameter passed to the installer and store it in <code>%ProgramData%\SomeFolder</code>. Second custom action is <code>ResidueRemove</code> that will does the job of cleaning any residue from <code>%ProgramData%\SomeFolder</code>.</p>
  
  <p>Below is the snippet of custom action from my Wix File:</p>
  
  <pre><code>&lt;Binary Id="SetupCA"  SourceFile="..\..\ext_library\SetupCACPP\SetupCACPP\bin\Release\SetupCACPP.dll"/&gt;
  &lt;CustomAction Id="WRITEFILETODISK" Execute="immediate" BinaryKey="SetupCA" DllEntry="WriteFileToDisk" /&gt;
  &lt;CustomAction Id="ResidueRemove" Execute="immediate" BinaryKey="SetupCA" DllEntry="DeleteResidue" /&gt;
  &lt;InstallExecuteSequence&gt;
    &lt;Custom Action="WRITEFILETODISK" After="InstallFinalize"&gt;NOT Installed&lt;/Custom&gt;
    &lt;Custom Action="ResidueRemove" After="InstallFinalize"&gt;REMOVE~="ALL"&lt;/Custom&gt;
    &lt;!-- Rob Menshing Answer @ http://stackoverflow.com/a/321874/2634612 --&gt;
  &lt;/InstallExecuteSequence&gt;
  </code></pre>
  
  <p>The <code>ResidueRemove</code> Custom Action is added here:</p>
  
  <pre><code>    UINT __stdcall DeleteResidue(MSIHANDLE hInstall)
  {
      HRESULT hr = S_OK;
      UINT er = ERROR_SUCCESS;
      SC_HANDLE sHandleLPA, sHandleLPAM;
      SERVICE_STATUS servStatusLPA, servStatusLPAM;
      SHFILEOPSTRUCT shFileCommFolder, shFileInstalledFolder;
      LPWSTR lpaCommFolder, lpaInstalledFolder;
      std::wstring wlpaCommFolder, wlpaInstalledFolder;
      std::string errorCode;
      hr = WcaInitialize(hInstall, "DeleteResidue");
      ExitOnFailure(hr, "Failed to initialize");
  
      //Stop the LPA and LPA Monitor Service. Then delete the residue.
      WcaLog(LOGMSG_STANDARD, "Doing Delete Residue"); // Fails after printing this log
  
      hr = WcaGetProperty(L"LPCOMMAPPFOLDER",&amp;lpaCommFolder);
      ExitOnFailure(hr, "Failure in Common Folder"); // Getting the %ProgramData%\SomeFolder here
  
      hr = WcaGetProperty(L"INSTALLFOLDER",&amp;lpaInstalledFolder);
      ExitOnFailure(hr, "Failure in getting Installed Folder"); // Getting Installed Folder here
  
      //Path should be double Terminated for SHFILEOPSTRUCT.pFrom
      wlpaCommFolder = std::wstring(lpaCommFolder);
      wlpaCommFolder.push_back(L'\0');
  
      wlpaInstalledFolder = std::wstring(lpaInstalledFolder);
      wlpaInstalledFolder.push_back(L'\0');
  
      try
      {
          sHandleLPAM = OpenSCManager(NULL,NULL, SC_MANAGER_ALL_ACCESS);
          if(sHandleLPAM == NULL)
          {
              WcaLog(LOGMSG_STANDARD, "OpenSCManager NULL Handle");
          }
          sHandleLPAM = OpenService(sHandleLPAM, L"SomeServiceOne",SERVICE_ALL_ACCESS);
          if(sHandleLPAM == NULL)
          {
              WcaLog(LOGMSG_STANDARD, "OpenService NULL Handle");
          }
          bool res = ControlService(sHandleLPAM, SERVICE_CONTROL_STOP,(LPSERVICE_STATUS) &amp;servStatusLPAM);
          if(!res)
          {
              WcaLog(LOGMSG_STANDARD, "ControlService Cannot Stop the service");
          }
          // Free the service Handler
          CloseServiceHandle(sHandleLPAM);
      }
      catch(std::exception&amp; e)
      {
          WcaLog(LOGMSG_STANDARD, e.what());
      }
  
      try
      {
          sHandleLPA = OpenSCManager(NULL,NULL, SC_MANAGER_ALL_ACCESS);
          if(sHandleLPA == NULL)
          {
              WcaLog(LOGMSG_STANDARD, "OpenSCManager NULL Handle");
          }
          sHandleLPA = OpenService(sHandleLPA, L"SomeServiceTwo",SERVICE_ALL_ACCESS);
          if(sHandleLPA == NULL)
          {
              WcaLog(LOGMSG_STANDARD, "OpenService NULL Handle");
          }
          bool res = ControlService(sHandleLPA, SERVICE_CONTROL_STOP,(LPSERVICE_STATUS) &amp;servStatusLPA);
          if(!res)
          {
              WcaLog(LOGMSG_STANDARD, "ControlService Cannot Stop the service");
          }
          // Free the service Handler
          CloseServiceHandle(sHandleLPA);
      }
      catch(std::exception&amp; e)
      {
          WcaLog(LOGMSG_STANDARD, e.what());
      }
  
      ZeroMemory(&amp;shFileCommFolder, sizeof(SHFILEOPSTRUCT));
      shFileCommFolder.hwnd = NULL;
      shFileCommFolder.wFunc = FO_DELETE;
      shFileCommFolder.pFrom = wlpaCommFolder.c_str();
      shFileCommFolder.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_NOERRORUI;
      BOOL res = DirectoryExists(lpaCommFolder);
      if(res)
      {
          WcaLog(LOGMSG_STANDARD, "The directory exist");
          int result = SHFileOperation(&amp;shFileCommFolder);
          if(!result)
              WcaLog(LOGMSG_STANDARD, "The directory should have deleted by now");
          else
          {
              errorCode = GetLastErrorStdStr();
              WcaLog(LOGMSG_STANDARD, "The directory could not be deleted %s", errorCode);
          }
  
      }       
      else
      {
          WcaLog(LOGMSG_STANDARD, "It Seems the Installed Folder is No more there");
      }
  
      ZeroMemory(&amp;shFileInstalledFolder, sizeof(SHFILEOPSTRUCT));
      shFileInstalledFolder.hwnd = NULL;
      shFileInstalledFolder.wFunc = FO_DELETE;
      shFileInstalledFolder.pFrom = wlpaInstalledFolder.c_str();
      shFileInstalledFolder.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_NOERRORUI;
      res = DirectoryExists(lpaInstalledFolder);
      if(res)
      {
          WcaLog(LOGMSG_STANDARD, "The directory exist");
          int result = SHFileOperation(&amp;shFileInstalledFolder);
          if(!result)
              WcaLog(LOGMSG_STANDARD, "The directory should have deleted by now");
          else
          {
              errorCode = GetLastErrorStdStr();
              WcaLog(LOGMSG_STANDARD, "The directory could not be deleted %s", errorCode);
          }
      }       
      else
      {
          WcaLog(LOGMSG_STANDARD, "It Seems the Installed Folder is No more there");
      }
  
  
  LExit:
      er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
      return WcaFinalize(er);
  }
  </code></pre>
  
  <p>I get error after the log <code>Delete Residue</code> that is:</p>
  
  <pre><code>DeleteResidue:  Doing Delete Residue
  MSI (s) (64:A4) [10:54:51:643]: Leaked MSIHANDLE (11) of type 790541 for thread 980
  MSI (s) (64:A4) [10:54:51:643]: Note: 1: 2769 2: ResidueRemove 3: 1 
  MSI (s) (64:A4) [10:54:51:643]: Note: 1: 2205 2:  3: Error 
  MSI (s) (64:A4) [10:54:51:643]: Note: 1: 2228 2:  3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 2769 
  DEBUG: Error 2769:  Custom Action ResidueRemove did not close 1 MSIHANDLEs.
  The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2769. The arguments are: ResidueRemove, 1, 
  Action ended 10:54:51: ResidueRemove. Return value 3.
  Action ended 10:54:51: INSTALL. Return value 3.
  </code></pre>
  
  <p>This is replicated when the upgrade of installer is done in (Non-English) German Windows. Upon some research I found that <code>The InstallExecuteSequence may have been authored incorrectly. Actions that change the system must be sequenced between the InstallInitialize and InstallFinalize actions. Perform package validation and check for ICE77.</code> Does this mean My <code>InstallExecuteSequence</code> is wrong? The first CA <code>WriteFileToDisk</code> should run after installation and before the service are started (because the executable depend upon the file). The second CA should remove the residue, stop services after Uninstall is complete. What's wrong here in my code? Any help is appreciated.</p>