Managed Debugging Assistants (MDA’s)


When I read through the responses for the questionnaire below I saw that many users were not aware of MDA’s and that drove the topic for this post. I had written a small sample for a simple MDA which I thought that I will share with everyone.


 


MDA’s can help you diagnose problems that you might not know about normally. These are like advanced diagnostic messages that tell you what is going wrong in your application. There are many ways to turn MDA’s on and off. Let us look in to them here.


 


Consider the following source code (sample.cs):


 


using System;


using System.Diagnostics;


using System.Runtime.InteropServices;


public class Program {


    public static void Main() {


        Beep(5,5);


    }


    [DllImport(“kernel32.dll”, SetLastError=true)]


    [return: MarshalAs(UnmanagedType.Bool)]


    internal static extern bool Beep(long frequency, long duration);


}


 


Let us compile this code and execute it :- csc sample.cs /debug


 


This runs without any errors. If you enable MDA’s then it will let you know that the marshalling for Beep is wrong as it takes two DROWD and hence the parameter should be “int” instead of “long”. How do you catch this error is the question? MDA’s come in handy for this. Here is how you would do it with MDA’s.


 


Step-1: Turning on MDA’s


There is a global registry key which is used to turn on MDA’s.


 


Windows Registry Editor Version 5.00


[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework]


“MDA”=”1”


 


Step – 2: Selecting individual MDA’s as required:


Now you can select individual MDA’s that you want in three different ways as mentioned below


 


1.      Through an exe.mda.config file


2.      Through environment variable


3.      Through Exceptions in Visual Studio


 


1.      Enabling MDA’s through sample.exe.mda.config file


Let us produce sample.exe.mda.config file as below:


 


<mdaConfig>


  <assistants>


    <pInvokeStackImbalance enable=true/>


  </assistants>


</mdaConfig>


 


This enables the pInvokeStackImbalance MDA which will fire off when it finds irregularities in marshalling.


 


2.      Enabling MDA’s through environment variables


Set the environment variable COMPLUS_MDA as mentioned below.


 


COMPLUS_MDA= pInvokeStackImbalance


 


3.      Enabling MDA’s from Visual Studio


You can enable MDA’s from Visual Studio by going to Debug-Exceptions-Managing Debugging Assistants and selecting the MDA’s that are of interest to you.


 


Let us enable the pInvokeStackImbalance MDA using the sample.exe.mda.config option and run the above executable again. This time you get an error message as follows:


 


Managed Debugging Assistant ‘PInvokeStackImbalance’ has detected a problem in sample.exe.


Additional Information: A call to PInvoke function ‘sample!Program::Beep’ has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature


 


This is pretty good information that you can use to correct the signature of the pInvoke from long, long to int,int and re run the code. This time the MDA does not fire up. Your marshalling should be correct then! There is good information about MDA’s at the following locations and I recommend everyone to read them.


 


The msdn article at MDA walks through the same example that I have here with excellent details. I strongly urge reading through that. I read it and it is extremely useful.


 


Other references are:


http://blogs.msdn.com/jmstall/archive/2005/11/10/introducing-mdas.aspx


http://msdn2.microsoft.com/en-us/library/d21c150d.aspx


 


 


 


