The Modules window in VS.

When I debug a problem on someone else's machine the first thing I do is look at the modules window.  Sorting by Version and seeing the one dll that just doesn't belong can help instantly diagnose a configuration problem, and save much debugging agony.  I am writing this while looking at the C++ 2005 Express edition beta. Most of the columns are relatively obvious but I'll try to be thorough here.

Name: This is the short name of the PE (Portable Executable .. dll, exe, ocx).  'PE format' is a good phrase to drop into google when you want to understand what's inside a dll.

Path: Where the PE lives on the file system.  This is useful when you want to find the correct PE to start interrogating with command line tools.

Optimized:  This is for managed code.   It tells you whether the JIT compiler used optimization when going from MSIL to the target platforms native instruction set.

User Code: User Code is a Managed code feature added for Whidbey.  It is also termed 'just my code' in debugger options.  If you have Just My Code turned on and the dll is optimized or has no symbols we will treat it as "non-user" code.  This means all frames in the callstack window will be collapsed behind a [non-user code] frame.  This feature is off by default for C++, and on for VB and C# user profiles.  You can switch it under Tools/options/Debugging/Enable Just My Code.  The full ramifications of 'JMC' are much larger than simply hiding callstack frames.  It includes stepping through non-user code all the way to where your code starts running (and doing so quickly).  Mike Stall has blogged about some of this.

Symbol Status: This tells you if Symbols are loaded.  It can also tell you if they are stripped (really only a native dll issue), or if devenv just loaded exports. If you are doing crash dump debugging it can also tell if the binary has been found.  Right click for a context menu and you can load symbols, jump to the "Symbol Settings ..." dialog, and also see where we searched for symbols.

Symbol File: Where the pdb file was located.  The context menu item "Symbol Load Information..." can tell you where the debugger looked to find symbols.

Order: When the dll was loaded.

Version:  The version information for the dll.  This is very useful for grouping together related components, and will often show you when someone has a bad version #.  Check out the amount of info we keep in a visual studio version string.  The string has enough information to tell the specific build lab (or developer) that built the bits.

Timestamp: This is the real deal - the internal timestamp when the linker (or .Net compiler) gave birth and sent the PE out into the world.

check this out:
C:\Program Files\Internet Explorer>dir iexplore.exe
 Volume in drive C has no label.
 Volume Serial Number is 2CAB-3E87

 Directory of C:\Program Files\Internet Explorer

08/04/2004  05:00 AM            93,184 IEXPLORE.EXE

That's the filesystem timestamp ... nice if you want to know when it landed on your Hard Drive.  Not as useful for figuring out it was built 2 days later than all the related components in the process.

C:\Program Files\Internet Explorer>dumpbin /headers IEXPLORE.EXE | findstr time
        41107B81 time date stamp Tue Aug 03 23:00:33 2004

This is what you really want.  Well ... it's what I really want.  And it's what you get in this column.  In versions of VS before Whidbey the timestamp for managed code was the less useful filesystem timestamp.

Address:  The load address range for the PE in the Process' memory.  Back on the far left is an untitled column of icons. If the icon looks like a little page this address is the prefered load address.  If it has a page with a small red exclamation point this PE was relocated at load time.  If you own that PE, find it a place all it's own, it could be loading faster. Check out Matt Pietrek's MSDN article for getting faster load times.

Process:  [Process Id] Process Name: one of (Native or Managed).  Note if you are doing mixed mode debugging then many dlls will actually have rows in the modules window.  One for the 'Native' dll load ... everything gets to be native at some level.  And one for the managed dll load.  You can tell they are the same dll because the address ranges will match.  Base names may not match because sometimes NGen'd dlls show up with a 'ni' extension added in to the name. (Such as

You can change the order of the columns in the modules window by clicking and dragging them. The columns also resize by draging the borders.  Another neat trick is setting the window to be a tabbed document via the context menu on the title bar.  You can do this with just about any window in devenv.  I rarely need to be looking at code while examining the modules window and since I optimize for maximum screen real estate for code, this trick gives me a nice expansive view for the modules window. 

Since I mentioned the symbols settings, let me also mention the public symbol server. You can go to the Symbol Settings dialog, and add as one of the locations to search for symbols.  If you do this, fill out the "Cache symbols from Symbols servers" line so that it doesn't hit the network to pull down public symbols each time.  This step will ensure that you get better native callstacks.  Without those symbols callstack walkers have a tough time crossing modules that use Frame Pointer Omission.

If you have questions or find an error in this, please let me know.

Skip to main content