Click here to Skip to main content
Click here to Skip to main content

Include File Hierarchy Viewer

By , 29 Jul 2003
 

Introduction

I've seen many people ask about utilities to view the tree of #included files in their source code. I think I've seen one of these before, either here at CodeProject or maybe at CodeGuru, but I can't seem to find it. Since I really enjoy text processing, I took it upon myself to write my own. What I've come up with is a fast, multi-threaded #include tree generator.

Features

Searching multiple directories

As you can see in the screenshot above, there are a few fields to fill in before you can generate the tree. I think it's pretty self-explanatory, but I will explain the fields here just in case some think it's not.

  • Search in

    Type in a list of directories you want to search. You can enter multiple directories at one time by separating them with semi-colons. Or, optionally, use the browse button ("...") to pick a directory from the standard Shell Browser. This combo box will store the recently searched directories, so you can also select a directory from the drop-down list if you like.

  • File mask

    Type in a list of file masks you want to search for. You can enter multiple file masks at one time by separating them with semi-colons. This combo box will store the recently used file masks, so you can also select a mask from the drop-down list if you like.

  • Includes

    Type in a list of directories where external header files reside. You can enter multiple include directories at one time by separating them with semicolons. Also, it's possible to enter an environment variable in this field, which the software will expand at runtime. To do this, simply prefix the variable with a '%' character (i.e. %INCLUDE).

  • Recurse subdirectories

    Set this check box if you want the program to recurse through subdirectories of the directories you entered.

Searching files loaded from VC6/VC7 workspaces or projects

When searching a workspace or project, you don't have to input as much information as when searching a directory, but you still have to load a project or workspace, specify a file mask, and select a configuration. The software will read settings related to preprocessing, such as additional include directories, and preprocessor definitions. Also, the VC6 project reader will read the registry for the VC6 include directories, and the VC7 project reader will read the registry for the VC7 include directories, which means if you have VC6 or VC7 configured already, you don't have to configure this program as well.

Note: The workspace and project loading isn't perfect yet, but I have tested it in a variety of scenarios, and it works well for me. The biggest problem is accurately interpreting the project settings, which there are still issues with.

  • Workspace

    Type in the path to the workspace or project you want to load. Or, optionally, use the browse button ("...") to pick a workspace from the standard File Open dialog box. This combo box will store the recently searched workspaces, so you can also select a recent entry from the drop-down list if you like.

  • Load workspace

    Click this button to load the selected workspace or project, so you can select a configuration. If you don't load the workspace before you click Start, the Include Finder will use the first configuration found in each project.

  • File mask

    Type in a list of file masks you want to search for. You can enter multiple file masks at one time by separating them with semi-colons. This combo box will store the recently used file masks, so you can also select a mask from the drop-down list if you like.

  • Configuration

    Select a project configuration. The configuration you select will determine which preprocessor include directories are used, and also which preprocessor definitions are used.

Other options

  • Parse preprocessor macros

    There is now the capability to parse the preprocessor macros, and this flag is used to turn that feature on and off. Since the parsing may not be 100% accurate (with respect to the compiler), I leave this as a choice to you.

Once you've entered some valid data, click Start and the program will start the search. The searching is done in a separate thread, so you will see the button's text turn to "Stop" once you click Start. To stop the search, simply click Stop and the thread will quit, turning the Stop button back into the Start button.

Viewing and searching the output

The output is shown in a standard Win32 tree control, using MFC's CTreeCtrl. As each source file is completed, the program populates the tree with the source file and all the files #included by it. You will notice that there are a few icons used in the tree that denote properties of the item. Here's an explanation of them:

This icon is used to denote a regular file.

This icon is used to denote that the instance of the file is not the first time it was included by the current source file (either directly or indirectly).

This icon is used to denote that the file could not be found along the specified include paths.

This icon is used to denote that the file has been recursively included.

To search the tree for a particular file, select the Find... menu item, or click F3 to search for the next occurrence of a string.

Saving and restoring the data

