【问题标题】:How can I query a .pdb file in PowerShell?如何在 PowerShell 中查询 .pdb 文件?
【发布时间】:2016-09-11 17:34:03
【问题描述】:

Querying the .Pdb File 我可以看到有一个COM 接口可以访问.pdb 文件的内容。现在,我将如何从 PowerShell 访问该接口?我知道我需要使用New-Object -ComObject ...,但我不知道我需要在... 部分指定什么。

【问题讨论】:

    标签: powershell com


    【解决方案1】:

    DIA2 接口的问题在于,它不提供后期绑定支持,因此无法在 Powershell 等脚本语言中轻松使用它。
    在 COM 术语中,它不提供从 IDispatch 派生的双重接口,只提供从 IUnknown 派生的接口。没有 IDispatch,这是不可能的 让调用者在运行时找出任何给定对象都可以使用哪些方法。

    第 1 步:生成类型库

    在 COM 世界中,您将使用类型库(.tlb 文件)来传达此元数据,尽管 DIA SDK 不提供这样的类型库 开箱即用,您可以从 DIA SDK 中的 dia2.idl 文件生成它。

    此步骤要求您有可用的 MIDL 编译器,如果您已安装,则该编译器将作为 Visual Studio 2015 的一部分安装 Visual C++ 常用工具(在安装程序菜单中的“Programming Languages/Visual C++/Common Tools for Visual C++ 2015”下)。

    打开一个提升的(即以管理员身份运行)Visual Studio 命令提示并导航到 DIA SDK:

    cd C:\Program Files (x86)\Microsoft Visual Studio 14.0\DIA SDK
    

    从这里,对 idl\dia2.idl 文件运行 Microsoft IDL 编译器:

    midl idl\dia2.idl /tlb dia2.tlb /I .\include
    

    这将生成文件 dia2.tlb,其中包含 coclass 和接口元数据。

    第 2 步:生成 COM 类包装器

    为了能够使用 .NET 中的此元数据,Microsoft 提供了一个类型库导入器工具,该工具可以基于 .tlb 文件生成托管包装器。 有关详细信息,请参阅https://msdn.microsoft.com/en-us/library/aa645736(VS.71).aspx。从同一目录调用它,如下所示:

    tlbimp dia2.tlb
    

    它应该回应:

    TlbImp : Type library imported to Dia2Lib.dll
    

    换句话说,您现在有了 DIA SDK 的 .NET 类型定义。如果您愿意,请使用 ILSpy 进行检查。

    第 3 步:在 Powershell 中使用这些类型。

    现在使用这些类型变得轻而易举。首先加载包装器dll(假设它位于当前工作目录中):

    [void][System.Reflection.Assembly]::LoadFile("$pwd\Dia2Lib.dll")
    

    现在,只需实例化其中一个 CoClass 并开始使用它们:

    $ds = new-object Dia2Lib.DiaSourceClass
    $ds.lastError
    

    编辑:从 Powershell 调用 openSession 时,我无法获得有用的结果。也就是Powershell知道它是一个IDiaSession对象

    $sessionObj = $null
    $ds.openSession([ref]$sessionObj)
    $sessionObj -is [Dia2Lib.IDiaSession]
    True
    

    但不知何故不提供对该接口公开的成员的访问:

    $sessionObj | Get-Member
    
    TypeName: System.__ComObject
    
    Name                      MemberType Definition
    ----                      ---------- ----------
    CreateObjRef              Method     System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
    Equals                    Method     bool Equals(System.Object obj)
    GetHashCode               Method     int GetHashCode()
    GetLifetimeService        Method     System.Object GetLifetimeService()
    GetType                   Method     type GetType()
    InitializeLifetimeService Method     System.Object InitializeLifetimeService()
    ToString                  Method     string ToString()
    

    编辑 2: 显然,正如 x0n 所说,here你不能让它工作。PowerShell 使用透明的“com 适配器”层来阻止它工作,但启用脚本中的后期绑定。在大多数情况下,这是一件好事,但不是你的。"

    由于问题出在 Powershell 中,而不是一般的 .NET,您仍然可以使用 Powershell 中的 C# 代码来访问 SDK:

    # Declare a C# helper class inline, and make it available in the current Powershell session:
    $diaSessionHelperClassDef = @"
        using Dia2Lib;
    
        public class DiaSessionHelper
        {
            public IDiaSession Session { get; private set; }
    
            public DiaSessionHelper(IDiaDataSource dataSource)
            {
                IDiaSession result = null;
                dataSource.openSession(out result);
                Session = result;
            }
    
            public string GlobalScopeName
            {
                get{ return Session.globalScope.name; }
            }
        }
    
    "@
    
    Add-Type -TypeDefinition $diaSessionHelperClassDef -ReferencedAssemblies "$pwd\Dia2Lib.dll"
    
    # Use this class to access the SDK's functionality:
    $diaHelper = new-object DiaSessionHelper($ds)
    $diaHelper.GlobalScopeName
    Acme
    

    【讨论】:

    • 这看起来很棒!非常详细。迫不及待想尝试一下。
    • 那么,第 2 步会生成您所指的 IDispatch 吗?
    • 是的,理论上这会给你一个类型库,但即便如此,使用 .NET 语言的 DIA 接口仍然非常困难。例如,DIA 接口返回的字符串不是基于 BSTR(也不是 System.String),因此正确释放从这些接口获得的任何字符串都需要调用 LocalFree。
    • @Adrian: 不,IDispatch 应该已经内置在 SDK 中,之后无法添加。它提供了类似反射的功能,因此 .NET 可以在运行时发现每个接口提供的方法。我们现在正在做的是使用与 COM 服务(.tlb)分开提供的元数据在编译时生成一个 .NET 包装器,其中(作为 .NET 类型)包含其所有类型信息。
    【解决方案2】:

    从文档的外观来看,Debug Interface Access SDK 旨在用于 C++,而不是 .NET 语言。出于这个原因,我认为您将很难从 PowerShell 中使用它。

    严格来说,使用New-Object -COM 需要知道的是PROGID,它相当于CLSID_DiaSource。不幸的是,一些 COM 类没有注册 PROGID 并以 C/C++ 特定形式(“.h”和“.lib”文件,而不是像 ITypeLib、ITypeComp 甚至 IDispatch 等与语言无关的形式)提供它们的绑定元数据。因此,克服新对象的障碍仅仅是开始。

    请参阅this post,了解任何 .NET 语言都难以解决的那种 COM 操作(与 QueryInterface 一样基本)的示例。另一个显示了相关的sort of limitations that occur even on ADSI COM objects,它在 PowerShell 中具有 内置 支持。

    如果您在 C++/COM 开发方面经验丰富,那么几乎可以肯定地为您在项目的这一部分中使用 C++ 编写代码节省您的时间。

    【讨论】:

    • 因为它有一个 COM 接口,这意味着它可以通过任何可以与之交互的语言访问。是的,文档只有 C++ 示例,但这并不意味着我不能通过可以使用 COM 接口的另一种语言访问该功能。
    • 我没有说不可能,我说这很难。尽管如此,我还是扩展了我的答案以提供更多细节。我对您的建议是为您项目的这一部分编写一个 C++ 命令行工具,该工具基于 20 多年的 COM 经验,其中 17 年是 Microsoft 的全职员工。
    猜你喜欢
    • 2014-12-16
    • 2010-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-27
    • 2015-11-01
    相关资源
    最近更新 更多