MsiInstallProduct () starts msiexe.exe, but in 32-bit mode?

I have a customized setup application that installs multiple MSI files. Today I tried to implement an external interface in order to implement my own progress bar using this article. everything looks workable (progressbar receives data and updates), but after about 60% when starting the component update, I get an exception: "the object is not installed ..." and digging further received: _COMPlusExceptionCode "-532462766"

checked the process monitor and suddenly realized that msiexec was working in 32-bit mode.

When msiexe starts, it starts in 64-bit mode, but using the MsiInstallProduct () method, it starts in 32-bit format.

I believe that an exception occurs when msiexec tries to configure registry keys, and MSI files on 64-bit, it fails.

any help appreciated.

Cheers, Afshin

Update 1: turned on the log using MsiEnableLog, and this error appeared:

"MSI (c) (94: F8) [07: 50: 29: 395]: Internal exception during installation operation: 0xc0000005 at 0x000007FE9827F768."

Update 2: digging further depending on @marceln's suggestion, I used Process Monitor and noticed that there were two msiexec processes in memory. one in 64-bit mode, which is in session 0, and the other starts from the first when I call MsiInstallProduct. the second starts with "c: \ windows \ syswow64 \ msiexec.exe", which is a 32-bit version. I tried to set the search path using SetDllDirectory , but still getting the same result.

Update 3: the main process definitely works in 64-bit mode: both prccess monitors confirm this and the result of the powershell command:

[reflection.assemblyname]::GetAssemblyName("setup.exe") | fl Name : Setup Version : 5.0.0.0 CultureInfo : CultureName : CodeBase : file:///...../Setup.exe EscapedCodeBase : file:///Setup.exe ProcessorArchitecture : **MSIL** ContentType : Default Flags : None HashAlgorithm : SHA1 VersionCompatibility : SameMachine KeyPair : FullName : Setup, Version=5.0.0.0, Culture=neutral, PublicKeyToken=null 

Update 4: I use this method to import MSI.DLL:

 [DllImport("msi.dll", CharSet = CharSet.Auto, SetLastError = true)] internal static extern int MsiInstallProduct(string packagePath, string commandLine); 

Update 5: I tried the process explorer, the application is 64 bit, the MSI.DLL file under the application is launched from system32. but the msiexec.exe process still runs on syswow64, which is 32 bits. msi file is built as 64-bit msi.

Update 6: I just found out that this line is the source of the problem:

 oldHandler = MSIIntrop.MsiSetExternalUI( new MSIIntrop.InstallUIHandler(OnExternalUI), 32735, IntPtr.Zero); 

Update 7 [FINAL UPDATE]: To make a local claim: After hours and hours of wasting time, I finally managed to overcome this problem. there seems to be some kind of internal memory management leak in the MSI API that causes the external user interface handler to crash in completely random behavior. To fix this problem, I implemented the IDisposable interface and tried to use the class in the "using" block to make sure the class was completely deleted. MsiSetExternalUI () and MsiInstallProduct () are now safely called inside this block. don't forget to call MsiSetExternalUI () to return the user interface to its original state:

 IntPtr prevWindow = IntPtr.Zero; MSIIntrop.INSTALLUILEVEL prevUILevel = MSIIntrop.MsiSetInternalUI(MSIIntrop.INSTALLUILEVEL.INSTALLUILEVEL_NONE, ref prevWindow); using (MSIContext context = new MSIContext(progressChanged, messageRaised)) { MSIIntrop.INSTALLUI_HANDLER prevHandlre = MSIIntrop.MsiSetExternalUI(context.Handler, MSIIntrop.INSTALLLOGMODE.INSTALLLOGMODE_FATALEXIT | MSIIntrop.INSTALLLOGMODE.INSTALLLOGMODE_ERROR | MSIIntrop.INSTALLLOGMODE.INSTALLLOGMODE_WARNING | MSIIntrop.INSTALLLOGMODE.INSTALLLOGMODE_ACTIONDATA | MSIIntrop.INSTALLLOGMODE.INSTALLLOGMODE_PROGRESS, IntPtr.Zero); try { int ret = MSIIntrop.MsiInstallProduct(runningPath, commandLine); } catch (Exception ex) { messageRaised("Error: " + ex.Message); } finally { MSIIntrop.MsiSetExternalUI(prevHandlre, 0, IntPtr.Zero); } } 

PS 1: I did not answer this, as I am not% 100 sure that this was the source of the error. This is just a workaround. PS 2: Thanks to Marcel and Jacob :)

+4
source share
2 answers

I think that after two years of running the code without problems, it would be right to complete the workflow proposed in update 7 above - this is the answer to the question:

It looks like a memory leak in the MSI API, which causes the external UI handler to crash in completely random behavior. To fix this problem, I implemented the IDisposable interface and tried to use the class in the "using" block to make sure the class was completely deleted. MsiSetExternalUI () and MsiInstallProduct () are now safely called inside this block. don't forget to call MsiSetExternalUI () to return the user interface to its original state

0
source

The reason is the garbage collector. Please try using the GC.KeepAlive () method so that the garbage collector does not collect an external user interface handler.

For instance:

 // create ui handler MSIIntrop.UIHandlerDelegate externalUIHandler = new MSIIntrop.UIHandlerDelegate(context.Handler); // execute MsiSetExternalUI with this handler MSIIntrop.INSTALLUI_HANDLER prevHandlre = MSIIntrop.MsiSetExternalUI(externalUIHandler, MSIIntrop.INSTALLLOGMODE.INSTALLLOGMODE_FATALEXIT | MSIIntrop.INSTALLLOGMODE.INSTALLLOGMODE_ERROR | MSIIntrop.INSTALLLOGMODE.INSTALLLOGMODE_WARNING | MSIIntrop.INSTALLLOGMODE.INSTALLLOGMODE_ACTIONDATA | MSIIntrop.INSTALLLOGMODE.INSTALLLOGMODE_PROGRESS, IntPtr.Zero); // install product int ret = MSIIntrop.MsiInstallProduct(runningPath, commandLine); // restore the previous ui handler MSIIntrop.MsiSetExternalUI(prevHandlre, 0, IntPtr.Zero); // prevent GC from collecting ExternalUIHandler during the product installation GC.KeepAlive(externalUIHandler); 
0
source

Source: https://habr.com/ru/post/1483530/


All Articles