收录查询

[转贴]The Code Project Visual C++ Forum FAQ

为了方便查阅,原文地址: http://www.codeproject.com/cpp/cppforumfaq.asp#mfc_cstrtopchar
===============================================================================

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

1.1

What's the best way to ask a question about code, so that I get a good answer?

1.2

Why don't my #include lines or template parameters show up right in the forum?

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?

2.1a

How do I know if my code is using the iostream library or STL?

2.2

I'm trying to call a Windows API, but the compiler gives an undeclared identifier error (C2065). Why?

2.3

I'm trying to call a Windows API, but the linker gives an unresolved external error (LNK2001) on the API name. Why?

2.4

Why do I get an unresolved external error (LNK2001) on main() when I make a release build of my ATL project?

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?

2.5a

Thanks. Now, what's a precompiled header?

2.6

Where is the header file atlres.h (or atlapp.h)?
Where can I download WTL?

2.7

Why do I get an unresolved external (LNK2001) error on _beginthreadex and _endthreadex?

2.8

Why do I get an unresolved external on nafxcw.lib or uafxcw.lib?

Debugging questions

3.1

What does a failed debug assert mean?

Windows UI questions

4.1

How can I save and load JPGs, PNGs, or other graphics formats?

4.2

How do I change the background color of a dialog, or draw a picture as the background?

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?

4.4

How do I change the cursor when it's in my window?

4.5

How do I show or hide a window?

4.6

How do I enable or disable a dialog control (button, edit box, etc.)?

4.7

How do I keep a window on top of all other windows?

4.8

How do I highlight an entire row of a list view control in report mode?

4.9

How do I change the background color of a static control?

4.10

How do I programmatically select an item in a list view control?

4.11

My list or tree control works fine in debug builds, but not in release builds. Why?

4.12

How do I create a newline in a multi-line edit control?

4.13

How do I prompt the user to select a directory?

4.14

How do I retrieve the text that the mouse cursor is pointing at?

4.15

How do I set the text in the caption of a frame window or dialog?

4.16

How do I set the icon that's displayed in the caption of a frame window or dialog?

4.17

How do I read the text in an edit box in another process?

4.18

How do I restrict my window so it can't be resized larger or smaller than a certain size?

Console program questions

5.1

How do I clear the screen in a console program?

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++?

5.3

How can I output text in different colors in a console application?

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?

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?

5.6

How can I run my console program without the console window popping up?

General C++ questions

6.1

Why can't I use a member function as a callback?

6.2

How do I share a global variable among my .CPP files?

6.3

How can I change a number into its string representation, or vice versa?

6.4

How do I run another program from my program?

6.5

How do I declare and use a pointer to a class member function?

6.6

Is there a C++ equivalent to the Visual Basic "With" keyword?

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?

7.2

I'm trying to change the font of a dialog control, but it's not having any effect. Why?

7.3

How do I convert a CString to a char*?

7.4

How do I prevent a dialog from closing when the user presses Enter or Esc?

7.5

How do I remove "Untitled" from the main frame window caption?

7.6

I have a dialog-based app and want the dialog hidden on startup. How do I do this?

7.7

How can I make my main frame window non-resizable?

Other Windows topics

8.1

I've written a service and it can't access mapped network drives. Why?

8.2

A program I've written doesn't load when it's run on a computer without Visual C++ installed. Why?

8.3

How do I find the full path to my program's EXE file?

8.4

How do I read the summary information from an Office file?

8.5

How do I delete a file that is currently in use?

8.6

How do I send an email using the default mail client?

8.7

How do I tell if the computer is connected to the Internet?

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 "&lt;" and "&gt;" respectively. So the above include line should be entered as:

  #include &lt;iostream&gt;