If you click on the Save toolbar icon, or select the Save Results... menu item, you will be prompted to enter a file name to save to. The results are saved in XML format like the sample shown below.

Sample XML output (viewed with IE)

Once you have saved an XML file, you can click the Open toolbar icon, or select the Open... menu item to select a file to reload. The XML tree will be reloaded into the Include Finder.

About the code

Note: At my work we have a coding standard which is a form of Hungarian notation. I've also used this standard in this project. It's what I've been using for the past few years, and I like it, but that's not the point of the article or the code, so please don't flame me for it.

I've tried to keep the core code of the program as separated from the interface as possible, so that it will be easy for someone to reuse the interesting portions. Since the code has grown substantially in size since the first version, I decided to omit descriptions of the classes. If you are interested in using the code, you can find a description of what's in each file in the headers at the top of them.

Acknowledgements

I'd like to thank the following people:

To Do

  • It would be neat to make a static library out of the core, thereby making it possible to use the core in a Developer Studio add-in, as well as the external tool that it currently is.
  • The preprocessor macro handling could be better.
  • Interpreting the project settings could also be better.
  • I've tried to write the code cleanly, but I'm sure it could still use some clean-up.
  • Documentation for those who would like to use the code?

History

  1. January 7th, 2003 - Initial release.
  2. January 27th, 2003
    • Added the capability to read .dsp/.dsw/.vcproj/.sln files.
    • Added an option to parse preprocessor macros.
    • Added the capability to search multiple directories at once.
    • Added an option to show only files which couldn't be found.
    • Added support for entering environment variables in the Includes field.
    • Added the capability to load a saved XML file from disk.
    • Added the capability to select a custom program for viewing source files.
    • Added the capability to double-click a leaf node in the tree to open the file.
    • Added the capability to search the tree for specified strings.
    • Added CMMFStream class, which improved parsing performance greatly.
  3. February 24th, 2003 (bug fixes) - Thanks to Medved, Oliver Wahl, and Andreas Saurwin for alerting me to, and/or showing patches for these bugs.
    • CMMFStream would incorrectly handle files with zero length.
    • CParser::FindFullPath had a bug which made it find the incorrect file in certain cases.
    • CLexer incorrectly handled certain characters that could be found in binary files.
    • CLexer incorrectly handled files which had a strange combination of \r\n, which caused a crash.
  4. July 30th, 2003 (bug fixes and some changes to run on NT 4 without IE shell update)
    • Fixed a bug where FindFullPath would incorrectly handle two files with the same name but in different paths. - Thanks to Oliver Wahl.
    • Fixed a bug where bracketed include directories from project settings weren't read. - Thanks to EvanKeats.
    • Removed the use of SHGetSpecialFolderPath and replaced it with SHGetSpecialFolderLocation/SHGetPathFromIDList. - Thanks to brownfox and Hemal Shah.

Disclaimer and copyright

Although great care has gone into developing this software, it is provided without any guarantee of reliability, accuracy of information, or correctness of operation. I am not responsible for any damages that may occur as a result of using this software. Use this software entirely at your own risk. Copyright 2003, Chris Richardson.

Final notes

Any feedback or bug reports will be greatly appreciated. If you do or do not like the article, the code, or the program I've provided, please tell me why.

Thanks for taking the time to read my article. I hope you enjoyed it, and I hope you find the Include Finder useful.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Chris Richardson
Software Developer (Senior)
United States United States
Member
I like to program, I like to sail.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralApparently abandoned by authormemberVaclav_Sal3 Apr '10 - 15:36 
Anybody interested in fixing the bugs?
Like to use it to fix Windows inability to copy files with long names.
But it will build them!!
Cannot make it stay on line, crashes every time.
Vaclav
Questionlittle bug? What is the intention?memberpeterchen11 Nov '06 - 12:42 
      case CDSSetting::SETTING_UNDEFINE:
      {
         // Remove the definition.
         for( int i = 0; i<p_roDefines.size(); ++i )
         {
            if( !p_roDefines[i].compare( a_pszText ) )
            {
               p_roDefines.erase( &p_roDefines[i] );
               break;
            }
         }
         break;
      }
