我该如何在PowerShell中查询.pdb文件?

4

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

2个回答

3
DIA2接口的问题在于它不提供后期绑定支持,这使得它无法轻松地从脚本语言(如Powershell)中使用。
按照COM术语,它不提供从IDispatch派生的双重接口,只提供从IUnknown派生的接口。没有IDispatch,调用者无法在运行时确定任何给定对象可用的方法。

步骤1:生成类型库

在COM世界中,您需要使用类型库(.tlb文件)来传递此元数据,虽然DIA SDK没有提供此类类型库,但您可以从DIA SDK的dia2.idl文件生成它。

此步骤要求您有MIDL编译器可用,如果您已安装Visual C++公共工具(在安装程序菜单中的“编程语言/Visual C++/Visual C++ 2015的公共工具”下),则已安装Visual Studio 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和interface元数据。

步骤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")

现在,只需实例化其中一个CoClasses并开始使用它们即可:
$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 在 这里 所说的那样: "你不能使其工作。PowerShell 使用一个透明的“com 适配器”层来防止其工作,但启用脚本中的后期绑定。对于大多数情况而言,这是一件好事,但在你的情况下不是。"

由于问题出在 Powershell 中,而不是 .NET 总体上,因此您仍然可以使用 C# 代码从 Powershell 中访问 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

1
好文章:http://www.developerfusion.com/article/84368/debugging-with-the-dia-sdk/ - Burt_Harris
@Burt_Harris:.idl文件(基本上是描述提供的接口的契约)确实将它们声明为BSTR,但我在使用它们时没有遇到任何问题——生成的.NET包装器将它们公开为常规字符串并正确地进行了封送。还要注意,您引用的文章仅在使用NoRegCoCreate绕过常规COM加载机制时才谈到BSTR错误,而不是一般情况下BSTR错误。 - Leon Bouquiet
好的,那么我该如何打开一个会话呢?我似乎无法生成一个会话对象 $session = New-Object -ComObject Dia2Lib.IDiaSession,因为它显示了 New-Object : 检索组件 CLSID {00000000-0000-0000-0000-000000000000} 的 COM 类工厂失败,原因是以下错误: 80040154 类未注册 (来自 HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))。 - Adrian
另外,有没有一种方法可以列出名称空间“Dia2Lib”中的所有类?我尝试使用“Get-WMIObject -List -Namespace” Dia2Lib“”但没有成功。错误是“Get-WMIObject:无法从名称空间Dia2Lib获取对象。无效的名称空间。” - Adrian
@x0n编写了一个巧妙的PowerShell函数“Get-Interface”,它解决了PSObject和接口的限制问题,但是多年前发布时带有“此处有龙”的警告。我现在拥有的最新版本的“Get-Interface”在http://www.nivot.org/blog/post/2009/03/19/PowerShell20CTP3ModulesInPractice中。他的警告是我说这很难在PowerShell中实现的原因之一。 - Burt_Harris
显示剩余9条评论

1
从文档的外观来看,Debug Interface Access SDK 旨在用于 C++,而不是 .NET 语言。因此,我认为您将会在 PowerShell 中使用它非常困难。
严格来说,您需要知道要使用 New-Object -COM 的等效于 CLSID_DiaSourcePROGID。不幸的是,有些 COM 类不注册 PROGID,并以 C/C++ 特定形式(".h" 和 ".lib" 文件)提供其绑定元数据,而不是以语言无关的形式,例如 ITypeLib、ITypeComp 或甚至 IDispatch。因此,克服 New-Object 障碍只是开始。

请参见此帖子,了解.NET语言难以处理的COM操作示例(包括基本的QueryInterface)。另一个示例展示了即使在PowerShell中具有内置支持的ADSI COM对象也存在的一些限制

如果您有C++/COM开发经验,编写C++代码几乎肯定可以为项目节省时间。


1
由于它具有COM接口,这意味着可以通过任何能够与其进行接口的语言来访问它。是的,文档只提供了C++示例,但这并不意味着我不能通过另一种可以使用COM接口的语言来访问该功能。 - Adrian
我并没有说这是不可能的,我只是说这非常困难。尽管如此,我已经扩展了我的答案,以提供更多细节。我对你的建议是,为你项目的这部分编写一个C++命令行工具,这基于我超过20年的COM经验,其中17年是作为微软全职员工的经验。 - Burt_Harris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接