.: Home :: Contact Us :.  
  



Hans Dietrich Software

free and licensed software

   

Visual Dumpbin image image image

Since I started working with .NET, I use dumpbin frequently, since some of my work involves integrating unmanaged C++ DLLs, most of which I do not have source code for. It is very tedious to find the file I want to dump, open a command prompt, run dumpbin, open the output file, and finally copy the information I want. For .lib files this is bad enough, but for .dll files it is even worse; .lib files contain undecorated function prototypes, but .dll files do not. I put together Visual Dumpbin to help with this.

The Visual Dumpbin Utility

After you select the file you want to dump, you see the exported functions with just one click:

screenshot

The right-click menu allows you to copy the dump output to the clipboard.

Visual Dumpbin Options

You can select the dumpbin options with the Options dialog. Tooltips display descriptions of what each option does:

screenshot

To use options which take additional parameters such as /RAWDATA or /SECTION, you can enter them in the Additional options field.

Undecorating Mangled Names

From MSDN: The Microsoft C++ compilers encode the names of symbols in C++ programs to include type information in the name. This is called "name decoration," or "name mangling." The purpose of this is to ensure type-safe linking. The C++ language allows function overloading where functions with the same name are only distinguished from one another by the data types of the arguments to the functions. Name decoration enables the linker to distinguish between different versions of overloaded functions because the names of the functions are encoded or decorated differently.

An example: the function prototype

  bool __cdecl func1(void)
is represented by the decorated name
  ?func1@@YA_NXZ
Why is this important? After all, in the first screenshot, we saw that the undecorated name is displayed next to the decorated name. Yes, this happens with .lib files, but with .dll files we see something different:

screenshot

If you have source code to the DLL, you can rebuild it with a module definition file, as I explain in my article Step by Step: Calling C++ DLLs from VC++ and VB - Part 2. This allows you to create DLLs with unmangled names.

Fortunately, Microsoft also provides UnDecorateSymbolName() in dbghelp.dll, which Visual Dumpbin uses to display the undecorated function prototypes:

screenshot

I should point out here that the technique used by Visual Dumpbin to undecorate mangled names may not work with DLLs produced by non-Microsoft compilers, since each compiler has its own algorithm for generating decorated names.

Generate Wrapper Class

So far, I have discussed how to use Visual Dumpbin to get undecorated names from dumpbin output. To take this one step further, I used code from the excellent article NativeWrapper to add the Generate Class button, which takes the undecorated prototypes and creates a C# DllImport wrapper class. For the eight functions shown in the previous screenshot, this is the class that is generated:
// Wrapper for TestDllAnsiAR.dll generated by Visual Dumpbin 3/23/2010 6:36:22 AM
// Full path: D:\CP Articles\VisualDumpbin\1.0\bin2008\TestDllAnsiAR.dll

using System;
using System.Text;
using System.Runtime.InteropServices;

public class TestDllAnsiAR
{
    private string datetime = "3/23/2010 6:36:22 AM";
    public string CreationDateTime
    {
        get { return datetime; }
    }

    // generated from ?func1@@YA_NXZ  (bool __cdecl func1(void))
    [DllImport("TestDllAnsiAR.dll", EntryPoint="func1", CallingConvention=CallingConvention.Cdecl)]
    public static extern bool func1();

    // generated from ?func2@@YA_NPAHH@Z  (bool __cdecl func2(int *,int))
    [DllImport("TestDllAnsiAR.dll", EntryPoint="func2", CallingConvention=CallingConvention.Cdecl)]
    public static extern bool func2(int[] var1,int var2);

    // generated from ?func3@@YA_NPBHH@Z  (bool __cdecl func3(int const *,int))
    [DllImport("TestDllAnsiAR.dll", EntryPoint="func3", CallingConvention=CallingConvention.Cdecl)]
    public static extern bool func3(int[] var1,int var2);

    // generated from ?func4@@YA_NPAD@Z  (bool __cdecl func4(char *))
    [DllImport("TestDllAnsiAR.dll", EntryPoint="func4", CallingConvention=CallingConvention.Cdecl)]
    public static extern bool func4(StringBuilder var1);

    // generated from ?func5@@YA_NPBD@Z  (bool __cdecl func5(char const *))
    [DllImport("TestDllAnsiAR.dll", EntryPoint="func5", CallingConvention=CallingConvention.Cdecl)]
    public static extern bool func5(String var1);

    // generated from ?func6@@YA_NPA_W@Z  (bool __cdecl func6(wchar_t *))
    [DllImport("TestDllAnsiAR.dll", EntryPoint="func6", CallingConvention=CallingConvention.Cdecl)]
    public static extern bool func6(StringBuilder var1);