Note that you have to do this for if, for, and while expressions as well, such as:

  for ( i = 0; i &lt; 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 "&amp;"

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 #defines 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:

// MFC:
wndYourWindow.ShowWindow ( SW_SHOW );
// Win32 API:
ShowWindow ( hwndYourWindow, SW_SHOW );

To hide it:

// MFC:
wndYourWindow.ShowWindow ( SW_HIDE );
// Win32 API:
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:

// MFC:
wndYourControl.EnableWindow ( FALSE );
// Win32 API:
EnableWindow ( hwndYourControl, FALSE );

To enable it:

// MFC:
wndYourControl.EnableWindow ( TRUE );
// Win32 API:
EnableWindow ( hwndYourControl, TRUE );

4.7: How do I keep a window on top of all other windows? (top)

To make your window topmost:

// MFC:
wndYourWindow.SetWindowPos ( &wndTopMost, 0, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE );
// Win32 API:
SetWindowPos ( hwndYourWindow, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE );

To revert back to normal:

// MFC:
wndYourWindow.SetWindowPos ( &wndNoTopMost, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE );
// Win32 API:
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.

// MFC:
wndYourList.SetExtendedStyle ( LVS_EX_FULLROWSELECT );
// Win32 API:
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.

// MFC:
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 is a CBrush member variable
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.

// Win32 API:
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:

// MFC:
wndYourList.SetItemState ( nItemToSelect, LVIS_SELECTED,
LVIS_SELECTED );
// Win32 API:
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.

// MFC:
wndYourWindow.SetWindowText, _T("New text here") );
// Win32 API:
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().

// MFC:
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 );
// Win32 API:
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 )
{
// do stuff...
...
}

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()
{
// white on black - the default
SetConsoleTextAttribute ( m_hConsole,
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE );
}
void CMyConsoleClass::SetTextBold()
{
// hi-white on black 
SetConsoleTextAttribute ( m_hConsole,
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE |
FOREGROUND_INTENSITY );
}
void CMyConsoleClass::SetTextReverse()
{
// black on white
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 );
// Give this a chance - it may fail the first time through.
HWND hwnd = NULL;
while ( NULL == hwnd )
{
hwnd = ::FindWindowEx ( NULL, NULL, NULL, (LPCTSTR) buf );
}
// Reset old title - we'd normally save it with GetConsoleTitle.
SetConsoleTitle ( _T("whatever") );
// Remove the Close menu item. This will also disable the [X] button
// in the title bar.
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 );
// This helps kill the window quickly.
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;
// see FAQ 6.4 for all the parameters
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:
// ...data members that the callback function needs to access...
};
void CCallback::DoWork()
{
SomeAPIThatHasACallback (
GlobalCallback,           // your callback function
(void*) this );           // 'this' pointer
}
BOOL CCallback::MyCallback()
{
// Do your callback processing here...
}
BOOL CALLBACK GlobalCallback ( void* pv )
{
// pv is the same as the 2nd parameter to
// SomeAPIThatHasACallback() above.
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 );  // CRT sprintf()
cstr.Format ( "%d", num );              // MFC/WTL CString
strm << num << std::ends; // First put the number into a string stream,
stl_string = strm.str();  // then get the actual string.

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 );     // integer
long lNum = atol ( szNumber );    // long integer
double dNum = atof ( szNumber );  // floating-point

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 );     // integer/long
LONGLONG llNum;                       // 64-bit int
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);    // Full declaration syntax
pMethod1 = CMyClass::AddOne;           // sets pMethod1 to the address of AddOne
cout << (myclass.*pMethod1)( 100 );    // calls myclass.AddOne(100);
cout << (pMyclass->*pMethod1)( 200 );  // calls pMyclass->AddOne(200);
pMethod1 = CMyClass::AddTwo;           // sets pMethod1 to the address of AddTwo
cout << (myclass.*pMethod1)( 300 );    // calls myclass.AddTwo(300);
cout << (pMyclass->*pMethod1)( 400 );  // calls pMyclass->AddTwo(400);
// Typedef a name for the function pointer type.
typedef int (CMyClass::* CMyClass_fn_ptr)(unsigned);
CMyClass_fn_ptr pMethod2;
// Use pMethod2 just like pMethod1 above....
}

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 );
// ... create a font here using the 'myfont' object ...
// Change the static control's font.
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 );  // OK - calls CString::operator LPCTSTR() to convert
}

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);
// use pch here...
// When you're done using pch, give the CString control
// of the buffer again.
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;
// Get a non-const pointer and set the buffer size.
pch = sFilename.GetBuffer ( MAX_PATH );
// Pass the buffer to an API that writes to it.
GetModuleFileName ( NULL, pch, MAX_PATH );
// Return control of the array to the CString object.
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
{
// ...
// Generated message map functions
//{{AFX_MSG(CMyDialog)
virtual void OnOK();
    virtual void OnCancel();
//}}AFX_MSG
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;
// rest of the AppWizard code here...
}

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 /*=NULL*/)
: 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;
// optional - set initial window size
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:

posted @ 2006-03-17 22:42  ->  阅读(1967)  评论(0编辑  收藏  举报