You are erasing from the vector you are iterating through - in the case of erase, i would be still be incremented, and you would miss one element behind the deleted one. Is this intended?
 
(Also, it doesn't compile on VC8, but this can be fixed Wink | ;) )
 


Developers, Developers, Developers, Developers, Developers, Developers, Velopers, Develprs, Developers!
We are a big screwed up dysfunctional psychotic happy family - some more screwed up, others more happy, but everybody's psychotic joint venture definition of CP
Linkify!|Fold With Us!

AnswerRe: little bug? What is the intention?memberChris Richardson11 Nov '06 - 12:47 
Ah yes, I guess I hadn't thought about the case where a setting appeared more than once in the list. Thanks for the information. And please ignore my [mis]use of STL in this program Wink | ;)
 
peterchen wrote:
(Also, it doesn't compile on VC8, but this can be fixed )

 
Unfortunately for me I only have VC6 and VC7. I'm unsure when I will be upgrading to VC8, but I am not surprised it doesn't compile Wink | ;) .
 
Thanks,
 
Chris Richardson

GeneralRe: little bug? What is the intention?memberpeterchen11 Nov '06 - 13:06 
With a few fixes it does Smile | :)
 
(1) two instances where the return value of _tcschr is assigned to TCHAR pointer (must be TCHAR const *)
(2) two for's that break due to the now standard-compliant scope rules
(3) above line (the vector iterators are no longer pointers) but this fixes both problems:
 
if( !p_roDefines[i].compare( a_pszText ) )
{
  p_roDefines.erase( p_roDefines.begin() + i ); 
  break;
}
 
[edit]just noticed: the loop counter is no problem, since you break immediately after deleting D'Oh! | :doh: [/edit]
 
I'm currently poking around in the code base to see if I can improve/add a few things.
 

 


Developers, Developers, Developers, Developers, Developers, Developers, Velopers, Develprs, Developers!
We are a big screwed up dysfunctional psychotic happy family - some more screwed up, others more happy, but everybody's psychotic joint venture definition of CP
Linkify!|Fold With Us!

GeneralRe: little bug? What is the intention?memberChris Richardson11 Nov '06 - 13:14 
I appreciate the help, thanks again. I hadn't noticed the break statement either. Blush | :O
 
If you are interested in the code base, I could talk to Chris M. about making you a co-author so you could upload your changes. Otherwise if you'd like to send them to me I will make sure to attribute the fixes to you, in the article and code.
 
Like I said before though, the code is pretty rough, and it has been a few years since I've had time to work on it.
 
Do you mind if I ask what you are thinking about adding? Only out of curiousity; you are of course welcome to do whatever you'd like with the code. Smile | :)
 
Thanks,

 
Chris Richardson

GeneralRe: little bug? What is the intention?memberpeterchen11 Nov '06 - 13:31 
Chris Richardson wrote:
If you are interested in the code base, I could talk to Chris M. about making you a co-author so you could upload your changes

 
I was going to suggest that if I get anything useful done Blush | :O I think that's better than a separate article.
 
I am thinking of the following:
 
Finding include paths (how come a.cpp depends from b.h?)
 
Reverting the tree, i.e. starting at a file and seeing into which files it goes)
 
Some better control over the include directories, like not scanning PDSK headers (and it looks like VC8 include directories need to be supported, too)
 
better command line support (so it can be added to Extras/Tools conveniently)
 
VC6 also has a problem accessing the headers during a build while you are scanning - it looks like you are doing everything right (_tfopen opens with "share deny none" at least wit hthe VC8 runtime, so this might be a VC6 problem)
 
Other things I am now thinking of: some metrics (how "hot" is a file, lines of code), using a checkbox to enable/disable (comment/uncomment) #include statements, so one can go looking for unused ones, stripping a base folder from paths (if they are local to it) ....
 
But these are just ideas, I am currently just checking if I can get along with the code base and I don't know how much time and energy I can put into it.
 
