简体   繁体   English

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

[英]What's the best way to get the namespaces in a WinMD file?

I'm looking to get all of the namespaces in a WinMD file programmatically. 我正在寻找以编程方式获取WinMD文件中的所有名称空间。 I would prefer a PowerShell or C#-based solution since I need it to be in a script, but any language will do as long as it gets the job done. 我希望使用基于PowerShell或C#的解决方案,因为我需要将其包含在脚本中,但是只要能完成工作,任何语言都可以。

Here is the code I have right now, using Assembly.ReflectionOnlyLoadFrom : 这是我现在使用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;
    }
}

For some reason, it doesn't seem to be working. 由于某种原因,它似乎无法正常工作。 When I run it, I'm getting a ReflectionTypeLoadException when I try to load WinMD files. 当我运行它时,尝试加载WinMD文件时出现了ReflectionTypeLoadException (You can see this question for the full details.) (您可以查看此问题的完整详细信息。)

So my question is, what's the best way to go about doing this, if the Reflection APIs aren't working? 所以我的问题是,如果Reflection API无法正常工作,最好的方法是什么? How do tools like Visual Studio or ILSpy do this when you hit F12 on a WinRT type? 当您在WinRT类型上按F12键时,像Visual Studio或ILSpy这样的工具如何做到这一点? Is there any way to do this from PowerShell? 有什么办法可以从PowerShell做到这一点?

TL;DR: How do I extract all of the namespaces from a WinMD file? TL; DR:如何从WinMD文件中提取所有名称空间? Any language solution accepted. 接受任何语言解决方案。

Thanks. 谢谢。

Ended up taking up @PetSerAl's suggestion for using Mono.Cecil , which is actually pretty solid. 最终采取了@ PetSerAl的建议使用Mono.Cecil能做到 ,这实际上是非常稳固。 Here's the approach I ended up taking (written in PowerShell): 这是我最终采用的方法(用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
}

You can find the full contents of the script here. 您可以在此处找到脚本的完整内容

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM