我有一个定制的安装应用程序,它安装了几个MSI文件。今天,我尝试使用这实现外部UI来实现我自己的进度条。一切看起来都正常(进度条接收数据和更新),但是当开始更新组件时,大约60%之后,我收到一个异常:“object not设置为.”进一步挖掘得到:_COMPlusExceptionCode "-532462766“
检查进程监视器,突然意识到msiexec正在以32位模式运行。
有趣的是,当直接调用msiexe时,它从64位开始,但是使用MsiInstallProduct()方法从32位开始。
我认为,当msiexec试图配置注册表项时,当MSI文件为64位时,会引发异常。
任何帮助都很感激。
干杯,阿夫辛
更新1:使用MsiEnableLog启用了日志,出现了以下错误:
"MSI (c) (94:F8) 07:50:29:395:安装过程中的内部异常: 0xc0000005 at 0x000007FE9827F768“。
更新2:根据@marceln的建议进一步挖掘,使用Process并注意到内存中有两个msiexec进程。一种是64位模式,在会话0中,另一种模式在我调用MsiInstallProduct时由第一个模式启动。第二个开始于'c:\windows\syswow64\msiexec.exe‘,这是32位版本。我尝试使用SetDllDirectory设置查找路径,但仍然得到了相同的结果。
更新3:主进程肯定以64位模式运行: prccess监视器都证明了这一点,并得到了powershell命令结果:
[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
更新4: --我正在使用此方法导入MSI.DLL:
[DllImport("msi.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern int MsiInstallProduct(string packagePath, string commandLine);
更新5:尝试了process,应用程序是64位,应用程序下的MSI.DLL文件是从system32运行的。但是msiexec.exe进程仍然运行在32位的syswow64上。msi文件构建为64位msi。
更新6:我刚刚发现这一行是问题的根源:
oldHandler = MSIIntrop.MsiSetExternalUI(
new MSIIntrop.InstallUIHandler(OnExternalUI),
32735,
IntPtr.Zero);
更新7最终更新:经过几个小时的浪费时间之后,我终于克服了这个问题。看起来,MSI中存在某种内部内存管理漏洞,这会导致外部UI处理程序完全随机崩溃。为了解决这个问题,我实现了IDisposable接口,并尝试在一个“使用”块中使用该类,以确保类被完全释放。MsiSetExternalUI()和MsiInstallProduct()现在在这个块中被安全地调用。不要忘记调用MsiSetExternalUI()将UI恢复到它的原始状态:
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:我没有把这个写在答案里,因为我不能肯定这是错误的来源。这只是一个解决办法。PS 2:感谢马塞尔和雅各布:)
发布于 2015-12-01 22:48:13
我认为,经过两年的代码运行,没有任何问题,最好总结一下上面更新7中提出的工作流,这是对以下问题的回答:
看起来,MSI中存在某种内部内存管理漏洞,这会导致外部UI处理程序完全随机崩溃。为了解决这个问题,我实现了IDisposable接口,并尝试在一个“使用”块中使用该类,以确保类被完全释放。MsiSetExternalUI()和MsiInstallProduct()现在在这个块中被安全地调用。不要忘记调用MsiSetExternalUI()将UI恢复到它的原始状态
发布于 2016-07-13 12:13:53
原因是垃圾收集器。请尝试使用GC.KeepAlive()方法防止垃圾收集器收集外部UI处理程序。
例如:
// 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);
https://stackoverflow.com/questions/16830332
复制相似问题