    // generated from ?func7@@YA_NPAXPAH@Z  (bool __cdecl func7(void *,int *))
    [DllImport("TestDllAnsiAR.dll", EntryPoint="func7", CallingConvention=CallingConvention.Cdecl)]
    public static extern bool func7(IntPtr var1,int[] var2);

    // generated from ?func8@@YA_NPAUHWND__@@PAEH@Z  (bool __cdecl func8(struct HWND__ *,unsigned char *,int))
    [DllImport("TestDllAnsiAR.dll", EntryPoint="func8", CallingConvention=CallingConvention.Cdecl)]
    public static extern bool func8(IntPtr var1,byte[] var2,int var3);
}

It is possible that you will want to tweak the generated class. Here are some typical things to modify:

  • CharSet Field - Indicates how to marshal string parameters to the method.
  • SetLastError Field - Indicates whether the callee calls the SetLastError() Win32 API function.
  • UnmanagedType Enumeration - Identifies how to marshal parameters or fields to unmanaged code. For example, you could write this:
        [DllImport("...")]
        static extern int MyFunction([MarshalAs(UnmanagedType.LPStr)] string s);

    This tells the marshaler to translate to LPStr, which is null-terminated, single-byte ANSI.

Some Alternative Tools

I have written about Visual Dumpbin as if it was developed quickly and logically, but that was far from how I came to write it. Along the way, I found some other tools which I investigated, but in the end none of them did what I was looking for. You might want to take a look at them to see if they are a better match for your needs.
  • PInvoke Interop Assistant

    At first I was very hopeful about this free tool. It's a command-line tool with a GUI interface:

    screenshot

    SigExp converts managed signature to an unmanaged signature. OK, not what I want to do.

    SigImp Search allows users to choose the managed code language in which they want code generated and then select a native type, procedure, or constant to perform the generation from. Great! This was more like it!

    screenshot

    Oops. Spoke too soon. You can't enter a path to your DLL, and even if you could, you can choose only one function at a time.

    SigImp Translate Snippet allows users to write their own native code snippet in the tool. The tool will then generate and display the managed code equivalent in the main window.

    screenshot

    Again, not what I was looking for. I don't have the patience to enter individual snippets into the GUI, although it might be good to verify a DllImport you're not sure of.

  • PInvoker

    My next stop was the PInvoker tool, the only commercial tool ($USD149.95) I looked at.

    screenshot

    There was just one slight problem. PInvoker produced a DLL, not the list of DllImport statements I wanted. According to the PInvoker FAQ, P/Invoker .NET produces a .NET assembly interface dll allowing .NET applications to get/set exported variable values and call exported methods on the specified C++ static dlls. This might be OK for some situations, but I wanted something less opaque, that I could tweak if I had to.

    Update: There is now a PInvoker Addin for VS VS2005, VS2008 and VS2010; it sells for $USD99.95. According to the vendor's site, "PInvoker Visual Studio Addin imports C++ header files (even the windows SDK header files) together with their associated dlls and generates C#/VB.NET pinvoke definitions."
  • MSDN

    MSDN gave me the following advice: Wrapping a frequently used DLL function in a managed class is an effective approach to encapsulate platform functionality. Oh, OK. Thanks.

  • NativeWrapper: a tool for Native Interoperability

    This article was close to what I wanted. It showed how to take a whole DLL or lib file and extract all the exported functions. It also produced a complete project for a managed DLL that called the unmanaged DLL, which was not something I needed.

Visual Dumpbin Projects

In addition to the Visual Dumpbin project, the download includes three other projects that create test DLLs which you can use to experiment with Visual Dumpbin:

screenshot

TestDllAnsi and TestDllUnicode create DLLs using the standard __declspec(dllexport) mechanism for exporting DLL functions; TestDllAnsiDef creates a DLL using a module definition (.def) file. For more information on module definition files, see my article Step by Step: Calling C++ DLLs from VC++ and VB - Part 2.

A Problem Running Dumpbin

If you do a web search for dumpbin, you will find posts complaining that an error occurs when running dumpbin: This application has failed to start because mspdb80.dll was not found... The problem is that mspdb80.dll is not installed in System32 when Visual Studio® is installed, but rather in Common7\IDE.

Some web sites suggest copying the missing DLL to the VC\bin directory (where dumpbin is located), or even to System32. This is a very bad idea, because you may end up with an orphan, out-of-date DLL if you later install a Visual Studio® service pack. If you get the above error, a better solution would be to copy dumpbin.exe to the Visual Studio® Common7\IDE directory, which is where mspdb80.dll is located (or mspdb100.dll for VS2010). You may also have to copy VC\bin\link.exe to the Common7\IDE directory.

Revision History

Version 1.1

  • Added VS2010 projects

Version 1.0

  • Initial public release

Free download