Visual C++ 7.1Visual C++ 8.0Visual C++ 7.0Visual C++ 6.0Windows XPMFCIntermediateDevVisual StudioWindowsC++
Count Lines of C or C++ Code






3.40/5 (11 votes)
Dec 29, 2005
2 min read

79662

954
An article on counting lines of code.
The main window is initially 760x550 (reduced for the article).
Introduction
This program only counts lines of code, but has some very useful features.
- I used the MFC class
CFileFind
to recursively find the files in the selected folder. - The file types recognized by this version are defined in
BOOL IsCplusplusFile(CString &lpszFileName)
. - The main window is scrollable using the scroll bar arrows or the keyboard keys, up, down, left, right, Home, and End.
- I used the macro
_MSC_VER
in a conditional assembly so the code can be assembled using VC++ 6.0 or VC++ 8.0. - The main window is centered on the desktop.
- The first time the user runs the program, the browser starts in the project directory. When the program exits, the last folder selected is saved to an ini file thus remembering what you selected last.
- During a session with the program, the browser start directory
m_szDirectory
is updated and passed to the functionCALLBACK BrowseCallbackProc(....);
. The Browse for Folder dialog is also centered on the desktop in theCALLBACK
function.
Background
In Microsoft Visual C++ 8.0, several older C functions are declared as deprecated; in most cases, _s
is added to the end of the function definition and a size_t
variable is required inside the function.
For example:
// The char array is created on the stack. char title[10]; // should have been MAX_PATH. // VC++ 6.0 function. strcpy(title, "Open Dialog Box"); // strcpy(..); has no array bounds checking, the string literal is 16 bytes. // The next 6 bytes in stack are overwritten and the program crashes. // VC++ 8.0 function. strcpy_s(title, MAX_PATH, "Open Dialog Box"); // This will throw and exception in the Debug version and a Message Box // will be displayed. __________________________________________ [ Microsoft Visual Studio ] [------------------------------------------] [ ] [ Run-Time Check Failure #2 - Stack around ] [ the variable 'title' was corrupted. ] [ ] [ [ Break ] [ Continue ] ] [__________________________________________]
The predefined macro _MSC_VER
defines the compiler version: defined as 1200 for Microsoft Visual C++ 6.0 and defined as 1400 for Microsoft Visual C++ 8.0.
Using the code
- Find all files in a folder:
VOID GetFileNamesInDirectory(CString &lpszDirectory) { CFileFind finder; CString strFullPath; BOOL bWorking = FALSE; CString strWildcard(lpszDirectory); if (strWildcard.Right(1) != "\\") strWildcard += "\\*.*"; bWorking = finder.FindFile(strWildcard); while (bWorking) { bWorking = finder.FindNextFileA(); if (finder.IsDots()) continue; if (finder.IsDirectory()) { strFullPath = finder.GetFilePath(); GetFileNamesInDirectory(strFullPath); } else { strFullPath = finder.GetFilePath(); szaFiles.Add(strFullPath); } } finder.Close(); }
- Get the C or C++ file type:
BOOL IsCplusplusFile(CString &lpszFileName) { char szExt[_MAX_EXT]; #if _MSC_VER < 1400 _splitpath(lpszFileName, NULL, NULL, NULL, szExt); #else _splitpath_s(lpszFileName, NULL, 0, NULL, 0, NULL, 0, szExt, _MAX_EXT); #endif if (!_stricmp(szExt, ".c") || !_stricmp(szExt, ".cpp")|| !_stricmp(szExt, ".dsp")|| !_stricmp(szExt, ".dsw")|| !_stricmp(szExt, ".h") || !_stricmp(szExt, ".hpp")|| !_stricmp(szExt, ".rc") || !_stricmp(szExt, ".vcproj")) { return TRUE; } return FALSE; }
- Keyboard scrolling:
case WM_KEYDOWN: switch(wParam) { case VK_LEFT: SendMessage(hwnd, WM_HSCROLL, SB_LINELEFT, 0); break; case VK_RIGHT: SendMessage(hwnd, WM_HSCROLL, SB_LINERIGHT, 0); break; case VK_DOWN: SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0); break; case VK_UP: SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0); break; case VK_HOME: SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0); break; case VK_END: SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0); break; } return 0;
- Conditional assembly:
int GetNumberOfLinesInFile(CString &lpszFileName) { FILE *lpFile; int nNumberOfLines; #if _MSC_VER < 1400 lpFile = fopen(lpszFileName, "r"); #else errno_t ernum; ernum = fopen_s(&lpFile, lpszFileName, "r"); #endif nNumberOfLines = 0; if (lpFile != NULL) { char ch; do { ch = fgetc(lpFile); if (ch == '\n') { nNumberOfLines ++; } }while (ch != EOF); fclose(lpFile); } return nNumberOfLines; }
- Center main window:
void CenterWindow(HWND hwnd) { int x, y; HWND hwndDeskTop; CRect rcWnd, rcDeskTop; // Get a handle to the desktop window hwndDeskTop = ::GetDesktopWindow(); // Get dimension of desktop in a rect ::GetWindowRect(hwndDeskTop, &rcDeskTop); // Get dimension of main window in a rect ::GetWindowRect(hwnd, &rcWnd); // Find center of desktop x = rcDeskTop.Width() / 2; y = rcDeskTop.Height() / 2; x -= rcWnd.Width() / 2; y -= rcWnd.Height() / 2; // Set top and left to center main window on desktop ::SetWindowPos(hwnd, HWND_TOP, x, y, 0, 0, SWP_NOSIZE); }
- Save last selected file:
case WM_DESTROY: WritePrivateProfileString("CountLinesApp", "DIRECTORY", m_szDirectory, szAppIniFile); PostQuitMessage (0) ; return 0 ; case WM_CREATE: GetCurrentDirectory(MAX_PATH, m_szDirectory); szAppIniFile = m_szDirectory; szAppIniFile += "\\CountLinesApp.ini"; dwNum = GetPrivateProfileString("CountLinesApp", "DIRECTORY", "C:\\", m_szDirectory, MAX_PATH, szAppIniFile); if (dwNum == 3) GetCurrentDirectory(MAX_PATH, m_szDirectory);
- Update start directory and center window:
int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM pData) { switch(uMsg) { case BFFM_INITIALIZED: { int x, y; HWND hwndDeskTop; CRect rc, rcDeskTop; // Get dimension of dlg window in a rect ::GetWindowRect(hwnd, &rc); // Get a handle to the desktop window hwndDeskTop = ::GetDesktopWindow(); // Get dimension of desktop in a rect ::GetWindowRect(hwndDeskTop, &rcDeskTop); // Find center of client x = rcDeskTop.Width() / 2; y = rcDeskTop.Height() / 2; x -= rc.Width() / 2; y -= rc.Height() / 2; // Set top and left to center dlg window on Desk Top SetWindowPos(hwnd, HWND_TOP, x, y, 0, 0, SWP_NOSIZE); LPCTSTR lpszPath = m_szDirectory; TCHAR szTemp[MAX_PATH]; if(lpszPath==NULL) { ::GetCurrentDirectory(MAX_PATH, szTemp ); lpszPath = szTemp; } // WParam is TRUE since you are passing a path. // It would be FALSE if you were passing a pidl. ::SendMessage(hwnd,BFFM_SETSELECTION,TRUE, (LPARAM)lpszPath); break; } case BFFM_SELCHANGED: { char szSelection[MAX_PATH]; if(!::SHGetPathFromIDList((LPITEMIDLIST)lParam, szSelection) || szSelection[1]!=':') { szSelection[0] = '\0'; ::SendMessage(hwnd, BFFM_ENABLEOK, 0, FALSE); } else { ::SendMessage(hwnd, BFFM_ENABLEOK, 0, TRUE); } ::SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)szSelection); break; } default: break; } return 0; }
Points of Interest
The scroll bars are not automatically redrawn so I added my own message handler.
#define WM_DRAW_BAR WM_USER + 1 case WM_DRAW_BAR: // Set vertical scroll bar range and page size si.cbSize = sizeof (si) ; si.fMask = SIF_ALL ; si.nMin = 0 ; si.nMax = nVMax ; si.nPage = nVPage; si.nPos = 0 ; si.nTrackPos = 0; SetScrollInfo (hwnd, SB_VERT, &si, TRUE) ; // Set horizontal scroll bar range and page size si.cbSize = sizeof (si) ; si.fMask = SIF_ALL ; si.nMin = 0 ; si.nMax = nHMax ; si.nPage = nHPage ; si.nPos = 0 ; si.nTrackPos = 0; SetScrollInfo (hwnd, SB_HORZ, &si, TRUE) ; return 0;
History
- December 29, 2005 - Version 1.0.