OLE32 Stack Walking

In Vista & 7 (but not above), OLE32 contains a family of threadsafe COM classes that wrap the symbol functions in imagehlp.dll. These interfaces provide encapsulation of stack walking and address to symbol translation

Attach calls SymInitialize passing hProcess unmodified (or as GetCurrentProcess in the NULL case). It passes NULL & FALSE as the other two parameters, so the symbol server will only be used if the _NT_SYMBOL_PATH/_NT_ALTERNATE_SYMBOL_PATH environment variables are set before calling.
Attach also calls SymSetOptions with 0 as the options value, turning off all the options. You can reset these by calling SymSetOptions yourself.

Other Interfaces

The other functions of IStackWalker return other interfaces directly instead of HRESULTS. This is a theme which continues into these other interfaces, which are defined as:

MIDL_INTERFACE("00000158-0000-0000-c000-000000000046")
IStackWalkerStack : IUnknown
{
// returns the interface for the top symbol of this stack trace
STDMETHOD_(IStackWalkerSymbol*, TopSymbol)(void);
// Returns the number of characters required hold 'numSymbols' lines of the stack trace
// the return size is the required buffer size to pass to GetStack to get this many lines
STDMETHOD_(ULONG, Size)(ULONG numSymbols);
// Retrieves 'numSymbols' lines of the textual stack trace
// starting from the top. 'bufferChars' is the size of 'pNameBuffer'
// in characters
STDMETHOD_(BOOL, GetStack)(ULONG bufferChars, PWSTR pNameBuffer, ULONG numSymbols);
};
MIDL_INTERFACE("00000157-0000-0000-c000-000000000046")
IStackWalkerSymbol : IUnknown
{
// These strings are owned by the interface, do not
// attempt to free them by any means
STDMETHOD_(PCWSTR, ModuleName)(void);
STDMETHOD_(PCWSTR, SymbolName)(void);
STDMETHOD_(ULONG64, Address)(void);
STDMETHOD_(ULONG64, Displacement)(void);
// this returns the aymbol underneath this one in the stack
// calling this in s loop on the returned interfaces allows
// you to enumerate the stack trace. A NULL return means
// this is bottom of the stack
STDMETHOD_(IStackWalkerSymbol*, NextSymbol)(void);
};

Usage Example

This example creates the interface, causes an exception to get a valid context and then prints the stack trace. Then it looks up a simple address to demonstrate that too!

If you compile and run the above code, the first thing you'll notice is that it prints "Failed to create StackTrace!" It'll do that no matter which thread handle or however you construct the CONTEXT you pass to CreateStackTrace. This is because there is a bug within CreateStackTrace that causes StackWalk64 to fail everytime:

When setting up the StackFrame64 structure for the first call, the address of the stack (esp), frame (ebp) and program counter (eip) are saved into it. As StackWalk can handle walking through 16-bit code, you also have to tell it which address mode the offsets are in. The push/pop to eax shows this to be AddrModeFlat (which has the value 3), and the mov's into the Mode members show these being initialized correctly. But as you can see, there are three sets of offsets written, but only two modes. This leaves the mode for the Frame as 0, which is AddrMode1616. Since the flat address is invalid as a 1616 address, this causes StackWalk64 to fail.

This issue doesn't affect IStackWalker::ResolveAddress, so that still works for looking up individual address symbols, little consolation though that is.