Anyway, it's a great tool!
 


Developers, Developers, Developers, Developers, Developers, Developers, Velopers, Develprs, Developers!
We are a big screwed up dysfunctional psychotic happy family - some more screwed up, others more happy, but everybody's psychotic joint venture definition of CP
Linkify!|Fold With Us!

NewsVisual Studio AddinmemberMatt Godbolt20 Sep '06 - 4:25 
The company I work for has a Visual Studio Addin that shows include graphs inside Visual Studio itself. They update automatically as you type and are very configurable. See my sig for more details. It's commercial but cheap, and with a 14-day free trial Smile | :)
 
Matt Godbolt
IncludeManager - #include graph viewer
StyleManager - a C/C++ source code reformatter

GeneralRe: Visual Studio Addin [modified]memberpeterchen11 Nov '06 - 12:28 
..and your message board currently isn't working Wink | ;)
 
submitting an e-mail gives the following error message:
 
Failed sending email :: PHP ::
 
DEBUG MODE
 
Line : 234
File : emailer.php

 

 
-- modified at 19:45 Saturday 11th November, 2006
 


Developers, Developers, Developers, Developers, Developers, Developers, Velopers, Develprs, Developers!
We are a big screwed up dysfunctional psychotic happy family - some more screwed up, others more happy, but everybody's psychotic joint venture definition of CP
Linkify!|Fold With Us!

GeneralRe: Visual Studio AddinmemberMember 49072430 Aug '08 - 12:25 
Another solution: a free add in to show include graphs inside or outside the Visual Studio:
http://www.mobile-mir.com/cpp/index.php[^]
Generalfix/enhancementmemberBillTT28 Jul '06 - 4:07 
I recently made a fix and added an enhancement to IncludeFinder that I wanted to share.
 
The fix has to do with the search order of include directories -- "standard" include directories should be searched last, not first, the latest version has this backwards. This only matters if you're including a file with the same name as one of the "standard" include files, in which case the wrong file gets picked up. (In my case, it was IMessage.h).
 
The enhancement supports the use of environment variables to specify include directories in project files. Visual Studio supports this, but IncludeFinder does not without the attached patch.
 
Diff output for two affected files is listed following:
 
FILE COMPARISON
Produced: 7/28/2006 9:52:10 AM
 
Left base folder: K:\IncludeFinder
Right base folder: K:\IncludeFinderOrig
 
File: VC6Objects.cpp
116c116
< if( p_pszOpt )
---
> if( *p_pszOpt )
118,133c117,118
< // check for and expand env vars in include settings
< if ( (p_eType == CDSSetting::SETTING_INCLUDE) && ((_tcsncmp(p_pszOpt, "($", 2) == 0) || (_tcsncmp(p_pszOpt, "$(", 2) == 0) ) ) {
< TCHAR p_pszOptEnv[MAX_PATH +1] = "";
< TCHAR p_pszOptEx[MAX_PATH +1] = "";
< _tcsncpy(p_pszOptEnv, p_pszOpt+2, strlen(p_pszOpt) -2);
< TCHAR* p_pszOptEnd = _tcschr(p_pszOptEnv, _T(')'));
< if (p_pszOptEnd) {
< *p_pszOptEnd = _T('\0');
< TCHAR* p_pszOptEnvEx = getenv(p_pszOptEnv);
< _tcscat(p_pszOptEx, p_pszOptEnvEx);
< _tcscat(p_pszOptEx, (p_pszOpt + (p_pszOptEnd - p_pszOptEnv) +3));
< p_roSettings.push_back( CDSSetting( p_eType, p_pszOptEx ) );
< }
< }
< else
< p_roSettings.push_back( CDSSetting( p_eType, p_pszOpt ) );
---
> p_roSettings.push_back( CDSSetting( p_eType, p_pszOpt ) );
320,321c305,306
< a_roIncludes.insert( a_roIncludes.begin(), a_oNewIncludes.begin(), a_oNewIncludes.end() );
< a_roIncludes.insert( a_roIncludes.end(), a_oStdIncludes.begin(), a_oStdIncludes.end() );
---
> a_roIncludes.insert( a_roIncludes.begin(), a_oStdIncludes.begin(), a_oStdIncludes.end() );
> a_roIncludes.insert( a_roIncludes.end(), a_oNewIncludes.begin(), a_oNewIncludes.end() );
 

