如何在 c# 中使用其产品代码卸载 MSI

Posted

技术标签:

【中文标题】如何在 c# 中使用其产品代码卸载 MSI【英文标题】:How to uninstall MSI using its Product Code in c# 【发布时间】:2013-07-05 15:04:35 【问题描述】:

我知道我们可以使用它的 MSI 卸载 Windows 应用程序,方法是传递如下命令参数,

Process p = new Process(); 
p.StartInfo.FileName = "msiexec.exe"; 
p.StartInfo.Arguments = "/x \"C:\\MyApplication.msi\"/qn"; 
p.Start(); 

但我想知道的是如何在不使用 MSI 的情况下卸载应用程序?在上述情况下,我应该在特定位置有 MSI 来卸载此应用程序,如果我可以使用产品代码卸载,那么我不需要在目标机器中拥有 MSI。

【问题讨论】:

【参考方案1】:

根据MSDN,您可以使用产品代码卸载它:

msiexec.exe /x your-product-code-guid

当您使用产品代码时,它使用来自C:\WINDOWS\Installer 的缓存 MSI。

【讨论】:

谢谢,我想知道在没有主 MSI 的情况下如何进行卸载。现在只有我知道缓存部分:)【参考方案2】:

按照 PhilmE 的回答,Windows Installer XML (WiX) 将 Microsoft.Deployment.WindowsInstaller 互操作库作为部署工具基础 (DTF) 的一部分提供。这会跳过 COM 互操作并封装 Win32 API。

using Microsoft.Deployment.WindowsInstaller;

public static void Uninstall( string productCode)

    Installer.ConfigureProduct(productCode, 0, InstallState.Absent, @"REBOOT=""R"" /l*v uninstall.log");

【讨论】:

【参考方案3】:

可能对于您的情况,知道“/x”参数就足够了。对此有两点评论: 更安全的是在命令行中添加“REBOOT=R”部分。你可以添加一个日志文件路径:

msiexec /x "..." /qn REBOOT=R /L*v "c:\mylogdir\mymsi.log"

其次,不要尝试将任何内容更改为“缓存”。你甚至不需要理解它。如果缓存的包被破坏,则无法再进行常规卸载,这可能会使计算机处于“需要支持”状态。

因为您的问题最初是在谈论 C# .. 您不必为此使用 msiexec:

a) 使用带有函数 MsiInstallProduct() 或 MsiConfigureProduct() 的原始 C/C++ API。 MSDN 参考: http://msdn.microsoft.com/en-us/library/windows/desktop/aa370315(v=vs.85).aspx

您必须使用互操作才能在 C# 中使用它。

或 b) 使用 Windows 安装程序对象。 例如,这个相关案例已经在 *** 中得到解答: Programmatically installing MSI packages 但是使用这个功能需要物理包,也需要卸载。 稍微间接一点,这里是更好的卸载代码:

首先,在您的项目中添加对 COM 对象“Microsoft Windows Installer Object Library”的引用。

using WindowsInstaller;


public static class MyMsiLib

    public static void Uninstall(string productCode)
    

         Type type = Type.GetTypeFromProgID("WindowsInstaller.Installer");
         Installer installer = (Installer)Activator.CreateInstance(type);
         installer.UILevel=msiUILevelNone;
         installer.ConfigureProduct(productCode, 0, msiInstallStateAbsent);
    

之前的 UILevel 属性在此处设置为硬编码,以确定您似乎想要的静默 UI 级别。其他属性也一样。请参阅 MSDN 文档,例如在上面的链接中提到。

当然,“真正的程序员”使用原始 API 而不是“安装程序对象”:-) 但对于小目的来说就足够了。而且更容易。

【讨论】:

仅供参考 Windows Installer XML (WiX) 将 Microsoft.Deployment.WindowsInstaller 互操作库作为部署工具基础 (DTF) 的一部分提供。这会跳过 COM 互操作并封装 Win32 API。 是的,使用上述库是第三种可能性。这是品味和使用的问题。如果您使用 MSI 做很多事情,那么这个库当然值得一试。我不太清楚。如果您将该库用于类似的开源,您可能必须满足交付软件的特殊许可要求。在生成互操作程序集后,在我看来使用本机 MSI API 并没有那么困难。但很高兴让所有感兴趣的人知道,您可以在多种可能性之间进行选择。 从技术上讲,WindowsInstaller.Installer 是 MSI.dll 公开的两个“真实”API 之一。但是,我发现 P/Invoking MSI 的问题比 COM 互操作要小得多。 DTF 库做得非常好,应该在 BCL 中提供。也就是说,如果您只需要 1 或 2 个 API 的 google“MSIInterop.cs”并将其减少到您的需要。 FOSS 参数是 FUD。 实际上 WindowsInstaller.Installer 是“基础”API 的 COM 包装器,因此它调用另一个。我同意它不像 P/Invoking MSI API 那样稳定和防弹,有几个原因。最初,它是为编写脚本任务而制作的。【参考方案4】:

此命令在命令行上运行:

msiexec /x 3A40307D-6DF2-4412-842F-B1D848043367 /quiet

我没有在 C# 中尝试过,但是用上面显示的键替换你的参数应该可以。您可以在您尝试卸载的应用的注册表项中找到 GUID。

【讨论】:

以上是关于如何在 c# 中使用其产品代码卸载 MSI的主要内容,如果未能解决你的问题,请参考以下文章

使用可覆盖属性时如何按命令行卸载 MSI 包?

安装后MSI文件复制到哪里?

使用 C# 以编程方式卸载软件

C#打包时如何添加卸载程序????

如何使用 WiX 和 MSI 进行静默安装和卸载?

如何在每次创建 msi 期间动态更改 wix 中的产品版本