创建包支持框架修复

如果问题没有运行时修补程序,可以通过编写替换函数并包括任何有意义的配置数据来创建新的运行时修复。 让我们看看每个部分。

替换函数

首先,需要识别当应用程序在 MSIX 容器中运行时哪些函数调用失败。 然后可以创建替代的函数,让运行时管理器改为调用这些函数。 这样,便可以使用符合新式运行时环境规则的行为来替代函数的实现。

声明 FIXUP_DEFINE_EXPORTS 宏,然后为每个要在其中添加运行时修复函数之 .CPP 文件顶部的 fixup_framework.h 添加 include 语句。

#define FIXUP_DEFINE_EXPORTS
#include <fixup_framework.h>

重要

请确保 FIXUP_DEFINE_EXPORTS 宏显示在 include 语句之前。

创建一个函数,该函数的签名与要修改其行为的函数相同。 下面是替换 MessageBoxW 函数的示例函数。

auto MessageBoxWImpl = &::MessageBoxW;
int WINAPI MessageBoxWFixup(
    _In_opt_ HWND hwnd,
    _In_opt_ LPCWSTR,
    _In_opt_ LPCWSTR caption,
    _In_ UINT type)
{
    return MessageBoxWImpl(hwnd, L"SUCCESS: This worked", caption, type);
}

DECLARE_FIXUP(MessageBoxWImpl, MessageBoxWFixup);

调用 DECLARE_FIXUPMessageBoxW 函数映射到新的替换函数。 当应用程序尝试调用函数 MessageBoxW 时,它将改为调用替换函数。

防止对运行时修复中的函数进行递归调用

reentrancy_guard 类型可添加到函数中,以防止其被执行递归函数调用。

例如,可以生成 CreateFile 函数的替换函数。 你的实现可能会调用 CopyFile 函数,但 CopyFile 函数的实现可能会调用 CreateFile 函数。 这可能会导致对 CreateFile 函数执行无限递归循环调用。

有关 reentrancy_guard 的详细信息,请参阅 authoring.md

配置数据

如果要将配置数据添加到运行时修复,请考虑将其添加到 config.json。 这样,就可以使用 FixupQueryCurrentDllConfig 来轻松分析该数据。 此示例分析该配置文件中的布尔值和字符串值。

if (auto configRoot = ::FixupQueryCurrentDllConfig())
{
    auto& config = configRoot->as_object();

    if (auto enabledValue = config.try_get("enabled"))
    {
        g_enabled = enabledValue->as_boolean().get();
    }

    if (auto logPathValue = config.try_get("logPath"))
    {
        g_logPath = logPathValue->as_string().wstring();
    }
}

修复元数据

每个修复和 PSF 启动器应用程序都有一个 XML 元数据文件,其中包含以下信息:

  • 版本:MAJOR.MINOR.PATCH 格式的 PSF 的版本,基于 Sem 版本 2 确定。
  • 最低版本 Windows 平台:修复或 PSF 启动器所需的最低 Windows 版本。
  • 说明:对修复的简短说明。
  • WhenToUse:应用修复时机的启发式介绍。

有关示例,请参阅 FileRedirectionFixupMetadata.xml 元数据文件以了解重定向修复。 可以在这里找到元数据架构。