FILE COMPARISON
Produced: 7/28/2006 9:53:30 AM
 
Left base folder: K:\IncludeFinder
Right base folder: K:\IncludeFinderOrig
 
File: VC7Objects.cpp
192,193c192,193
< a_roIncludes.insert( a_roIncludes.begin(), a_oNewIncludes.begin(), a_oNewIncludes.end() );
< a_roIncludes.insert( a_roIncludes.end(), a_oStdIncludes.begin(), a_oStdIncludes.end() );
---
> a_roIncludes.insert( a_roIncludes.begin(), a_oStdIncludes.begin(), a_oStdIncludes.end() );
> a_roIncludes.insert( a_roIncludes.end(), a_oNewIncludes.begin(), a_oNewIncludes.end() );

Generaldoxygen with graphviz do it better!memberMihai Moga6 Apr '06 - 1:03 
Hi, I'm using 'doxygen' with 'graphiz' to document my projects and it's doing a great job! Would be very nice to have an UML diagram of classes from a Visual C++ project. Could you please tell me if you could do that? Thanks in advance.

GeneralSuggested EnhancementsussAnonymous6 Oct '05 - 0:57 
Hi, Thank you for writing this! There've been times in the past when this would have been very usefulSmile | :)
 
One possible enhancement I could suggest would be to allow a workspace to be passed in on the command line. I saw that there is a standard treatment of CCommandLineInfo in the InitInstance but I think it currently treats the input file as a results document. If the workspace can be input in this way then I believe one can add a verb to the Windows file association application and hence be able to right click on a workspace from a File Explorer and launch the IF Hierarchy viewer that way! Just an idea, you probably have left this code behind now!
 

Generalstdafx.hmemberFatalError0x4c15 Dec '04 - 9:54 
If a .cpp file has includes like this:

#include "stdafx.h"
#include "blah1.h"
#include "blah2.h"

then only the first , "stdafx." appears in the treeview ouput.
 
if i move "stdafx.h" to the end of the list like this:

#include "blah1.h"
#include "blah2.h"
#include "stdafx.h"

 
then it seems to work fine.
Is this by design, a bug or a bug that only happens to me?
 
thanks for the program, bye
 
Smile | :)
QuestionReport #if settings around each file?memberSBarney25 Oct '04 - 9:01 
Very useful! Thanks!
 
But people never start one of these without asking for something, do they? Smile | :) So ...
 
Sometimes you have a conflict with something in a header being included five levels deep. Often there's some preprocessor symbol you could define or undefine that would skip over the problem definition. (Like NOSYSMETRICS etc. in Windows.h, or even a multi-include guard like _WINDOWS_) Tracing the various #ifdef (and #ifndef, #if defined(), #else, etc.) directives can be tedious and error-prone.
 
Would it be possible to track and report the preprocessor state that was necessary for each file to get included when it was?
 
(I'd love to look at the sources and add this myself, but I know I won't have time in the forseable future, so I offer the idea here in case somebody else has time.)
 
-- Scott
GeneralScreen disappears.memberWREY9 Sep '04 - 3:32 
If you were to select the "Directory" tab, and under "File mask" enter "*.*", the screen begins to fill up and about a second later, the entire screen disappears. To prevent this from happening, the user has to uncheck the "Recurse subdirectories" checkbox.
 
The suggestion is, "If this has to be done in order to prevent the screen from disappearing, why not disable that checkbox if the user were to enter "*.*" in the "File mask" window?"
 
Another suggestion: Since this is a handy programming tool, why not convert it to be a "plug in" and insert a toolbar icon where the user can simply click on the icon and have the information appear on the screen.
 
