From Querying the .Pdb File I can see that there is a COM interface to access the contents of a .pdb file. Now, how would I access that interface from PowerShell? I know I need to use New-Object -ComObject ...
but I don't know what I need to specify in the ...
section.

- 10,246
- 4
- 44
- 110
2 Answers
The problem with DIA2 interfaces is that it doesn't provide late-binding support that would make it easily usable from scripting languages like Powershell.
In COM terms, it doesn't provide dual interfaces that derive from IDispatch, only interfaces that derive from IUnknown. Without IDispatch, it is impossible
for the caller to figure out at run time which methods are available from any given object.
Step 1: Generating a Type Library
In the COM world, you would use a Type Library (.tlb file) to communicate this metadata, and although the DIA SDK doesn't provide such a type library out of the box, you can generate it from the dia2.idl file that is part of the DIA SDK.
This step requires that you have the MIDL compiler available, which is installed as a part of Visual Studio 2015 if you've installed the Visual C++ common tools (under "Programming Languages/Visual C++/Common Tools for Visual C++ 2015" in the installer menu).
Open an elevated (i.e. with Run as adminstrator) Visual Studio Command Prompt and navigate to the DIA SDK:
cd C:\Program Files (x86)\Microsoft Visual Studio 14.0\DIA SDK
From here, run the Microsoft IDL compiler on the idl\dia2.idl file:
midl idl\dia2.idl /tlb dia2.tlb /I .\include
This will generate the file dia2.tlb, which contains the coclass and interface metadata.
Step 2: Generating a COM class wrapper
To be able to use this metadata from .NET, microsoft provides a Type Library importer tool that generates managed wrappers based on a .tlb file. For more information, see https://msdn.microsoft.com/en-us/library/aa645736(VS.71).aspx. Invoke it from the same directory as follows:
tlbimp dia2.tlb
It should respond with:
TlbImp : Type library imported to Dia2Lib.dll
In other words, you now have the .NET type definitions for the DIA SDK. Check it out with ILSpy if you like.
Step 3: Use these types from Powershell.
Using these types is now a breeze. First load in the wrapper dll (assuming it is located in the current working directory):
[void][System.Reflection.Assembly]::LoadFile("$pwd\Dia2Lib.dll")
Now, simply instantiate one of the CoClasses and start using them:
$ds = new-object Dia2Lib.DiaSourceClass
$ds.lastError
Edit: I'm having trouble getting a useful result when calling openSession
from Powershell. That is, Powershell knows that it is a IDiaSession
object
$sessionObj = $null
$ds.openSession([ref]$sessionObj)
$sessionObj -is [Dia2Lib.IDiaSession]
True
But somehow doesn't provide access to the members this interface exposes:
$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()
Edit 2: Apparently, as x0n says here "You can't make this work. PowerShell uses a transparent "com adapter" layer that prevents this from working, but enables late binding in script. For the majority of cases this a Good Thing, but not in yours."
Since the problem lies within Powershell, not .NET in general, you can still use C# code from within Powershell to access the 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
- 1

