首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >MsiInstallProduct()启动msiexe.exe,但以32位模式启动?

MsiInstallProduct()启动msiexe.exe,但以32位模式启动?
EN

Stack Overflow用户
提问于 2013-05-30 07:26:31
回答 2查看 1.9K关注 0票数 4

我有一个定制的安装应用程序,它安装了几个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命令结果:

代码语言:javascript
运行
复制
[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:

代码语言:javascript
运行
复制
[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:我刚刚发现这一行是问题的根源:

代码语言:javascript
运行
复制
oldHandler = MSIIntrop.MsiSetExternalUI(
    new MSIIntrop.InstallUIHandler(OnExternalUI),
    32735,
    IntPtr.Zero);

更新7最终更新:经过几个小时的浪费时间之后,我终于克服了这个问题。看起来,MSI中存在某种内部内存管理漏洞,这会导致外部UI处理程序完全随机崩溃。为了解决这个问题,我实现了IDisposable接口,并尝试在一个“使用”块中使用该类,以确保类被完全释放。MsiSetExternalUI()和MsiInstallProduct()现在在这个块中被安全地调用。不要忘记调用MsiSetExternalUI()将UI恢复到它的原始状态:

代码语言:javascript
运行
复制
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:感谢马塞尔和雅各布:)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-12-01 22:48:13

我认为,经过两年的代码运行,没有任何问题,最好总结一下上面更新7中提出的工作流,这是对以下问题的回答:

看起来,MSI中存在某种内部内存管理漏洞,这会导致外部UI处理程序完全随机崩溃。为了解决这个问题,我实现了IDisposable接口,并尝试在一个“使用”块中使用该类,以确保类被完全释放。MsiSetExternalUI()和MsiInstallProduct()现在在这个块中被安全地调用。不要忘记调用MsiSetExternalUI()将UI恢复到它的原始状态

票数 0
EN

Stack Overflow用户

发布于 2016-07-13 12:13:53

原因是垃圾收集器。请尝试使用GC.KeepAlive()方法防止垃圾收集器收集外部UI处理程序。

例如:

代码语言:javascript
运行
复制
// 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
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16830332

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档