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 function CALLBACK BrowseCallbackProc(....);
. The Browse for Folder dialog is also centered on the desktop in the CALLBACK
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:
char title[10];
strcpy(title, "Open Dialog Box");
strcpy_s(title, MAX_PATH, "Open Dialog Box");
__________________________________________
[ 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;
hwndDeskTop = ::GetDesktopWindow();
::GetWindowRect(hwndDeskTop, &rcDeskTop);
::GetWindowRect(hwnd, &rcWnd);
x = rcDeskTop.Width() / 2;
y = rcDeskTop.Height() / 2;
x -= rcWnd.Width() / 2;
y -= rcWnd.Height() / 2;
::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;
::GetWindowRect(hwnd, &rc);
hwndDeskTop = ::GetDesktopWindow();
::GetWindowRect(hwndDeskTop, &rcDeskTop);
x = rcDeskTop.Width() / 2;
y = rcDeskTop.Height() / 2;
x -= rc.Width() / 2;
y -= rc.Height() / 2;
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;
}
::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:
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) ;
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.