Visual Dumpbin
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:
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:
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_NXZWhy 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:
Fortunately, Microsoft also provides UnDecorateSymbolName() in dbghelp.dll, which Visual Dumpbin uses to display the undecorated function prototypes:
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:
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!
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.
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
DllImportyou're not sure of. -
PInvoker
My next stop was the PInvoker tool, the only commercial tool ($USD149.95) I looked at.
There was just one slight problem. PInvoker produced a DLL, not the list of
DllImportstatements 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:
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