Comments (10)

  1. SteveC says:

    That is great stuff! For those of us doing WinForms and/or Interop, MDAs look like "just what the doctor ordered". Thanks for making this kind of information more widely known.

  2. Thottam Sriram says:

    I am glad this was useful. It will be nice to know your experience after your tunred on MDA’s in your application and if it was helpful in any form.

  3. Tao Wang says:

    It provides very useful information. Thanks for doing this.

  4. Thottam Sriram says:

    Thanks Tao. I am glad this was useful.

  5. Great – very usefull – very interesting info but it still doesn’t work.

    1. MDA is switched off by Debug-options

    very well no brake anymore

    BUT

    (sample from Microsoft)

    Private Declare Function GetVolumeInformation _

     Lib "kernel32" Alias "GetVolumeInformationA" ( _

     ByVal RootPathName As String, _

     ByVal VolumeNameBuffer As String, _

     ByVal VolumeNameSize As Long, _

     ByRef VolumeSerialNumber As Long, _

     ByRef MaximumComponentLength As Long, _

     ByRef FileSystemFlags As Long, _

     ByVal FileSystemNameBuffer As String, _

     ByVal FileSystemNameSize As Long _

     ) As Long

    ‘ — Sourcecode

    Private Function GetSerialNumber(ByVal Drive As String) As Long

    ‘ Liefert die Seriennummer eines Datenträgers zurück, dessen

    ‘ Laufwerksbuchstabe übergeben wird. Auch die Übergabe einer

    ‘ vollständigen Pfadangabe zu einem Verzeichnis oder einer Datei

    ‘ auf dem Datenträger ist möglich. Bitte beachten Sie, dass eine

    ‘ Seriennummer unter VB als negative Zahl erscheinen kann, da der

    ‘ Datentyp Long vorzeichenbehaftet ist. Wählen Sie für eine Dar-

    ‘ stellung der Seriennummer eine Darstellung als Hexadezimalzahl.

    Dim lDummy As Long

     ‘ Hauptverzeichnis-Angabe aus dem übergebenen Parameter erstellen

     If Len(Drive)>0 Then ‘small modification here

       If Left$(Drive, 2) <> "\" Then

         Drive = Left$(LTrim$(Drive), 1) & ":"

       End If

     End If

     ‘ Die Seriennummer des Datenträgers in diesem Laufwerk ermitteln

     GetVolumeInformation Drive, vbNullString, _

                          0, GetSerialNumber, _

                          lDummy, lDummy, _

                          vbNullString, 0

    End Function

    Private Function GetSerialNumberString(ByVal Drive As String) As String

    ‘ Liefert die hexadezimale Darstellung  der Seriennummer eines Datenträgers

    ‘ zurück, dessen Laufwerksbuchstabe übergeben wird. Auch die Übergabe einer

    ‘ vollständigen Pfadangabe zu einem Verzeichnis oder einer Datei

    ‘ auf dem Datenträger ist möglich.

     GetSerialNumberString = Hex$(GetSerialNumber(Drive))

    End Function

    Delivers at anytime &H0

    may be the MDA is right ? is there a problem

    to get in touch with the kernel32.dll ???

    Can You help ?

    Thanks in advance

    tb@optimal-process.de

  6. dmilirud says:

    Try using the following signature for GetVolumeInformation

    Imports System.Runtime.InteropServices

    Public Declare Function GetVolumeInformation _

       Lib "kernel32" Alias "GetVolumeInformationA" ( _

       <MarshalAsAttribute(UnmanagedType.LPStr)> ByVal lpRootPathName As String, _

       ByVal lpVolumeNameBuffer As System.IntPtr, _

       ByVal nVolumeNameSize As UInteger, _

       ByRef lpVolumeSerialNumber As UInteger, _

       ByRef lpMaximumComponentLength As UInteger, _

       ByRef lpFileSystemFlags As UInteger, _

       ByVal lpFileSystemNameBuffer As System.IntPtr, _

       ByVal nFileSystemNameSize As UInteger _

       ) As <MarshalAsAttribute(UnmanagedType.Bool)> Boolean

  7. dmilirud says:

    Actually even better is to use StringBuilder for the 2nd and 7th parameters:

     Private Declare Function GetVolumeInformation _

       Lib "kernel32" Alias "GetVolumeInformationA" ( _

       <MarshalAsAttribute(UnmanagedType.LPStr)> ByVal lpRootPathName As String, _

       ByVal lpVolumeNameBuffer As StringBuilder, _

       ByVal nVolumeNameSize As UInteger, _

       ByRef lpVolumeSerialNumber As UInteger, _

       ByRef lpMaximumComponentLength As UInteger, _

       ByRef lpFileSystemFlags As UInteger, _

       ByVal lpFileSystemNameBuffer As StringBuilder, _

       ByVal nFileSystemNameSize As UInteger _

       ) As <MarshalAsAttribute(UnmanagedType.Bool)> Boolean

  8. balabo_ak says:

    <a href= http://index7.riesxd.com >intetin</a> <a href= http://index3.riesxd.com >t mobil cell phones plans</a> <a href= http://index4.riesxd.com >mfc42.dll islinkedto missing export kernel32.dll</a> <a href= http://index2.riesxd.com >deastisdesigns</a> <a href= http://index8.riesxd.com >triamcindlone cream</a>

  9. Ashok Kumar says:

    It is really helpful. I was trying how to turn off pInvokeStackImbalance but could not get the answer.

    Thanks

Skip to main content