从查询 .Pdb 文件可以看到,有一个 COM 接口可以访问 .pdb 文件的内容。那么,我该如何从 PowerShell 访问该接口呢?我知道需要使用New-Object -ComObject ...
,但我不知道在...
部分需要指定什么。
从查询 .Pdb 文件可以看到,有一个 COM 接口可以访问 .pdb 文件的内容。那么,我该如何从 PowerShell 访问该接口呢?我知道需要使用New-Object -ComObject ...
,但我不知道在...
部分需要指定什么。
在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元数据。
为了能够从.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进行检查。
现在使用这些类型非常容易。首先加载包装器dll(假设它位于当前工作目录中):
[void][System.Reflection.Assembly]::LoadFile("$pwd\Dia2Lib.dll")
$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
New-Object -COM
的等效于 CLSID_DiaSource
的 PROGID
。不幸的是,有些 COM 类不注册 PROGID,并以 C/C++ 特定形式(".h" 和 ".lib" 文件)提供其绑定元数据,而不是以语言无关的形式,例如 ITypeLib、ITypeComp 或甚至 IDispatch。因此,克服 New-Object 障碍只是开始。
请参见此帖子,了解.NET语言难以处理的COM操作示例(包括基本的QueryInterface)。另一个示例展示了即使在PowerShell中具有内置支持的ADSI COM对象也存在的一些限制。
如果您有C++/COM开发经验,编写C++代码几乎肯定可以为项目节省时间。
$session = New-Object -ComObject Dia2Lib.IDiaSession
,因为它显示了New-Object : 检索组件 CLSID {00000000-0000-0000-0000-000000000000} 的 COM 类工厂失败,原因是以下错误: 80040154 类未注册 (来自 HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))。
- Adrian