About This FAQ
Latest additions and updates.
Welcome to the FAQ for the CodeProject Visual C++ forum. This FAQ is a compilation of the most-often asked questions
in the forum, and covers several C++ programming subjects. It is not a full-fledged C++ or Windows programming
FAQ (there are plenty of those already), but rather it's meant to cover the topics that CodeProject readers ask
about the most.
If you think of any questions that you feel should be covered in this FAQ, email
me with the question and the answer.
NOTE: Please do not email me directly to ask individual questions. I can't be everyone's personal consultant.
Also, don't post programming questions in the message area of this article. Use the
CodeProject forums to ask your questions; that's what they're there for!
Thanks to Tim Deveaux, Anders Molin, and Christian Graus for their contributions to this FAQ, along with all
the folks who have posted suggestions in the comments area and via email!
Contents
CodeProject forum questions
Compiling and linking questions
Debugging questions
Windows UI questions
Console program questions
General C++ questions
MFC questions
Other Windows topics
Links to other Resources
CodeProject forum questions
1.1: What's the best way to ask a question about code, so that I get a good answer? (top)
First off, don't just say, "My program doesn't work. What's wrong?" as that will never get an answer.
At the very minimum, explain what you want to do, what is going wrong, what compiler or linker errors you are getting,
and post the code that isn't working right.
That last phrase bears repeating: Post the code that isn't working right. This is usually the most helpful
thing you can do for the forum readers. When you post the code, the readers will often be able to tell you exactly
what needs to be changed. If you just post with "why doesn't my program work?", the readers then have
to play 20 questions until they finally know enough to answer you. Providing all that info up front will make everyone
happy and get you an answer sooner.
When you include code in your post, enclose the code in a <pre>
...</pre>
block so that your indentation is preserved. If you don't do this, all groups of spaces are reduced down to one
space per HTML rules, and the result is impossible to read.
Here's an example of a good post:
I'm working on a simple dialog-based app that should show the drives on the computer and each volume label.
I have a list control with two columns, the first column for the drive letter and the second for the volume label.
But I can't get anything to appear in the second column. Anyone have a clue what I'm doing wrong? Here's how I'm
trying to add items to the control:
m_DriveList.InsertItem ( 1, szDriveLetter );
m_DriveList.InsertItem ( 2, szVolumeLabel );
And so on, continuing on with items 3, 4, etc. Nothing ever shows up in the second column.
It is generally OK to ask questions about a homework assignment, but you must at least try on your own first.
Don't just post the assignment description; that looks like you want the forum readers to do the assignment for
you. Start the program yourself, and when you get stuck, ask a specific question and, again, include the
code that isn't working.
1.2: Why don't my #include
lines or template parameters show
up right in the forum? (top)
The forum allows you to use HTML tags in posts, for example <b> to make text bold. When you write:
#include <iostream>
the "<iostream>" part looks like an HTML tag, so it doesn't appear in the post. You must use
the HTML code for "<" and ">", which is "<" and ">"
respectively. So the above include line should be entered as:
#include <iostream>
Note that you have to do this for if
, for
, and while
expressions as well,
such as:
for ( i = 0; i < max; i++ ) { ... }
If you write "i < max" the < symbol will cause the same problem.
And by the way, if you want an ampersand (&) in your post, you must write it as "&"
Alternatively, you can turn off HTML parsing altogether in your post. Beneath the edit box where you type in
your post, there is a check box labeled Display this message as-is (no HTML). Check that box before submitting
your post, and the text will be displayed exactly as typed. But remember that no HTML features will work
(such as bold or italic text) when you use this method.
Compiling and linking questions
2.1: I'm trying to use a standard C++ library class (like cout
,
cin
, or string
) but the compiler gives an undeclared identifier error (C2065)
on those names. Why? (top)
The STL (standard template library) classes are separated into the std
namespace. When referring
to classes and functions in that namespace, you must preface them with std::
For example:
std::string str = "Salut, tout le monde!";
std::cout << str.c_str() << std::endl;
Alternatively, you can put this line at the top of your .CPP file:
using namespace std;
This makes the compiler treat everything in the std
namespace as if it weren't in a namespace,
which means you don't have to type std::
everywhere.
If you are using a book that pre-dates the STL and namespaces, you'll see library classes like cin
and cout
written without any prefix. The forerunner of STL, the iostream library, contained classes
with those names, but since namespaces hadn't been introduced to the language, they were accessible like any other
global object. Visual C++ 6 includes the iostream library, so you can use it if necessary, although it's definitely
better to go with the STL nowadays.
2.1a: How do I know if my code is using the iostream library or STL? (top)
The iostream library header files have the regular .H extension, whereas STL header files have no extension.
#include <iostream.h> // old iostream library
#include <iostream> // STL
Projects generated by Visual C++ AppWizards use STL unless you manually change the #include
lines
to reference the iostream headers.
2.2: I'm trying to call a Windows API, but the compiler gives an undeclared identifier
error (C2065). Why? (top)
The most likely reason is that the header files you are using to build are out-of-date and do not include the
features you're trying to use. The headers that came with Visual C++ 6 are extremely old, and if you are still
using them, you will run into this problem often. You can get updated header files by downloading the Platform
SDK from Microsoft. Microsoft recently created an online installer, much like Windows Update, called SDK
Update. If you do not want to use this page (it requires you to install an ActiveX control), you can download
the SDK CAB files and install the SDK from that local copy. You can also order the SDK on CD from the SDK Update
site.
If you have downloaded the latest header files and are still getting compiler errors, read on.
The Windows header files can be used to build programs for any version of Windows starting with Windows 95 and
NT 3.51. Since not all APIs are present in all versions of Windows, there is a system that prevents you from using
APIs that aren't available in the Windows version you are targeting.
This system uses preprocessor symbols to selectively include API prototypes. The symbols are:
WINVER
: Windows version (applies to 9x/Me and NT)
_WIN32_WINDOWS
: Windows 9x/Me version
_WIN32_WINNT
: Windows NT version
_WIN32_IE
: Common controls version
By default, you can only use functions in Windows 95, NT 3.51, and pre-IE3 common controls. To use APIs introduced
in later versions of Windows or the common controls, you need to #define
the above symbols correctly
before including any Windows headers.
As of this writing, here
is the current list of values you can use for the above symbols.
2.3: I'm trying to call a Windows API, but the linker gives an unresolved external
error (LNK2001) on the API name. Why? (top)
When you call a function whose code is not in your program itself, such as any Windows API, you need to tell
the linker where the function is so it can store information about the function in your EXE. This is done with
an import library. An import library is a LIB file that contains the list of functions exported from its
corresponding DLL. For example, kernel32.lib contains the exports for kernel32.dll. When Windows loads your EXE,
it reads this information, loads the correct DLL, and resolves the function calls.
The VC AppWizard creates projects with the most commonly-used LIBs (such as kernel32.lib, user32.lib, etc.)
already listed in the linker options, but if you use call APIs in other DLLs, you'll need to add the corresponding
LIB files.
Let's take for example the API PathAddBackslash()
. When you get an unresolved external error on
this API, you need to find out which LIB file its definition is contained in. Read the MSDN page on PathAddBackslash()
,
and at the bottom you'll see: "Import Library: Shlwapi.lib". That tells you that you must add shlwapi.lib
to your linker options.
To add import libraries to the linker options, click Project->Settings and go to the Link tab. Set
the Category combo box to General, then add the LIB filenames in the Object/library modules
edit box.
2.4: Why do I get an unresolved external error (LNK2001) on main()
when I make a release build of my ATL project? (top)
Release builds of ATL projects contain an optimization whereby the project does not link with the C runtime
library (CRT) in order to reduce the size of your binary. If you use any functions from the CRT (for example, string
manipulation functions) or classes from the C++ library, you need to link with the CRT.
In your project options, go to the C/C++ tab and select the Preprocessor category. Remove the
symbol _ATL_MIN_CRT
from the preprocessor defines, which will turn off this optimization.
Search MSDN for "lnk2001 atl" and see KB article Q166480
(question #4) for more details.
2.5: I added some source files I got from someone else into my project and the compiler
gives the error "C1010: unexpected end of file while looking for precompiled header directive." Why? (top)
By default, Visual C++ projects use precompiled headers. This is a system whereby the large Windows headers
are compiled only once when you build stdafx.cpp. Every other .CPP file in your project needs to #include
"stdafx.h"
as the first #include
in order to build. The compiler specifically looks
for the name "stdafx.h" to know when to insert the precompiled header information.
If you received the source for an entire program from someone else, and you want to build it as a Visual C++
project, you can turn off precompiled headers instead. In your project options, go to the C/C++ tab and
select the Precompiled headers category. Click the Not using precompiled headers radio button, then
click OK.
2.5a: Thanks. Now, what's a precompiled header? (top)
After the headers included by stdafx.cpp are processed, the preprocessor saves a snapshot of its internal state,
which includes all the function prototypes and #define
s in the Windows headers, along with anything
else you added to stdafx.h. This snapshot is saved in a .PCH file. Since processing all those headers takes a long
time, when the compiler compiles the other .CPP files, it reloads the preprocessor state from the .PCH file instead
of processing all the headers again.
The preprocessor looks for an #include "stdafx.h"
line or a #pragma hdrstop
directive to tell when it should read the .PCH file. If neither of those lines is present, you'll get error C1010.
2.6: Where is the header file atlres.h (or atlapp.h)? Where can I download WTL? (top)
WTL is an extension to ATL that provides many features previously only found in MFC, such as frame windows,
UI updating, common control wrappers, and so on. atlres.h and atlapp.h are two WTL header files, and usually the
first ones you'll get errors on if you don't have WTL installed. Microsoft has two versions available for download,
WTL 3.1 and WTL
7. Version 7 was released in April 2002 and includes lots of XP support. Version 3.1 is still functional, but
it does not run out-of-the-box in VC 7.
See Also: WTL section on CodeProject.
2.7: Why do I get an unresolved external (LNK2001) error on _beginthreadex
and _endthreadex
? (top)
This happens when you compile a project that uses MFC, but your compiler settings are set to use the single-threaded
version of the C runtime library (CRT). Since MFC uses threads, it requires the multithreaded CRT. Since the single-threaded
CRT doesn't contain _beginthreadex()
and _endthreadex()
, you get a linker error on those
two functions.
To change your CRT setting, click Project->Settings and go to the C/C++ tab. Set the Category
combo box to Code Generation. In the Use run-time library combo box, chose one of the multithreaded
versions of the CRT. For debug builds, choose Debug Multithreaded or Debug Multithreaded DLL. For
release builds, choose Multithreaded or Multithreaded DLL. The versions that say "DLL"
use MSVCRT.DLL, while the others do not depend on that DLL.
2.8: Why do I get an unresolved external on nafxcw.lib or uafxcw.lib? (top)
The files nafx*.lib
and uafx*.lib
are the static LIB versions of MFC. The files beginning
with "n" are the ANSI version, and the files beginning with "u" are the Unicode version. By
default, only the ANSI files are installed on your hard drive. If the linker cannot find these LIB files, copy
them from your Visual C++ CD to your <VCdir>\vc98\mfc\lib
directory.
If those files are not on your CD, then you have an edition of Visual C++ that does not support static linking
to MFC. You will need to change your project settings to use the DLL version of MFC. Click Project->Settings
and go the General tab. In the Microsoft Foundation Classes combo box, select Use MFC in a Shared
DLL.
Debugging questions
3.1: What does a failed debug assert mean? (top)
Simply put, it means you have a bug in your code. Asserts check for some condition that must always be
true, and if the condition is ever false, it indicates a bug in the calling code (yours).
A full description of asserts is beyond the scope of this FAQ, but when a library such as MFC gives an assert
failure message, it means the library detected that you are incorrectly using it or calling one of its functions
with bad parameters.
For example, this MFC code will assert:
BOOL CYourDlg::OnInitDialog()
{
CListCtrl wndList;
wndList.InsertColumn ( 0, "abcdef" );
}
CListCtrl::InsertColumn()
contains this check:
ASSERT(::IsWindow(m_hWnd));
which fails because the wndList
object wasn't attached to a real list view control.
Asserts that aren't trivial like the above example will (usually) have comments that can help you understand
what the assert was checking for.
Windows UI questions
4.1: How can I save and load JPGs, PNGs, or other graphics formats? (top)
Use GDI+ or a third-party library like paintlib, ImageMagick,
or ImageLibrary.
See Also: Christian Graus's GDI+ articles in the .NET section;
Peter Hendrix's article "Simple class for drawing
pictures."
4.2: How do I change the background color of a dialog, or draw a picture in the
background of my window? (top)
Handle the WM_ERASEBKGND
message. For dialogs, do not handle WM_PAINT
; WM_ERASEBKGND
is the message designed for just this purpose.
Search MSDN for "WM_ERASEBKGND" and you'll find several pages on this topic.
4.3: I have a dialog that does some lengthy processing, and I need to have
a Cancel button so the user can abort the processing. How do I get the Cancel button to work? (top)
First off, the reason the UI doesn't respond to the mouse is that your program is single-threaded, which means
it is not pumping messages in the dialog's message queue while the thread is busy doing the processing.
You have two choices, either move the processing to a worker thread, or keep the dialog single-threaded and
periodically poll your message queue during your processing. Multithreading is beyond the scope of this FAQ, but
see the Threads, Processes & Inter-Process Communication
section of CodeProject for more info. As to the second solution, here is MFC code that will pump any messages waiting
in your message queue:
void ProcessMessages()
{
CWinApp* pApp = AfxGetApp();
MSG msg;
while ( PeekMessage ( &msg, NULL, 0, 0, PM_NOREMOVE ))
pApp->PumpMessage();
}
Call ProcessMessages()
periodically in the code that does the lengthy processing.
See Also: Several articles on threads.
4.4: How do I change the cursor when it's in my window? (top)
Handle the WM_SETCURSOR
message, and call the SetCursor()
function to change the cursor.
Note that your window receives this message every time the mouse is moved, so be sure your WM_SETCURSOR
handler executes quickly. (That is, don't do slow operations like file access.)
4.5: How do I show or hide a window? (top)
To show a window:
wndYourWindow.ShowWindow ( SW_SHOW );
ShowWindow ( hwndYourWindow, SW_SHOW );
To hide it:
wndYourWindow.ShowWindow ( SW_HIDE );
ShowWindow ( hwndYourWindow, SW_HIDE );
There are many more flags that control minimizing and maximizing windows, among other things. See the ShowWindow()
documentation in MSDN for more details.
4.6: How do I enable or disable a dialog control (button, edit box, etc.)? (top)
To disable a control:
wndYourControl.EnableWindow ( FALSE );
EnableWindow ( hwndYourControl, FALSE );
To enable it:
wndYourControl.EnableWindow ( TRUE );
EnableWindow ( hwndYourControl, TRUE );
4.7: How do I keep a window on top of all other windows? (top)
To make your window topmost:
wndYourWindow.SetWindowPos ( &wndTopMost, 0, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE );
SetWindowPos ( hwndYourWindow, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE );
To revert back to normal:
wndYourWindow.SetWindowPos ( &wndNoTopMost, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE );
SetWindowPos ( hwndYourWindow, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE );
4.8: How do I highlight an entire row of a list view control in report mode? (top)
The full-row-select feature is enabled by setting an extended style of the list control.
wndYourList.SetExtendedStyle ( LVS_EX_FULLROWSELECT );
ListView_SetExtendedListViewStyle ( hwndYourList, LVS_EX_FULLROWSELECT );
4.9: How do I change the background color of a static control? (top)
The method for doing this is different depending on whether you're using MFC or the Win32 APIs. In Win32, you
handle the WM_CTLCOLORSTATIC
message, whereas in MFC you handle WM_CTLCOLOR
. In your
handler, verify that the message is for the static control in question, and then return a brush of the color you
want.
HBRUSH CYourDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
if ( pWnd->GetSafeHwnd() == GetDlgItem(IDC_LABEL1)->GetSafeHwnd() &&
CTLCOLOR_STATIC == nCtlColor )
{
m_bkbrush.CreateSolidBrush ( RGB(255,0,0) );
pDC->SetBkMode ( TRANSPARENT );
return m_bkbrush;
}
return hbr;
}
Note the call to CDC::SetBkMode()
which makes the control's text draw transparently. Omitting this
call will make the text background appear gray, although you can change that color as well by calling CDC::SetBkColor()
.
In the Win32 version, you handle WM_CTLCOLORSTATIC
instead of WM_CTLCOLOR
.
LRESULT CALLBACK YourDlgProc(HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
static HBRUSH hbrBkcolor;
switch (message)
{
case WM_INITDIALOG:
hbrBkcolor = CreateSolidBrush ( RGB(255,0,0) );
return TRUE;
break;
case WM_CTLCOLORSTATIC:
{
HDC hdc = (HDC) wParam;
HWND hwndStatic = (HWND) lParam;
if ( hwndStatic == GetDlgItem ( hDlg, IDC_LABEL1 ))
{
SetBkMode ( hdc, TRANSPARENT );
return (LRESULT) hbrBkcolor;
}
}
break;
}
return FALSE;
}
4.10: How do I programmatically select an item in a list view control? (top)
Setting the selection in a list control is done by changing the state of the item you want to select. Set an
item's LVIS_SELECTED
state to select it, or clear that state to unselect it. Here is how to select
an item whose index is nItemToSelect
:
wndYourList.SetItemState ( nItemToSelect, LVIS_SELECTED,
LVIS_SELECTED );
ListView_SetItemState ( hwndYourList, nItemToSelect,
LVIS_SELECTED, LVIS_SELECTED );
If you want the item to have the focus as well, meaning it will be drawn with the focus rectangle around it,
set the LVIS_FOCUSED
state.
4.11: My list or tree control works fine in debug builds, but not in release
builds. Why? (top)
This can usually be fixed by initializing your structures (such as LVITEM
and TVINSERTSTRUCT
)
to zero before using them. You can do this at the same time you declare the structs:
LVITEM lvi = {0};
TVINSERTSTRUCT tvins = {0};
See Also: Joseph M. Newcomer's article "Surviving
the Release Build."
4.12: How do I create a newline in a multi-line edit control? (top)
Use "\r\n" to create a newline. If you use "\r" or "\n" or even "\n\r"
you'll see little blocks in the control.
4.13: How do I prompt the user to select a directory? (top)
Use the SHBrowseForFolder()
API. You can find several examples in MSDN by searching for "SHBrowseForFolder".
See Also: Use this
canned search to find articles related to SHBrowseForFolder()
on CodeProject.
4.14: How do I retrieve the text that the mouse cursor is pointing at? (top)
There is no built-in way to do this. Once the text is on the screen, it is no longer readable as a character
string, only as a bitmap. You'll need OCR (optical character recognition) software to transform the bitmap back
into a string of characters.
4.15: How do I set the text in the caption of a frame window or dialog? (top)
Use the SetWindowText()
API.
wndYourWindow.SetWindowText, _T("New text here") );
SetWindowText ( hwndYourWindow, _T("New text here") );
4.16: How do I set the icon that's displayed in the caption of a frame window
or dialog? (top)
You first load the icon from your program's resources, then set it as the window's current icon. You should
set both the large (32x32) and small (16x16) icons; the large icon is used in the Alt+Tab window, and the small
icon is used in the caption bar and the Taskbar.
Note that the code generated by the MFC AppWizard is buggy and does not properly set the small icon.
The LoadIcon()
function can only load 32x32 icons; to load 16x16 icons, use LoadImage()
.
HICON hLargeIcon = AfxGetApp()->LoadIcon ( IDI_NEW_ICON );
HICON hSmallIcon = (HICON) ::LoadImage ( AfxGetResourceHandle(),
MAKEINTRESOURCE(IDI_NEW_ICON),
IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR );
wndYourWindow.SetIcon ( hLargeIcon, TRUE );
wndYourWindow.SetIcon ( hSmallIcon, FALSE );
HICON hLargeIcon = LoadIcon ( hinstYourModuleInstance,
MAKEINTRESOURCE(IDI_NEW_ICON) );
HICON hSmallIcon = (HICON) LoadImage ( hinstYourModuleInstance,
MAKEINTRESOURCE(IDI_NEW_ICON),
IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR );
SendMessage ( hwndYourWindow, WM_SETICON, ICON_BIG, hLargeIcon );
SendMessage ( hwndYourWindow, WM_SETICON, ICON_SMALL, hSmallIcon );
4.17: How do I read the text in an edit box in another process? (top)
The GetWindowText()
function behaves differently when you use it to retrieve the text in a window
that's in another process. A full description of the problem and the solution is in the first question in this
MSDN Magazine article.
4.18: How do I restrict my window so it can't be resized larger or smaller than
a certain size? (top)
You restrict your window's size by handling the WM_GETMINMAXINFO
message. Your handler receives
a pointer to a MINMAXINFO
struct, which you fill in with the minimum and/or maximum size for your
window. Here is an example that keeps the window between 100x150 and 600x400 pixels in size.
LRESULT OnGetMinMaxInfo ( WPARAM wParam, LPARAM lParam )
{
MINMAXINFO* pmmi = (MINMAXINFO*) lParam;
pmmi->ptMinTrackSize.x = 100;
pmmi->ptMinTrackSize.y = 150;
pmmi->ptMaxTrackSize.x = 600;
pmmi->ptMaxTrackSize.y = 400;
return 0;
}
In MFC, your OnGetMinMaxInfo()
handler is passed a MINMAXINFO*
directly, but otherwise
the code is the same.
Console program questions
5.1: How do I clear the screen in a console program? (top)
This is covered in the Knowledge Base article Q99261,
"HOWTO: Performing Clear Screen (CLS) in a Console Application."
Essentially, the procedure is to get information on the size of the console output buffer, then fill it with
spaces using FillConsoleOutputCharacter()
and FillConsoleOutputAttribute()
.
Before you can use this method, however, you need to get a HANDLE
to the console screen buffer,
like so:
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if ( hConsole != INVALID_HANDLE_VALUE )
{
...
}
Now you are set to call this and several other Win32 console functions. Search MSDN for "console reference"
to learn more about the console-related structures and functions.
5.2: With other compilers, I used to use gotoxy()
to position
the cursor in a console program. How do I do this in Visual C++? (top)
Output to a console is essentially controlled by the console screen buffer's current settings, and each position
in the buffer is addressable with a COORD
structure. This code uses SetConsoleCursorPosition()
to move the current output location to row 11, column 32:
#include <windows.h>
#include <stdio.h>
int main ( int argc, char** argv )
{
HANDLE hConsole = GetStdHandle ( STD_OUTPUT_HANDLE );
if ( INVALID_HANDLE_VALUE != hConsole )
{
COORD pos = {32, 11};
SetConsoleCursorPosition ( hConsole, pos );
printf ( "Hello World!\n" );
}
return 0;
}
Also, code that outputs to cout
will respect the buffer settings as well.
5.3: How can I output text in different colors in a console program? (top)
Each location in the console screen buffer has text attributes as well as a character associated with it, and
the Win32 console functions can affect these in two ways. SetConsoleTextAttribute()
affects subsequent
characters written to the buffer, while FillConsoleOutputAttribute()
directly changes the attributes
of an existing block of text.
The following functions might be used for normal, bold, and reverse text (this assumes that the class has a
handle to the console, through a call to GetStdHandle()
):
void CMyConsoleClass::SetTextNormal()
{
SetConsoleTextAttribute ( m_hConsole,
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE );
}
void CMyConsoleClass::SetTextBold()
{
SetConsoleTextAttribute ( m_hConsole,
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE |
FOREGROUND_INTENSITY );
}
void CMyConsoleClass::SetTextReverse()
{
SetConsoleTextAttribute ( m_hConsole,
BACKGROUND_RED |
BACKGROUND_GREEN |
BACKGROUND_BLUE );
}
Note that there are no settings for blink or underline, so you will need to be a bit creative if you try to
emulate ANSI or VT100 terminal text modes with this method.
5.4: I've allocated a console window in my GUI program, but if the user closes
the console, my program closes too. What to do? (top)
One method that works well is to disable the close menu option. After the console has been allocated with AllocConsole()
,
you can do this if you can find the console window's handle.
void DisableClose()
{
char buf[100];
wsprintf ( buf,
_T("some crazy but unique string that will ID ")
_T("our window - maybe a GUID and process ID") );
SetConsoleTitle ( (LPCTSTR) buf );
HWND hwnd = NULL;
while ( NULL == hwnd )
{
hwnd = ::FindWindowEx ( NULL, NULL, NULL, (LPCTSTR) buf );
}
SetConsoleTitle ( _T("whatever") );
HMENU hmenu = GetSystemMenu ( hwnd, FALSE );
DeleteMenu ( hmenu, SC_CLOSE, MF_BYCOMMAND );
}
5.5: I've allocated a console in my GUI program. When I try to close the
console window, it hangs around for a while. Why? (top)
While only one console can be associated with a process, its possible for more than one process to share the
same console. When you call FreeConsole()
, Windows detaches your app from the console, and will close
it if no other processes are using it. There is a difference between NT and 9x in when the close is performed.
NT seems to check the status immediately and close the console. Windows 9x seems to take more of a "garbage
collection" approach, preferring to wait until some action is performed on the console widow before checking
if it's time to get rid of it.
One trick that helps is to minimize the window before calling FreeConsole()
; check the previous
FAQ entry for a tip on getting the window handle needed to do this.
CloseHandle ( hConsole );
ShowWindow ( console_hwnd, SW_HIDE );
console_hwnd = NULL;
FreeConsole();
Note: Don't call SendMessage(console_hwnd, WM_SYSCOMMAND, SC_CLOSE, 0)
as this will terminate your
entire process!
5.6: How can I run my console program without the console window popping up? (top)
Use CreateProcess()
(as described in FAQ 6.4), and set some members in
the STARTUPINFO
struct to tell Windows to hide the console window.
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi = {0};
BOOL bSuccess;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
bSuccess = CreateProcess ( ..., &si, &pi );
If the CreateProcess()
call succeeds, the console window will be hidden because we specified SW_HIDE
in the wShowWindow
member.
See Also: Steven Szelei's article "Running
console applications silently."
General C++ questions
6.1: Why can't I use a member function as a callback? (top)
Member functions receive the this
pointer as their first parameter (even though you don't write
it that way), so a member function can never match the required prototype of a callback function. There are two
solutions.
First, you can make the member function static. Doing so removes the this
parameter, but then you
cannot access non-static data or functions in the class.
Second, you can keep the member function as-is, use a global function as the actual callback, and pass the global
function the this
pointer yourself. The global function then calls the member function using the passed-in
this
pointer. Windows APIs that use a callback function have a void*
parameter that you
can use for whatever purpose you like. Windows sends that void*
parameter along to the callback function.
So, you use that parameter to pass the this
pointer.
Here is an example:
class CCallback
{
public:
void DoWork();
BOOL MyCallback();
protected:
};
void CCallback::DoWork()
{
SomeAPIThatHasACallback (
GlobalCallback,
(void*) this );
}
BOOL CCallback::MyCallback()
{
}
BOOL CALLBACK GlobalCallback ( void* pv )
{
CCallback* pThis = reinterpret_cast<CCallback*>(pv);
return pThis->MyCallback();
}
void main()
{
CCallback cbk;
cbk.DoWork();
}
Note that this technique of passing the this
pointer can also be used if you make the callback
a static member function.
See Also: Daniel Lohmann's article "Use
member functions for C-style callbacks and threads - a general solution."
6.2: How do I share a global variable among my .CPP files? (top)
First, in one of your .CPP files (and only one) declare the variable at global scope (that is, outside of all
function and class definitions). For example:
int g_volume;
Then in a header file that is included in all .CPP files - such as stdafx.h - add an extern
declaration:
extern int g_volume;
The extern
keyword tells the compiler that g_volume
is an int
declared
in some other .CPP file. If you forget the first step, the linker will give an unresolved external error.
6.3: How can I change a number into its string representation, or vice versa? (top)
Number to a string:
You can use sprintf()
and its clones (wsprintf()
, CString::Format()
,
strstream
) to get the string representation of a number.
int num = 12345;
TCHAR c_style_string[32];
CString cstr;
std::strstream strm;
std::string stl_string;
sprintf ( c_style_string, "%d", num );
cstr.Format ( "%d", num );
strm << num << std::ends;
stl_string = strm.str();
There are also C runtime functions that convert one type of number into a string: itoa()
, ltoa()
,
ultoa()
, i64toa()
, ui64toa()
.
String to a number:
Use the atoi()
or atol()
functions, or if the number is floating-point, atof()
:
char* szNumber = "10235";
int iNum = atoi ( szNumber );
long lNum = atol ( szNumber );
double dNum = atof ( szNumber );
If you need more flexibility, especially if your string is a base other than decimal, use the strtol()
,
strtoul()
, or strtod()
functions. Along with accepting strings in any base up to 36,
they return a pointer to the first non-number character found, which is helpful if you're parsing a long input
string.
char* szNumber = "F33DF4CE~!";
char* pszStopPoint;
long lNum = strtol ( szNumber, &pszStopPoint, 16 );
unsigned long ulNum = strtoul ( szNumber, &pszStopPoint, 16 );
double dNum = strtod ( szNumber, &pszStopPoint, 16 );
After each of those functions, pszStopPoint
points at the '~' which was the first non-hexadecimal
character found.
You can also use a stringstream
:
std::string strWithNumbers = "100 20.5 -93";
std::stringstream strm ( strWithNumbers );
int i, j;
float f;
strm >> i >> f >> j;
There are also three functions in shlwapi.dll, which you can use if you want to avoid using the CRT. StrToInt()
works like atoi()
. The macro StrToLong()
is equivalent to StrToInt()
. StrToIntEx()
and StrToInt64Ex()
accept hexadecimal numbers as well, and return a BOOL
indicating whether
the string contained any numeric characters to convert.
#include <shlwapi.h>
char* szNumber = "10235";
char* szHexNumber = "b4df00d";
int iNum = StrToInt ( szNumber );
LONGLONG llNum;
StrToIntEx ( szHexNumber, STIF_SUPPORT_HEX, &iNum );
StrToInt64Ex ( szHexNumber, STIF_SUPPORT_HEX, &llNum );
These functions are in a DLL that ships with IE, so keep that in mind if your program depends on the version
of IE that's installed. StrToInt()
and StrToIntEx()
require IE 4; StrToInt64Ex()
requires IE 5.
6.4: How do I run another program from my program? (top)
There are several functions that run other programs. The simplest is WinExec()
:
WinExec ( "C:\\path\\to\\program.exe", SW_SHOWNORMAL );
There is also ShellExecute()
, which can run executables as well as files that are associated with
a program. For example, you can "run" a text file, as shown here:
ShellExecute ( hwndYourWindow, "open",
"C:\\path\\to\\readme.txt",
NULL, NULL, SW_SHOWNORMAL );
In this example, ShellExecute()
looks up the program associated with .TXT files and runs that program.
ShellExecute()
also lets you set the program's starting directory and additional command line parameters.
See the MSDN docs on ShellExecute()
for more info.
If you want complete control over every aspect of the program launching process, use CreateProcess()
.
CreateProcess()
has a ton of options, so see MSDN for all the details. Here is a simple example:
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi = {0};
BOOL bSuccess;
bSuccess = CreateProcess ( NULL, "\"C:\\Program Files\\dir\\program.exe\"",
NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS,
NULL, NULL, &si, &pi );
Note that the program name should be enclosed in quotes, as shown above, if the path contains spaces.
If CreateProcess()
succeeds, be sure to close the handles in the PROCESS_INFORMATION
structure once you don't need them anymore.
CloseHandle ( pi.hThread );
CloseHandle ( pi.hProcess );
Of course, if all you need to do is just run a program, CreateProcess()
is probably overkill, and
ShellExecute()
would be sufficient.
6.5: How do I declare and use a pointer to a class member function? (top)
The syntax is similar to a regular function pointer, but you also have to specify the class name. Use the .*
and ->*
operators to call the function pointed to by the pointer.
class CMyClass
{
public:
int AddOne ( unsigned n ) { return n+1; }
int AddTwo ( unsigned n ) { return n+2; }
};
main()
{
CMyClass myclass, *pMyclass = &myclass;
int (CMyClass::* pMethod1)(unsigned);
pMethod1 = CMyClass::AddOne;
cout << (myclass.*pMethod1)( 100 );
cout << (pMyclass->*pMethod1)( 200 );
pMethod1 = CMyClass::AddTwo;
cout << (myclass.*pMethod1)( 300 );
cout << (pMyclass->*pMethod1)( 400 );
typedef int (CMyClass::* CMyClass_fn_ptr)(unsigned);
CMyClass_fn_ptr pMethod2;
}
The line
int (CMyClass::* pMethod1)(unsigned);
reads: "pMethod1
is a pointer to a function in CMyClass
; that function takes
an unsigned
parameter and returns an int
".
Note that CMyClass::AddOne
is very different from CMyClass::AddOne()
. The first is
the address of the AddOne
method in CMyClass
, while the second actually calls the method.
6.6: Is there a C++ equivalent to the Visual Basic "With" keyword? (top)
Nope. Sorry, you have to type a struct's variable name every time you access its members.
MFC questions
7.1: In my MFC program, I'm trying to disable a menu item with EnableMenuItem()
,
but it doesn't have any effect on the menu. Why? (top)
MFC uses its own system for enabling and disabling menu items and toolbar buttons, which overrides any calls
you make to EnableMenuItem()
. If you look in the message map of your CMainFrame
class,
you may see some ON_UPDATE_COMMAND_UI()
macros. Those macros control when menu items and toolbar buttons
are enabled and disabled.
To add a macro for the menu item you want to disable, go to ClassWizard and click the Message Maps tab.
In the Class name combo box, select the class where you want to add the handler (usually CMainFrame
is a good choice, but for items that relate to data stored in your document, pick your CDocument
-derived
class instead). In the Object IDs list, select the command ID of the menu item, then in the Messages
list, double-click UPDATE_COMMAND_UI.
In the update handler, call:
pCmdUI->Enable ( FALSE );
to disable the menu item. Note that if you have a toolbar button with the same command ID, that button will
be disabled as well.
See the MSDN pages on CCmdUI
and ON_UPDATE_COMMAND_UI
for more details.
7.2: I'm trying to change the font of a dialog control, but it's not having any
effect. Why? (top)
The most likely cause is a logic error that causes the font to be destroyed prematurely. For example, you might
try to change the font of a static control like this:
BOOL CMyDlg::OnInitDialog()
{
CFont myfont;
CStatic* pStatic = GetDlgItem ( IDC_SOME_LABEL );
pStatic->SetFont ( &myfont );
return TRUE;
}
The problem with this code is that a font is a GDI resource managed by the CFont
class. When myfont
goes out of scope, the CFont
destructor destroys the GDI font object. Move the CFont
object to be a member variable of your dialog class, so that the font stays around until the CMyDlg
destructor cleans it up.
7.3: How do I convert a CString
to a char*
? (top)
First, be sure you actually need a char*
(non-constant pointer, or LPTSTR
). If you
need a const char*
(or LPCTSTR
), then CString
has a conversion function
that will be called automatically if you pass a CString
to a function expecting an LPCTSTR
.
For example:
void f ( LPCTSTR somestring )
{
cout << somestring << endl;
}
main()
{
CString str = "bonjour";
f ( str );
}
The remainder of this FAQ deals with obtaining a non-constant pointer to the string.
Because a CString
object manages the character array, you must explicitly tell the CString
that you want to get a non-constant pointer to the string. Call GetBuffer()
to get a char*
to the string, and then call ReleaseBuffer()
when you no longer need that pointer. Calling ReleaseBuffer()
tells the CString
that it can resume managing the character array.
CString str = "some string";
LPTSTR pch;
pch = str.GetBuffer(0);
str.ReleaseBuffer();
After calling GetBuffer()
, you may modify the contents of the string through pch
,
although you can't make the string longer since that would overrun the array. If you do modify the string, you
must not call any CString
methods before the call to ReleaseBuffer()
, since CString
methods may reallocate and move the array, which would render pch
invalid. After you call ReleaseBuffer()
,
you must not use pch
any more, again because the CString
may reallocate and move the
character array.
If you want to create a larger buffer for the string, for example if you are going to pass it to an API that
returns a filename, you can do so by passing the desired length to GetBuffer()
:
CString sFilename;
LPTSTR pch;
pch = sFilename.GetBuffer ( MAX_PATH );
GetModuleFileName ( NULL, pch, MAX_PATH );
sFilename.RelaseBuffer();
See also: "The Complete Guide to
C++ Strings, Part II - String Wrapper Classes"
7.4: How do I prevent a dialog from closing when the user presses Enter or
Esc? (top)
Let's first cover why the dialog closes, even if you remove the OK and Cancel buttons.
CDialog
has two special virtual functions, OnOK()
and OnCancel()
, which
are called when the user presses the Enter or Esc key respectively. The CDialog
implementations call
EndDialog()
, which is why the dialog closes. Since those are special-purpose functions, they do not
appear in the dialog's BEGIN_MESSAGE_MAP
/END_MESSAGE_MAP
section, and they need to be
overridden differently than normal button click handlers.
If you still have buttons with IDs IDOK and IDCANCEL, you can use ClassWizard to add BN_CLICKED
handlers for those buttons, and it will do the special handling necessary for OnOK()
and OnCancel()
.
If you do not have buttons with those IDs, then you can override the virtual functions manually. In your dialog
class definition:
class CMyDialog : public CDialog
{
virtual void OnOK();
virtual void OnCancel();
DECLARE_MESSAGE_MAP()
};
Then in the corresponding .CPP file:
void CMyDialog::OnOK()
{
}
void CMyDialog::OnCancel()
{
}
The important part here is that the handlers do not call the base-class implementation, so EndDialog()
is not called and the dialog doesn't close.
7.5: How do I remove "Untitled" from the main frame window caption? (top)
In your CMainFrame
's PreCreateWindow()
function, remove the FWS_ADDTOTITLE
style.
BOOL CMainFrame::PreCreateWindow ( CREATESTRUCT& cs )
{
cs.style &= ~FWS_ADDTOTITLE;
}
FWS_ADDTOTITLE
is an MFC-specific style, which tells MFC to add the current document's name to
the text in the main frame's caption. See the page "Changing
the Styles of a Window Created by MFC" in MSDN for more details and examples.
7.6: I have a dialog-based application and want the dialog hidden on startup.
How do I do this? (top)
Normally, modal dialogs are always shown, because if the dialog were hidden, the parent application would
be disabled with no way to re-enable it. Dialog-based apps are different, and hiding the window is safe (as long
as you provide a way for the user to get to the dialog later!).
Hiding the dialog involves handling WM_WINDOWPOSCHANGING
, which is sent when the dialog is moved,
shown, hidden, or rearranged in the Z order. The first time the handler is called, it tells Windows not to show
the dialog.
Add a member variable to your CDialog
-derived class that will keep track of whether WM_WINDOWPOSCHANGING
has been handled.
class CYourDialog : public CDialog
{
protected:
bool m_bFirstShowWindow;
};
Initialize this variable to true
in the constructor:
CYourDlg::CYourDlg (CWnd* pParent )
: m_bFirstShowWindow(true), CDialog(CYourDlg::IDD, pParent)
{
}
Add a handler for WM_WINDOWPOSCHANGING
and code it as shown below. The handler checks if the dialog
is being shown, and if this is the first time it's being shown. If so, it turns off the SWP_SHOWWINDOW
flag to keep the dialog from being shown.
void CYourDlg::OnWindowPosChanging ( WINDOWPOS* lpwndpos )
{
CDialog::OnWindowPosChanging(lpwndpos);
if ( lpwndpos->flags & SWP_SHOWWINDOW )
{
if ( m_bFirstShowWindow )
{
m_bFirstShowWindow = false;
lpwndpos->flags &= ~SWP_SHOWWINDOW;
}
}
}
7.7: How can I make my main frame window non-resizable? (top)
In your main frame's PreCreateWindow()
function, remove the WS_THICKFRAME
style. You
can also set the window's initial size in that same function.
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
cs.style &= ~WS_THICKFRAME;
cs.cx = 800;
cs.cy = 200;
return TRUE;
}
Other Windows topics
8.1: I've written a service and it can't access mapped network drives. Why? (top)
Mapped drives are stored on a per-user basis. The default configuration for a service logs it in as the LocalSystem
account, so it cannot access the mapped drives you make when you log in using your own account. You can manually
change your service's account by viewing its properties in the Services Control Panel applet (NT 4) or the Services
branch in Computer Management (Windows 2000/XP, Start->Programs->Administrative Tools->Computer Management).
If you are installing your service with the CreateService()
function, pass your account name and
password in the 12th and 13th parameters, respectively.
8.2: A program I've written doesn't load when it's run on a computer without Visual
C++ installed. Why? (top)
Your program links with numerous DLLs in order to run, such as kernel32.dll, advapi32.dll, and so on. If your
app is using MFC, the other computer needs to have the MFC and CRT (C runtime library) DLLs installed. You may
also be using ActiveX controls and/or COM objects, which must be properly installed and registered on the other
computer.
To determine which DLLs your app is statically linked to (that is, DLLs which are loaded as soon as your app
is run), run the Dependency Viewer on your EXE. (Start->Programs->MSVC 6->Tools->Depends) Depends version
2 is more powerful, and can show which DLLs are loaded at runtime, and which ActiveX controls and COM servers your
app uses. You can get version 2 from the Platform SDK, or the very latest version from the
official Dependency Walker site.
If you just want to remove the dependency on the MFC DLLs, you can statically link MFC to your app. This means
all the MFC and CRT code your app uses is put right in the EXE, instead of being read from the DLLs. To use static
linking, click Project->Settings, and click the General tab. In the Microsoft Foundation Classes
combo box, select Use MFC in a static library. Note that you normally do this for release builds only, and
this will significantly increase the size of your EXE.
One final thing to check is that you're distributing the release build of your program, not the debug build.
MFC apps built in debug mode use several other, and much larger, DLLs. Microsoft does not allow you to distribute
the debug MFC DLLs, but you shouldn't be distributing a debug build anyway, because it will be slower and much
larger than the release build.
8.3: How do I find the full path to my program's EXE file? (top)
Use the GetModuleFileName()
function:
TCHAR szEXEPath[MAX_PATH];
GetModuleFileName ( NULL, szEXEPath, MAX_PATH );
Passing a module handle of NULL tells the API to return the path for the EXE.
8.4: How do I read the summary information from an Office file? (top)
Microsoft Office files are OLE structured storage documents (also called "docfiles"), and the summary
info is contained in a stream in the docfile. See Knowledge Base article Q186898
for a description of how to read this data.
8.5: How do I delete a file that is currently in use? (top)
The code involved is different on 9x and NT. On NT, you can use the MoveFileEx()
function to mark
the file for deletion on the next reboot.
MoveFileEx ( szFilename, NULL, MOVEFILE_DELAY_UNTIL_REBOOT );
On 9x, you need to edit the wininit.ini
file in the Windows directory and add an entry that instructs
Windows to delete the file on the next reboot. The file should look like:
[rename]
NUL=C:\path\to\file.exe
Note that this file is processed in real mode before long filenames can be read, so you must use the short name
(8.3) of the file. See this C++
Q&A article (from the January 1996 MSJ) for code that modifies wininit.ini
.
8.6: How do I send an email using the default mail client? (top)
Use the ShellExecute()
function to "execute" a mailto:
URL:
ShellExecute ( hwndYourWindow, "open",
"mailto:user@domain.com?subject=Subject Here",
NULL, NULL, SW_SHOW );
There are other methods of sending mail and controlling the mail client, including MAPI (mail API), but that
subject is beyond the scope of this FAQ.
8.7: How do I tell if the computer is connected to the Internet? (top)
Use the InternetGetConnectedState()
function. This API returns a BOOL indicating whether the computer
is connected to a network. However, a system might be connected but in offline mode. (You toggle offline mode by
clicking File->Work Offline in IE.) So you also need to check the flags returned by the API.
BOOL bConnected;
DWORD dwFlags;
bConnected = InternetGetConnectedState ( &dwFlags, 0 );
if ( bConnected )
if ( dwFlags & INTERNET_CONNECTION_OFFLINE )
bConnected = FALSE;
Links to other FAQs
C++ FAQs
C++ FAQ Lite
Comeau C and C++ FAQ
Comeau C++ templates FAQ
MFC/ATL FAQs
CListCtrl/CListView FAQ at Celtic Wolf
MFC Tips and Tricks at cui.unige.ch.
ATL, COM, MFC FAQs at widgetware.com
FAQs on other Windows topics
List of FAQs in KB articles at widgetware.com
Active Scripting FAQ
Books about programming
CodeProject article - "Useful Reference
Books"
Recent changes
June 28, 2003
Updated FAQs:
New FAQs:
March 1, 2003
Updated FAQs:
New FAQs:
July 4, 2002
Updated FAQs:
New FAQs:
June 1, 2002
Updated FAQs:
New FAQs:
May 26, 2002
New FAQs:
Updated FAQs: