如何以编程方式卸载我的 MSIX python 应用程序?

Posted

技术标签:

【中文标题】如何以编程方式卸载我的 MSIX python 应用程序?【英文标题】:How can I programmatically uninstall my MSIX python app? 【发布时间】:2021-10-25 21:18:54 【问题描述】:

我刚刚在 python 3 中编写了我的第一个 MSIX 应用程序。我使用 pyinstaller 生成一个 EXE。然后我使用WiX Toolset 生成一个MSI。然后我使用 MSIX Packaging Tool 创建 MSIX。从代码到 MSIX 可能有一种更简单的方法,但这就是我目前所做的工作。

理想情况下,我想捕获一个 onuninstall 事件并抛出一个 GUI 提示,询问用户为什么要卸载。我可以在 MSI 中做到这一点。但是,我的理解是MSIX offers no onuninstall event。如果您有不同的认识,请告诉我!

由于我显然无法捕捉 MSIX 卸载事件,我的下一个偏好是为用户提供一种从托盘图标卸载应用程序的方法。用户从我的应用程序图标中选择一个卸载托盘菜单按钮,该按钮会弹出一个窗口,然后应用程序会在其中询问他们为什么要卸载。他们输入答案,然后单击提交按钮。然后,该应用程序应完全自行卸载。这在 MSI 中也很有效。但是,我无法让它在 MSIX 中工作。

以下是安装了 MSI 的 python 中的工作原理:

subprocess.call('msiexec.exe /x ' + myguid + '', shell=True)

但是,从 MSI 构建的 MSIX 在该行运行时抛出此弹出错误消息,并且从未实际卸载应用程序:

This action is only valid for products that are currently installed.

我尝试使用硬编码的 WXS 文件的 <Product> 条目中的 GUID,只是为了看看它是否可以工作。那一个适用于卸载 MSI,但不适用于 MSIX。我还尝试动态获取 GUID,但这对 MSI 或 MSIX 都不起作用,两者都会产生与上述相同的错误。以下是我动态获取 GUID 的方法:

from System.Runtime.InteropServices import Marshal
from System import Reflection

myguid = str(Marshal.GetTypeLibGuidForAssembly(
    Reflection.Assembly.GetExecutingAssembly()
)).upper()

在运行 MSI 时(我的日志记录比在 MSIX 中好得多),似乎GetExecutingAssembly() 获得了一个带有Python.RuntimeFullName 的程序集,这当然是我不想要的卸载。 GetCallingAssembly() 产生相同的结果。 GetEntryAssembly() 产生一个 null 值。

我通过AppDomain.CurrentDomain.GetAssemblies() 循环查看列出的内容,但我的应用未列出,尽管我看到了它使用的许多库。

那么,对于如何让应用程序以编程方式卸载有什么想法吗?如果这是问题所在,也许是关于如何获得 MSIX 应用程序的正确 GUID 的建议? DotNet 代码应该没问题。我大概能弄清楚如何将它翻译成 python。

或者更好的是,知道如何捕获 MSIX 卸载事件并运行一些自定义代码吗?

提前致谢!

【问题讨论】:

【参考方案1】:

据我所知,目前无法捕获卸载事件。我不建议实施您建议的方法(托盘图标),但要提出您的问题,您可以使用 MSIX PowerShell commandlets 以编程方式安装和卸载 MSIX 包。

另外,我注意到你真的在折磨自己来创建 MSIX 包。

MSIX 打包工具由 Microsoft 为无法访问源代码的 IT 专业人员创建。开发人员可以使用 Windows 应用程序打包项目项目模板(如果他们使用 Visual Studio)或其他第三方工具,例如 Advanced Installer 或 Wix(据我所知,有一个 Wix extension that can be used to build MSIX packages)。

这里有一个关于如何从头开始创建 MSIX 的快速教程,使用高级安装程序更容易: https://www.advancedinstaller.com/create-msi-python-executable.html

免责声明:我在团队建设 Advanced Installer 工作。

【讨论】:

谢谢!我之前尝试过 WiX MSIX 进程,但无法让它为我工作。如果我没记错的话,WiX MSIX 也只适用于 Visual Studio 项目,而我根本没有使用 Visual Studio。我怀疑 Advanced Installer 会让事情变得更容易,但我试图在不花费任何额外 $$ 的情况下完成此操作。不过我会检查命令行开关!【参考方案2】:

我使用了 Bogdan 的 Powershell 建议,并提出了以下代码,似乎运行良好:

import subprocess

powershellLocation = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
try:
    # Use the name of the app (which I found manually using Get-AppPackage)
    # to get the full name of the app, which seems to have some random numbers
    # on the end of it.
    powershell_tuple = subprocess.Popen([
        powershellLocation,
        "Get-AppPackage",
        "-name",
        '"' + myAppPackageName + '"'
    ],shell=True,stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE).communicate()
    appStrings = powershell_tuple[0].decode('utf-8').strip()
except Exception as e:
    pass
for appStr in appStrings.splitlines():
    # Find the full name of the app
    if appStr.startswith('PackageFullName'):
        colonIndex = appStr.index(':') + 1
        fullName = appStr[colonIndex:].strip()
if fullName:
    # The MSIX package was found, and I now have its full name
    subprocess.call(powershellLocation + ' Remove-AppPackage -Package "' + fullName + '"', shell=True)

【讨论】:

以上是关于如何以编程方式卸载我的 MSIX python 应用程序?的主要内容,如果未能解决你的问题,请参考以下文章

iOS Swift:以编程方式安装和卸载视图

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

如何以编程方式卸载 Windows 中的应用程序?

MSIX 侧载应用在更新后启动缓慢

如何以编程方式从标签栏控制器卸载视图控制器?

以编程方式卸载浏览器外的 silverlight 应用程序