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

7
我知道我们可以通过传递以下命令参数,使用其MSI卸载Windows应用程序:
Process p = new Process(); 
p.StartInfo.FileName = "msiexec.exe"; 
p.StartInfo.Arguments = "/x \"C:\\MyApplication.msi\"/qn"; 
p.Start(); 

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

4个回答

7
沿着PhilmE的回答,Windows Installer XML(WiX)作为部署工具基础(DTF)的一部分,提供了Microsoft.Deployment.WindowsInstaller互操作库。这样可以跳过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");
}

7
根据MSDN的说明,您可以使用产品代码卸载它:
msiexec.exe /x {your-product-code-guid}

当您使用产品代码时,它会使用缓存的MSI(安装程序)来自于C:\WINDOWS\Installer


谢谢,我一直在想如果没有主要的MSI文件,如何进行卸载。现在我终于知道了缓存部分的作用 :) - Kurubaran

4

也许对于您的情况来说,了解"/x"参数已经足够了。关于此,有两点需要注意: 更安全的做法是在命令行中添加一个"REBOOT=R"部分。您还可以添加日志文件路径:

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

第二点,不要试图更改“缓存”中的任何内容。您甚至不需要理解它。如果缓存的软件包损坏,则无法进行常规卸载,这可能会导致计算机处于“需要支持”的状态。
因为您的问题最初是关于C#的...您不必使用msiexec:
a)使用原始的C/C++ API和函数MsiInstallProduct()或MsiConfigureProduct()。 MSDN参考: http://msdn.microsoft.com/en-us/library/windows/desktop/aa370315(v=vs.85).aspx 您需要使用互操作才能在C#中使用它。
或者b) 使用Windows Installer对象。 例如,这个相关案例已经在stackoverflow上得到了答案: 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而不是“安装程序对象”:-) 但对于小目的来说,它已经足够了。而且更容易。

1
请注意,Windows Installer XML (WiX) 作为部署工具基础 (DTF) 的一部分提供了 Microsoft.Deployment.WindowsInstaller 互操作库。这样可以跳过 COM 互操作并封装 Win32 API。 - Christopher Painter
是的,使用提到的库是第三种可能性。这是一个品味和用法的问题。如果您正在使用许多MSI功能,则该库当然值得一试。我不太了解它。如果您像类似的开源软件一样使用该库,则可能需要满足特殊的许可要求才能运输您的软件。在生成了Interop程序集后,使用本地MSI API在我看来并不难。但对于每个有兴趣的人来说,知道您可以在几种可能性之间选择是很好的。 - Philm
从技术上讲,WindowsInstaller.Installer是MSI.dll公开的两个“真正”的API之一。但是,我发现与COM互操作相比,P/Invoke MSI问题要少得多。DTF库非常出色,应该已经在BCL中发货了。话虽如此,如果您只需要1或2个API,请搜索“MSIInterop.cs”,并将其缩小到您的需求。 FOSS论点是恐吓宣传。 - Christopher Painter
事实上,WindowsInstaller.Installer是“基本”API的COM包装器,因此它调用另一个API。我同意,出于几个原因,它不像P/Invoke MSI API那样稳定和牢固。最初,它是为脚本任务而设计的。 - Philm

3

这个命令可以在命令行上使用:

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接