Visual C++ includes several undocumented diagnostic tools that developers can use to their advantage when writing and debugging C++/CX code. This white paper examines some of these switches, which can make it easier to detect bugs and glitches. It explores tools for debugging the binary layout of classes, automatically generated interfaces, functions, and vtables, and it discusses methods for instrumenting object usage and for tracking down leaked objects for a given class. In short, the paper lays out ways to see exactly what your C++/CX code is doing “under the hood.”
Visual C++ component extensions (C++/CX) bring a whole new perspective to working in the long-established context of the Component Object Model (COM). One reason behind the design of C++/CX was to provide a quicker way to write COM objects in C++, with the intention of facilitating communication between processes and system run-time objects that might live in the kernel, other processes, or even other partitions on the system. As such, C++/CX manages to hide a large amount of COM programming rules and boilerplate under a much simpler programming paradigm.
However, although C++/CX makes life a lot simpler than COM (or even the Active Template Library [ATL]) ever did, that doesn’t mean you can’t still get tangled up in knots. It’s often necessary, particularly when you hit tricky edge cases, to take a closer look and figure out exactly what’s going on with your code.
Fortunately, the compiler contains a number of undocumented switches that make it possible for you to peer into the underlying system and gain insight into your code. This is particularly useful when dealing with memory leaks, such as those caused by cyclic references, references that have been unexpectedly retained beyond the intended lifetime of your object, and so on.
All of the following compiler switches are unofficial. This means that they might go away, stop working, or change their behavior whenever the compiler is updated. Don’t assume that they’ll still be around in any future versions of Visual Studio. Some of them (for example, /d1ZWinstr), are not yet released to the public and should be considered confidential. The easiest way to determine whether a particular switch has been made public is to check the VC++ Team Blog. (See the References section for information on accessing the blog.)
These switches were designed to give the Compiler team a simple way to diagnose and fix issues that they find in the compiler itself. Because they weren’t necessarily designed for external consumption, the switches are not necessarily as refined or as comprehensive as you might be used to. They are also completely unsupported and are not recommended as the “official” or “best” way to debug issues. In other words, use them at your own risk.
All of the switches should be applied through the Visual Studio Project Properties on the specific C++ file you want to apply them to. Applying them to an entire project will most likely be counterproductive except in special circumstances.
To apply the switches to your file, simply add them to the Additional Command-Line Options, as shown in the following screenshot.

The output for most of these switches will be emitted to the Build Output window during compile.
The remainder of this white paper is devoted to specific examples of how some of these undocumented switches work. Most of the examples use the following simple piece of test code for demonstration purposes:
ref class MyTestClass
{
private:
int m\_a;
public:
property int A {
int get()
{
return m\_a;
}
void set(int value)
{
m\_a = value;
}
}
int DoSomething()
{
return 4 + m\_a;
}
};
void TestFunction()
{
MyTestClass\^ myTestObject = ref new MyTestClass();
myTestObject-\>A = 1;
myTestObject-\>DoSomething();
}
The /d1ZWtokens command emits the code that the compiler generates for the translation unit (CPP file) it is applied to. The compiler-generated code is quite verbose, and it shows exactly what the C++ compiler that consumes the generated C++/CX code is actually doing.
Caution: Before running the /d1ZWtokens command, reduce the code in the translation unit that you’re inspecting to the absolute minimum it can be, including #included header files.
Everything that’s referenced by your CPP file will be turned into a code listing, and that listing is quite verbose. For instance, the code listing for the simple example shown above ended up being well over 15,000 lines. This is because of files that were included for the test harness’s precompiled header file when it was compiled. Another run that referenced only the code as shown yielded 4,974 lines of code. It’s not all actual code (a lot of it is blank lines), but a code listing of nearly 5,000 lines is still extremely verbose.
Most of the emitted code compiles down to inline function calls and/or very simple calls by the time the compiler’s done with it. In fact, some of it is elided entirely. Some of the code is run-time boilerplate code that is needed to perform operations like WeakReference handling, data marshalling, and building out the implementation specifics for the IUnknown and IInspectable interfaces on the class. You can find the source for a lot of the boilerplate run-time code in vccorlib.h.
Some of the generated code is required to support the C++/CX language itself—which definitely compiles down to a single copy—but still needs to be injected into the translated source file so that it is available to the C++ compiler, which consumes the C++/CX-generated code. Think of this second class of code as the equivalent of an included header file, except that it’s added automatically by the compiler whenever you enable C++/CX extensions using the /ZW compiler switch.
Yes, this also means that you might be able to recover a small amount of compile time by judiciously choosing on a file-by-file basis when to enable the language extensions in your code and when not to do so. However, be sure to measure the time it takes to compile a file before making this change. A file without the language extensions will need to compile only C++ code, without referencing any other C++/CX types, which may be more trouble than it’s worth.
You should also bear in mind that not every construct is translated by the /ZW switch. Some, such as the code in TestFunction, is not actually translated much at all. The reference-counting semantics are all handled by the compiler and the default implementation of the \^ operator. The result is that you won’t see the TestFunction code in the token output. The output is only for additional code that the compiler has to generate, not for expanding basic operations.
You can use either of the following two switches to emit the layout of ref classes in memory:
/d1reportAllClassLayout, which emits layout information for all classes that the compiler finds within the translation unit.
/d1reportSingleClassLayoutName, which emits layout information for a specifically named class. For example, with the code example shown in the preceding section, you might use /d1reportSingleClassLayoutMyTestClass.
The single-class switch is useful for more than C++/CX ref class types. You can apply it to any C, C++, or C++/CX type you want, and the compiler will emit a simple ASCII diagram of the class you’re emitting. For example, consider a file that contains only the following:
struct MyStruct
{
int a;
int b;
int c;
};
When this file is compiled with /d1reportSingleClassLayoutMyStruct set in the Additional Options, you will get the following output in the Build window:
1> class MyStruct size(12):
1> +---
1> 0 | a
1> 4 | b
1> 8 | c
1> +---
This switch can be very useful for diagnosing layout issues, such as padding and alignment, in your code. It is also useful for determining exactly how much space a struct or class will take up in memory.
Warning: Don’t try using /d1reportSingleClassLayout or /d1reportAllClassLayout to inspect a ref class that has been imported from a .winmd file. The layout information you will get is what the layout would be if you were implementing the ref class from your own code.
Because the ref class is from someone else’s code, however, the results will be wildly inaccurate. Internal members won’t be shown, and a virtual table pointer (VPTR) will be shown even though it doesn’t actually exist. (Platform code doesn’t necessarily include Platform::Object VPTRs, but using the switch will cause it to be shown). You should only trust these two switches on your own code that you’re compiling from source.
The /d1reportAllClassLayout switch is similar in behavior to the /d1reportSingleClassLayout switch, but it reports all of the types included in a given translation unit, including some that the compiler imports automatically. The /d1reportAllClassLayout switch suffers slightly from the same problem as the /d1ZWtokens switch—it returns everything. For this reason, be sure to scope down your header files and code as much as possible before you start using the command-line switch to analyze it.
More interesting is the layout information for ref classes. Running d1reportAllClassLayout on the MyTestClass class from the code example in the preceding section will result in the output shown below. The output lists all of the vtable entries, methods, COM interfaces, and base-class interfaces that the compiler automatically adds into the mix.
Note: In your output, you’ll find each line prefixed with the compiler instance #\ (for example, “1>”). These have been removed in this example for clarity.
class __IMyTestClassPublicNonVirtuals size(8):
+---
| +--- (base class Object)
0 | | {vfptr}
| +---
+---
__IMyTestClassPublicNonVirtuals::$vftable@:
| &__IMyTestClassPublicNonVirtuals_meta
| 0
0 | &__IMyTestClassPublicNonVirtuals::__abi_QueryInterface
1 | &__IMyTestClassPublicNonVirtuals::__abi_AddRef
2 | &__IMyTestClassPublicNonVirtuals::__abi_Release
3 | &__IMyTestClassPublicNonVirtuals::__abi_GetIids
4 | &__IMyTestClassPublicNonVirtuals::__abi_GetRuntimeClassName
5 | &__IMyTestClassPublicNonVirtuals::__abi_GetTrustLevel
__IMyTestClassPublicNonVirtuals::__abi_QueryInterface this
adjustor: 0
__IMyTestClassPublicNonVirtuals::__abi_AddRef this adjustor: 0
__IMyTestClassPublicNonVirtuals::__abi_Release this adjustor: 0
__IMyTestClassPublicNonVirtuals::__abi_GetIids this adjustor: 0
__IMyTestClassPublicNonVirtuals::__abi_GetRuntimeClassName this
adjustor: 0
__IMyTestClassPublicNonVirtuals::__abi_GetTrustLevel this adjustor:
0
class MyTestClass size(56):
+---
| +--- (base class __IMyTestClassPublicNonVirtuals)
| | +--- (base class Object)
0 | | | {vfptr}
| | +---
| +---
| +--- (base class Object)
8 | | {vfptr}
| +---
| +--- (base class IWeakReferenceSource)
| | +--- (base class __abi_IUnknown)
16 | | | {vfptr}
| | +---
| | +--- (base class Object)
24 | | | {vfptr}
| | +---
| +---
32 | m_a
| <alignment member> (size=4)
40 | __abi_FTMWeakRefData __abi_reference_count
+---
MyTestClass::$vftable@__IMyTestClassPublicNonVirtuals@:
| &MyTestClass_meta
| 0
0 | &MyTestClass::__abi_QueryInterface
1 | &MyTestClass::__abi_AddRef
2 | &MyTestClass::__abi_Release
3 | &MyTestClass::__abi_GetIids
4 | &MyTestClass::__abi_GetRuntimeClassName
5 | &MyTestClass::__abi_GetTrustLevel
MyTestClass::$vftable@Object@:
| -8
0 | &thunk: this-=8; goto MyTestClass::__abi_QueryInterface
1 | &thunk: this-=8; goto MyTestClass::__abi_AddRef
2 | &thunk: this-=8; goto MyTestClass::__abi_Release
3 | &thunk: this-=8; goto MyTestClass::__abi_GetIids
4 | &thunk: this-=8; goto MyTestClass::__abi_GetRuntimeClassName
5 | &thunk: this-=8; goto MyTestClass::__abi_GetTrustLevel
MyTestClass::$vftable@__abi_IUnknown@:
| -16
0 | &thunk: this-=16; goto MyTestClass::__abi_QueryInterface
1 | &thunk: this-=16; goto MyTestClass::__abi_AddRef
2 | &thunk: this-=16; goto MyTestClass::__abi_Release
3 | &thunk: this-=16; goto
MyTestClass::__abi_Platform_Details_IWeakReferenceSource____abi_GetWeakReference
4 | &thunk: this-=16; goto MyTestClass::GetWeakReference
MyTestClass::$vftable@Object@IWeakReferenceSource@:
| -24
0 | &thunk: this-=24; goto MyTestClass::__abi_QueryInterface
1 | &thunk: this-=24; goto MyTestClass::__abi_AddRef
2 | &thunk: this-=24; goto MyTestClass::__abi_Release
3 | &thunk: this-=24; goto MyTestClass::__abi_GetIids
4 | &thunk: this-=24; goto MyTestClass::__abi_GetRuntimeClassName
5 | &thunk: this-=24; goto MyTestClass::__abi_GetTrustLevel
MyTestClass::__abi_QueryInterface this adjustor: 0
MyTestClass::__abi_AddRef this adjustor: 0
MyTestClass::__abi_Release this adjustor: 0
MyTestClass::__abi_GetIids this adjustor: 0
MyTestClass::__abi_GetRuntimeClassName this adjustor: 0
MyTestClass::__abi_GetTrustLevel this adjustor: 0
MyTestClass::GetWeakReference this adjustor: 0
MyTestClass::__abi_Platform_Details_IWeakReferenceSource____abi_GetWeakReference
this adjustor: 0
The /d1ZWinst switch enables a whole host of extremely slow features that will add to your compile time considerably, so you’re going to want to enable these features on a case-by-case basis, possibly only on single, isolated classes. Furthermore, you will probably want to seriously consider staying with a single class per file when writing your own ref classes.
You may be wondering exactly how slow the /d1ZWinst switch really is. In truth, it entails a few extra indirections, a branch, and an increment/decrement each time it’s triggered. So extremely slow may be a bit of an overstatement, but the switch definitely has an impact on run-time performance.
The features enabled by /d1ZWinst include:
Tracking refcounts on a per-object basis (ideal for seeing whether you’re leaking object instances).
Tracking other functionality that is normally hidden behind the language extensions (such as QueryInterface calls).
There is also a little coding required to set up the instrumentation support functionality for use in your title.
The key data structure that tracks data regarding object utilization for your title is the __abi_WinClassInstrumentation struct, which you can find in vccorlib.h.
| Member name | Meaning |
|---|---|
| numcalls_QueryInterface | Count of times that QueryInterface has been called |
| numcalls_AddRef | Count of times that AddRef has been called |
| numcalls_Release | Count of times that Release has been called |
| numcalls_GetIids | Count of times that GetIids has been called |
| numcalls_GetRuntimeClassName | Count of times that GetRuntimeClassName has been called |
| numcalls_GetTrustLevel | Count of times that GetTrustLevel has been called |
| numcalls_Other | Number of calls on the object that have been made to the instance through any non-IInspectable method across an application binary interface (ABI) boundary |
| destructed | Non-zero if the object has been destructed, zero if it’s still active |
| refcount | Current refcount on the object instance |
Some of these aren’t as straightforward as they might seem. For example, if you’re working with your own ref class objects, a lot of QueryInterface calls can be optimized away into simple dynamic casts. The destructed member is an interesting one; it lets you see whether the object’s destructor has been called yet, regardless of its refcount.
The value of destructed will be non-zero if the refcount drops to 0 and the destructor of the object has been called as a result. However, if the destructor is called as a result of calling\ delete, or if the object was created on the stack and drops out of scope, then destructed will not be set.
Generally the value of destructed is the same as (refcount==0), but if the object happens to pass its instance out to something else that maintains ownership and increments the refcount within its destructor, destructed and refcount will not match—this should be considered an error condition.
The numcalls_Other member is used to count the number of calls made to your object instance using any non-IInspectable method over an ABI boundary. This is handy for checking such things as how many times the operating system is calling methods on an object you’ve passed to it through its public interface. Here is an example:
interface class IBall
{
void Func();
};
ref class Ball : IBall // Artificially introducing an interface to force
an ABI-boundary call
{
public:
virtual void Func() {}
internal:
void ShowStats()
{
Platform::Details::Console::WriteLine(
this-\>\_\_abi\_instrumentationData.numcalls\_Other.ToString() );
}
};
int main()
{
Ball ball;
IBall\^ iball = %ball;
iball-\>Func();
ball.ShowStats(); // prints 1
iball-\>Func();
ball.ShowStats(); // prints 2
ball.Func();
ball.Func();
ball.ShowStats(); // prints 2 (direct call via ball).
}
Another use of the numcalls_Other member is to verify in your own code that you’re calling methods on the most-derived concrete type of an object rather than calling them through the interface. The compiler can optimize away most of the overhead of the former, but it can’t optimize calls that go through the interface. In short, if you have a Ball that implements an IBall interface, you should call methods on the Ball version of the object—it’s faster.
To connect these elements to your object instance, create an instance of the __abi_WinClassInstrumentation class to contain the data for the object you want to track, and then call the __abi_SetInstrumentationData function on the object instance. Note that this function is only generated for you if you add the compiler switch, and it will not appear in Intellisense. For example:
\_\_abi\_WinClassInstrumentation g\_countersForMyObject;
// ...
MyTestClass\^ myObjectToTrack = ref new MyTestClass();
myObjectToTrack-\>\_\_abi\_SetInstrumentationData(
&g\_countersForMyObject );
Later, when you want to inspect the results, simply reference the member variables of g_countersForMyObject that you’re interested in.
Potential uses for the __abi_WinClassInstrumentation data include:
Verifying that the numcalls_AddRef and numcalls_Release call counts match or change as expected as you walk through your code, which will make it easier for you to find out where something grabbed a reference to your object if you didn’t expect it to.
Finding the absolute number of outstanding references on your object.
Verifying that your object still exists even if you don’t have a reference to it from your code anymore. As long as you have the __abi_WinClassInstrumentation class around, you can check without needing to hold a WeakReference to the object.
The Visual C++ and C++/CX team have built a number of tools designed to help ensure that they are producing a world-class, robust compiler. These tools, which are largely undocumented, are generally regarded as internal tools for debugging the compiler itself. However, now that you have an idea of how they work, you can add them to your collection of devices to help debug thorny edge cases and issues when you come across them in your own development.