创建包支持框架修复

如果没有可以解决问题的运行时问题解决方案,可以编写替代函数,并包括任何相关的配置数据以创建新的运行时解决方案。 让我们看看每个部分。

替换函数

首先,确定应用程序在 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_FIXUP的调用将MessageBoxW函数映射到您的新替换函数。 当应用程序尝试调用函数 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 元数据文件,其中包含以下信息:

  • Version:PSF 的版本采用 MAJOR.MINOR.PATCH 格式,遵循语义版本 2 的规范。
  • 最低 Windows 平台:修复或 PSF 启动器所需的最低 Windows 版本。
  • Description:修正的简短说明。
  • WhenToUse:关于何时应该应用该修正的经验法则。

有关示例,请参阅重定向修复的 FileRedirectionFixupMetadata.xml 元数据文件。 此处 提供了元数据架构。