获取 WinMD 文件中命名空间的最佳方法是什么

本文关键字:最佳 方法 是什么 命名空间 WinMD 文件 获取 | 更新日期: 2023-09-27 18:33:38

我希望以编程方式获取WinMD文件中的所有命名空间。我更喜欢基于 PowerShell 或 C# 的解决方案,因为我需要它在脚本中,但只要它完成工作,任何语言都可以。

这是我现在的代码,使用Assembly.ReflectionOnlyLoadFrom

var domain = AppDomain.CurrentDomain;
ResolveEventHandler assemblyHandler = (o, e) => Assembly.ReflectionOnlyLoad(e.Name);
EventHandler<NamespaceResolveEventArgs> namespaceHandler = (o, e) =>
{
    string file = WindowsRuntimeMetadata
        .ResolveNamespace(e.NamespaceName, Array.Empty<string>())
        .FirstOrDefault();
    if (file == null)
        return;
    var assembly = Assembly.ReflectionOnlyLoadFrom(file);
    e.ResolvedAssemblies.Add(assembly);
};
try
{
    // Load it! (plain .NET assemblies)
    return Assembly.LoadFrom(path);
}
catch
{
    try
    {
        // Hook up the handlers
        domain.ReflectionOnlyAssemblyResolve += assemblyHandler;
        WindowsRuntimeMetadata.ReflectionOnlyNamespaceResolve += namespaceHandler;
        // Load it again! (WinMD components)
        return Assembly.ReflectionOnlyLoadFrom(path);
    }
    finally
    {
        // Detach the handlers
        domain.ReflectionOnlyAssemblyResolve -= assemblyHandler;
        WindowsRuntimeMetadata.ReflectionOnlyNamespaceResolve -= namespaceHandler;
    }
}

出于某种原因,它似乎不起作用。当我运行它时,当我尝试加载 WinMD 文件时,我得到一个ReflectionTypeLoadException。(您可以看到这个问题的完整详细信息。

所以我的问题是,如果反射 API 不起作用,最好的方法是什么?当您在 WinRT 类型上按 F12 时,Visual Studio 或 ILSpy 等工具如何执行此操作?有没有办法从PowerShell做到这一点?

TL;DR:如何从 WinMD 文件中提取所有命名空间?接受任何语言解决方案。

谢谢。

获取 WinMD 文件中命名空间的最佳方法是什么

最终采纳了@PetSerAl的建议,使用 Mono.Cecil,这实际上非常可靠。这是我最终采用的方法(用PowerShell编写):

# Where the real work happens
function Get-Namespaces($assembly)
{
    Add-CecilReference
    $moduleDefinition = [Mono.Cecil.ModuleDefinition]
    $module = $moduleDefinition::ReadModule($assembly)
    return $module.Types | ? IsPublic | % Namespace | select -Unique
}
function Extract-Nupkg($nupkg, $out)
{
    Add-Type -AssemblyName 'System.IO.Compression.FileSystem' # PowerShell lacks native support for zip
    $zipFile = [IO.Compression.ZipFile]
    $zipFile::ExtractToDirectory($nupkg, $out)
}
function Add-CecilReference
{
    $url = 'https://www.nuget.org/api/v2/package/Mono.Cecil'
    $directory = $PSScriptRoot, 'bin', 'Mono.Cecil' -Join '''
    $nupkg = Join-Path $directory 'Mono.Cecil.nupkg'
    $assemblyPath = $directory, 'lib', 'net45', 'Mono.Cecil.dll' -Join '''
    if (Test-Path $assemblyPath)
    {
        # Already downloaded it from a previous script run/function call
        Add-Type -Path $assemblyPath
        return
    }
    ri -Recurse -Force $directory 2>&1 | Out-Null
    mkdir -f $directory | Out-Null # prevent this from being interpreted as a return value
    iwr $url -OutFile $nupkg
    Extract-Nupkg $nupkg -Out $directory
    Add-Type -Path $assemblyPath
}

您可以在此处找到脚本的完整内容。