- 4,159
- 3
- 25
- 36
-
This looks great! Very detailed. Can't wait to try it out. – Adrian Sep 10 '16 at 16:20
-
So, does step 2 generate the IDispatch you're referring to? – Adrian Sep 10 '16 at 16:24
-
Yes in theory this will get you a type library, but but even with that it will still be very difficult to use the DIA interfaces from a .NET language. For example, the strings DIA interfaces return are **not** based on BSTR (nor System.String), so properly freeing any strings obtained from these interfaces them requires a call to LocalFree. – Burt_Harris Sep 10 '16 at 16:27
-
1Good article: http://www.developerfusion.com/article/84368/debugging-with-the-dia-sdk/ – Burt_Harris Sep 10 '16 at 16:28
-
@Adrian: No, IDispatch should have been built into the SDK, it cannot be added afterwards. It provides reflection-like capabilities so that .NET could discover at run time which methods each interface provides. What we're doing now is using metadata that is provided separately from the COM service (the .tlb) to generate a .NET wrapper at compile time, which (being .NET types) has all its type information in it. – Leon Bouquiet Sep 10 '16 at 18:50
-
@Burt_Harris: The .idl file (which is basically the contract that describes the provided interfaces) *does* declare them as BSTRs though, and I haven't had any problems with using them - the generated ,NET wrapper exposes them as regular strings and marshalls them correctly. Also note that the article you reference only talks about BSTRs being wrong if you bypass the regular COM loading mechanism with NoRegCoCreate, not about BSTRs being wrong in general. – Leon Bouquiet Sep 10 '16 at 18:58
-
Ok, so how would I open a session with this? I can't seem to generate a session object `$session = New-Object -ComObject Dia2Lib.IDiaSession` as it states `New-Object : Retrieving the COM class factory for component with CLSID {00000000-0000-0000-0000-000000000000} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).` – Adrian Sep 10 '16 at 19:10
-
Also, is there a way to list all of the classes in the namespace `Dia2Lib`? I tried `Get-WMIObject -List -Namespace "Dia2Lib"` without success. Error was `Get-WMIObject : Could not get objects from namespace Dia2Lib. Invalid namespace ` – Adrian Sep 10 '16 at 19:16
-
@Adrian: IDiaSession is an interface, you can't instantiate these directly. What you would normally do is declare it as a typed variable but assign it null, i.e. `[Dia2Lib.IDiaSession]$session = $null`, and use that variable: `$ds.openSession([ref]$session)`, except that Powershell refuses to convert the COM objects (I don't know why). As for your second question, use `$obj.GetType()` or `$obj | Get-Member` for individual type info, or use http://ilspy.net/ if you really want a good look. – Leon Bouquiet Sep 10 '16 at 19:47
-
Get-WMIObject is only for WMI objects, not COM objects. The reason – Burt_Harris Sep 11 '16 at 09:32
-
The reason you don't see any methods on the object you created with New-Object is that it doesn't import the type library information into the .NET wrapper object. – Burt_Harris Sep 11 '16 at 09:41
-
@Burt_Harris: The type library information has already been statically compiled into the .NET wrapper types by `tlbimp`; the wrapper types *do* contain all interface members. The problem is that Powershell sees these objects primarily as COM objects, not as the .NET interface that it implements. – Leon Bouquiet Sep 11 '16 at 09:59
-
Yes @Astrotrain, the type information has been statically compiled into the "Runtime Callable Wrapper", which is why you can access it from C#. New-Object instantiates the RCW and wraps it again in a PSObject (which I imprecisely called a .NET Wrapper.) The problem you refer to is that PSObject doesn't support anything equivalent to QueryInterface, regardless if object it wraps is COM or .NET. – Burt_Harris Sep 11 '16 at 11:23
-
@x0n wrote a clever PowerShell function "Get-Interface" which works around the limitation of PSObject and interfaces., but it was published years back with a "thar be dragons" warning. The latest version of "Get-Interface" I have is at http://www.nivot.org/blog/post/2009/03/19/PowerShell20CTP3ModulesInPractice. His warning is part of the reason I said this is very hard.in PowerShell. – Burt_Harris Sep 11 '16 at 11:24
From the looks of the documentation, the Debug Interface Access SDK is intended to be used from C++, not .NET languages. For this reason I think you'll have a very hard time using it from PowerShell.
Strictly speaking, what you need to know to use New-Object -COM
is a PROGID
that is equivalent to CLSID_DiaSource
. Unfortunately some COM classes don't register a PROGID and provide their binding metadata in C/C++ specific form (".h" and ".lib" files, rather than in language-independent form like ITypeLib, ITypeComp or even IDispatch.) As a result, getting past the New-Object hurdle is just the beginning.
See this post for an example of the sort of COM operations (as basic as QueryInterface) that are hard to address from any .NET language. Another shows the related sort of limitations that occur even on ADSI COM objects which have built-in support in PowerShell.
If you are experienced in C++/COM development it will almost certainly save you time to write in C++ for this part of your project.

- 1
- 1

- 6,415
- 2
- 29
- 64
-
1As it is has a COM interface, that means that it is accessible via any language which can interface to it. Yes, the documentation has only C++ examples, but that doesn't mean that I cannot access that functionality through another language that can use COM interfaces. – Adrian Sep 10 '16 at 13:30
-
I didn't say it wasn't possible, I said it was very hard. None the less I've expanded my answer to provide a little more detail. My advice to you is to write a C++ command-line tool for this part of your project is based on over 20 years of experience with COM, 17 years of that as a Microsoft full-time employee. – Burt_Harris Sep 10 '16 at 15:54