In the past I blogged quite a few times about two immensely useful albeit mostly-unofficial debugger features: watch modification via autoexp.dat, and step-into modification via NoStepInto registry key. A long while ago I raised two suggestions at MS UserVoice, to invest in making these two semi-hacks into documented, supported features. The first suggestion got some traction, and is officially implemented in VS2012. The 2nd suggestion went mostly ignored – but nevertheless, there’s a new and better – though still undocumented – way to skip functions while stepping.
NatVis files
The Natvis (native-visualizers) file format is the shiny new replacement for autoexp.dat. It is well documented, and although still quite rough around the edges – bugs are accepted and treated, which means that for the first time it is actually supported. The new apparatus comes with several design advantages:
- It seems to be better isolated and not to crash the IDE so much,
- New visualizer debugging facilities are built in,
- Separate customized visualizers can be kept in separate files, allowing easier sharing (e.g., library writers can now share distribute .natvis files with their libraries).
- Natvis files can be placed at per-user locations.
It isn’t that much fun rehashing the syntax – being official and all – but I will include here a custom mfc-containers natvis, similar to the autoexp section I shared a while back
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!--from afxwin.h -->
<Type Name="CArray<*,*>">
<AlternativeType Name="CObArray"></AlternativeType>
<AlternativeType Name="CByteArray"></AlternativeType>
<AlternativeType Name="CDWordArray"></AlternativeType>
<AlternativeType Name="CPtrArray"></AlternativeType>
<AlternativeType Name="CStringArray"></AlternativeType>
<AlternativeType Name="CWordArray"></AlternativeType>
<AlternativeType Name="CUIntArray"></AlternativeType>
<AlternativeType Name="CTypedPtrArray<*,*>"></AlternativeType>
<DisplayString>{{size = {m_nSize}}}</DisplayString>
<Expand>
<Item Name="[size]">m_nSize</Item>
<Item Name="[capacity]">m_nMaxSize</Item>
<ArrayItems>
<Size>m_nSize</Size>
<ValuePointer>m_pData</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="CList<*,*>">
<AlternativeType Name="CObList"></AlternativeType>
<AlternativeType Name="CPtrList"></AlternativeType>
<AlternativeType Name="CStringList"></AlternativeType>
<AlternativeType Name="CTypedPtrList<*,*>"></AlternativeType>
<DisplayString>{{Count = {m_nCount}}}</DisplayString>
<Expand>
<Item Name="Count">m_nCount</Item>
<LinkedListItems>
<Size>m_nCount</Size>
<HeadPointer>m_pNodeHead</HeadPointer>
<NextPointer>pNext</NextPointer>
<ValueNode>data</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="CMap<*,*,*,*>::CAssoc">
<AlternativeType Name="CMapPtrToWord::CAssoc"></AlternativeType>
<AlternativeType Name="CMapPtrToPtr::CAssoc"></AlternativeType>
<AlternativeType Name="CMapStringToOb::CAssoc"></AlternativeType>
<AlternativeType Name="CMapStringToPtr::CAssoc"></AlternativeType>
<AlternativeType Name="CMapStringToString::CAssoc"></AlternativeType>
<AlternativeType Name="CMapWordToOb::CAssoc"></AlternativeType>
<AlternativeType Name="CMapWordToPtr::CAssoc"></AlternativeType>
<AlternativeType Name="CTypedPtrMap<*,*,*>::CAssoc"></AlternativeType>
<DisplayString>{{key={key}, value={value}}}</DisplayString>
</Type>
<Type Name="CMap<*,*,*,*>">
<AlternativeType Name="CMapPtrToWord"></AlternativeType>
<AlternativeType Name="CMapPtrToPtr"></AlternativeType>
<AlternativeType Name="CMapStringToOb"></AlternativeType>
<AlternativeType Name="CMapStringToPtr"></AlternativeType>
<AlternativeType Name="CMapStringToString"></AlternativeType>
<AlternativeType Name="CMapWordToOb"></AlternativeType>
<AlternativeType Name="CMapWordToPtr"></AlternativeType>
<AlternativeType Name="CTypedPtrMap<*,*,*>"></AlternativeType>
<DisplayString Condition="(m_nHashTableSize >= 0 && m_nHashTableSize <= 65535">{{size={m_nHashTableSize}}}</DisplayString>
<Expand>
<Item Name="num bins">m_nHashTableSize</Item>
<ArrayItems>
<Size>m_nHashTableSize</Size>
<ValuePointer>m_pHashTable</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="CMap<*,*,*,*>">
<AlternativeType Name="CMapPtrToWord"></AlternativeType>
<AlternativeType Name="CMapPtrToPtr"></AlternativeType>
<AlternativeType Name="CMapStringToOb"></AlternativeType>
<AlternativeType Name="CMapStringToPtr"></AlternativeType>
<AlternativeType Name="CMapStringToString"></AlternativeType>
<AlternativeType Name="CMapWordToOb"></AlternativeType>
<AlternativeType Name="CMapWordToPtr"></AlternativeType>
<AlternativeType Name="CTypedPtrMap<*,*,*>"></AlternativeType>
<DisplayString>{Hash table too large!}</DisplayString>
</Type>
<Type Name="ATL::CAtlMap<*,*,*,*>">
<AlternativeType Name="ATL::CMapToInterface<*,*,*>"/>
<AlternativeType Name="ATL::CMapToAutoPtr<*,*,*>"/>
<DisplayString>{{Count = {m_nElements}}}</DisplayString>
<Expand>
<Item Name="Count">m_nElements</Item>
<ArrayItems>
<Size>m_nBins</Size>
<ValuePointer>m_ppBins</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="ATL::CAtlMap<*,*,*,*>::CNode">
<DisplayString Condition="this==0">Empty bucket</DisplayString>
<DisplayString Condition="this!=0">Hash table bucket</DisplayString>
</Type>
</AutoVisualizer>
Visualizing Map is a bit tricky, and I didn’t take the time yet to look deep into it – but the file is hopefully useful as it is. To use, just save the text as, say, MfcContainers.natvis, either under %VSINSTALLDIR%\Common7\Packages\Debugger\Visualizers (requires admin access), or under %USERPROFILE%\My Documents\Visual Studio 2012\Visualizers\ .
NatStepFilter Files
– are the new and improved substitute for the NoStepInto registry key. While there are some online hints and traces, the natstepfilter spec is yet to be introduced into MSDN – or even the VC++ team blog. For now you can watch the format specification, along with some good comments, at the %VSINSTALLDIR%\Xml\Schemas\natstepfilter.xsd near you, or even better – inspect a small sample at %VSINSTALLDIR%\Common7\Packages\Debugger\Visualizers\default.natstepfilter.
The default.natstepfilter is implemented by Stephen T. Lavavej, and is very far from complete – both because of regex limitations and because of decisions not to set non-overridable limitations on users:
“Adding something to the default natstepfilter is a very aggressive move, because I don’t believe there’s an easy way for users to undo it (hacking the file requires admin access), and it may be surprising when the debugger just decides to skip stuff.”
I can think of several ways for users to override .natstepfilter directives (never mind stepping-into via assembly, how about setting a plain breakpoint it the function you wish to step into?) – and so I don’t agree with that decision. Still I hope the default rules would improve alongside the documentation. We mostly avoid STL, so I had no need to customize .natstepfilter’s yet – I’ll be sure to share such customizations if I do go there.
Caveat
Both improvements, natvis and natstepfilter files, do not work for debugging native/managed mixed code, which sadly renders them unusable for most of our code. While this behavior is documented – I would hardly say it is ‘by design’. It does seem to irritate many others, so there is hope – as Brad Sullivan writes that MS are-
“… working on making everything just work in a future release of Visual Studio.”

Although I came to this post looking for autoexp.dat, I found your discussion of the NatStepFilter. I believe the better UI you want is included in Visual Assist:
http://www.wholetomato.com/features/feature-debug-assistance.asp
I work for the company that makes Visual Assist and the product isn’t free, but if you debug native C/C++, you do have a way to step directly into methods without stepping into the methods of argument lists.
@Jeff Straathof – thanks! I use VA extensively and have only love for the tool. You say that this debug-assistance feature is a wrapper around a custom natstepfilter file?
No, Visual Assist isn’t providing a UI to a custom natstepfilter file. I think Visual Assist does you better: it provides a UI as you debug. If you step into a method you don’t want to step into again, just mark the method. You don’t need to edit the natstepfilter file.
Visual Assist comes with built-in filters that step over common methods, e.g. the std string class.
You need Visual Assist build 2042 or newer to get the VA Step Filter.
http://wholetomato.com/features/whats-new.asp