Wink | ;)
 
William
 
Fortes in fide et opere!
GeneralRe: Screen disappears.memberChris Richardson10 Sep '04 - 7:46 
Hi,
 
Thanks for the feedback. What did you enter for the search directory? And by the screen disappearing, do you mean the tree control? It shouldn't have to limit the recursive search if *.* is used; I need to fix whatever bug you found.
 
WREY wrote:
Another suggestion: Since this is a handy programming tool, why not convert it to be a "plug in" and insert a toolbar icon where the user can simply click on the icon and have the information appear on the screen.
 
This is in my "To Do" section of the article. Unfortunately, I don't have the time right now. Hopefully some day soon Smile | :)
 
Thanks,
 
Chris Richardson
QuestionNo longer supported?member.dan.g.1 Apr '04 - 21:28 
i would like to use some of the code in projectzip to provide optional error checking (to prevent missing headers).
 
however, you don't seem to be supporting the code anymore and there appear to are a number of significant outstanding issues.
 
i don't want to have to write my own code but i'd prefer to do that than debug someone elses.
 
any chance you could update the code with the necessary fixes?
 
rgds
 
.dan.g.
 
AbstractSpoon
AnswerRe: No longer supported?memberChris Richardson2 Apr '04 - 8:42 
Yeah I've gotten a quite bit far behind on this project, as I have been extremely busy with work and family the last year or so. I'd like to fix all the issues people have reported, but for the mean time, if you'll tell me which issues will prevent you from using it, I can let you know if I will have time to fix them.
 
Thanks,
 
Chris Richardson
GeneralNice work!memberxnwang2218 Feb '04 - 10:10 
It is very nice and useful. I wonder whether it is easy to be modified to do function call tree?
GeneralA couple of other suggestionsmemberMerlinB30 Sep '03 - 22:26 
This worked first time, and is most handy.   I thought of these things that may enhance it more...
 
1. To include the icon explanations in the about box, or as a pop-up tip in the list area.   You would not need to add any more documentation, it is so easy to use!
2. To pre-fill the file mask with some standard/suggested entries.
3. To offer a feature to list the files by .H first (rather than by source file).   Thus the top level tree lists all of the include files.
GeneralCould be more usefulmemberRobin28 Aug '03 - 8:43 
Hi,
 
this is could be more useful if we can specify additional directories to search while loading the workspace. As I have directories of 3rd party sdks specified globally in the compiler include settings and not via project configuration /I, it is unable to find those files and gives a '?'
Generalreproducible crashmemberRobin28 Aug '03 - 8:38 
Repro
 
1. Enter any directory in "Directory\Look in"
2. Press "Start"
3. crash
Generalinclude pathmemberAlarik6 Aug '03 - 1:38 
it seems you are not looking at the project's include paths.
GeneralEVC Workspacesmembersouthpawjoe5 Aug '03 - 4:38 
Any chance this tool can work with Embedded Visual C workspaces? The workspace format is similiar and this tool would be a fantastic addition!
GeneralTool's trymemberEric Lapouge31 Jul '03 - 1:23 
Hi,
 
I have downloaded your program and code and gived it a try. I have the impression (based on what I saw from the project on which I tried it...) that you're wrongly searching the path.
 
Explanation : my project is a clean MFC project, using pre-compiled headers, which are accessed from the (not so extravagant!) stdafx.h include file.
 
In all cases, the shown stdafx.h is the one from VS98\VC98\MFC\SRC directory and not the one from the project. So I'm thinking (I haven't dug into the source code) that you forget to search FIRST in the project's directory before the include's path.
 
Beside this, it would be interesting to have some kind of reports (HTML format would be great!):
- Missing searched files
- included filenames sorted by the include count (desc) for a given source-code file (which should be 1)
- included filenames sorted by the include count (desc) for a project (which should be less than the number of source-code file, and better: 1)
 
Regards,

 
Big Grin | :-D Eric

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 30 Jul 2003
Article Copyright 2003 by Chris Richardson
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid