As promised, here's my first entry with more details about Customer Debug Probes and CLR SPY.
The Marshaling probe is the easiest one to understand and great for experimentation since it's the only one that doesn't report on error/warning conditions. It also fits best into the spy theme since it non-intrusively reports on work that is regularly done by just about any managed application. In today's world, you'll be hard-pressed to find a managed application that doesn't marshal parameters to unmanaged code - especially if you count the .NET Framework APIs used by the application.
The Marshaling probe logs how parameters and return types get marshaled from managed to unmanaged code. (The probe doesn't tell you about marshaling in the opposite direction, nor does it tell you about fields as they are marshaled.) For a "Hello, World" C# application:
public class HelloWorld
{
public static void Main()
System.Console.WriteLine("Hello, World!");
}
I get the following output from CLR SPY (without the date, time, and probe prefix so it's easier to see):
Marshaling from IntPtr to DWORD in method GetStdHandle.
Marshaling from Int32 to DWORD in method GetStdHandle.
Marshaling from Int32 to DWORD in method GetFileType.
Marshaling from IntPtr to DWORD in method GetFileType.
Marshaling from Int32 to DWORD in method WriteFile.
Marshaling from IntPtr to DWORD in method WriteFile.
Marshaling from Byte* to DWORD in method WriteFile.
This happens because Console.WriteLine internally makes PInvoke calls to the Win32 GetStdHandle, GetFileType, and WriteFile APIs.
The steps to do this yourself are:
Look what happens if I use CLR SPY on an equivalent managed C++ "Hello, World" application:
Marshaling from UInt32 to DWORD in method _mainCRTStartup.
This highlights a difference between the C++-generated code, which has special entry point logic, and the C#-generated code.
There are two things to be aware of when analyzing Marshaling probe messages. For any method:
When parameters are user-defined types, they are qualified with their namespace. However, the methods whose parameters are being marshaled are never displayed with their namespace or even class name, which can make examining the output a little tedious.
If you're using the Marshaling probe to debug problems in your own code, you probably want to suppress messages for marshaling done by the .NET Framework. This is possible using the "Marshaling Filter" pane in CLR SPY. When you click the Edit button, you can type a semicolon-delimited expression list in the text box that states the items for which you want to see messages. The string you assign as the filter can be a semicolon-delimited expression list (with no spaces inbetween). Here are the rules for each expression:
For the C++ "Hello, World" example, a filter of GetStdHandle;GetFileType;WriteFile would show all messages except the _mainCRTStartup one. A filter of System.IO would only show the WriteFile messages (since that's the namespace containing the private PInvoke signature), and a filter of Microsoft.Win32.Win32Native would only show the GetStdHandle and GetFileType messages.